flash on 2010-11-26
/**
* Copyright kihon ( http://wonderfl.net/user/kihon )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/A7wS
*/
package
{
import flash.display.Sprite;
public class Main extends Sprite
{
public function Main()
{
addChild(new Board(stage));
}
}
}
import com.bit101.components.Label;
import com.bit101.components.PushButton;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;
class Board extends Sprite
{
public static const END_GAME:int = 48;
public static const WIDTH:int = 8;
public static const HEIGHT:int = 8;
public static const SIZE:int = 30;
public static const DEPTH_MAX:int = 2;
public static const SCORE_TABLE:Array =
[
[ 45,-11, 4, -1, -1, 4,-11, 45],
[-11,-16, -1, -3, -3, -1,-16,-11],
[ 4, -1, 2, -1, -1, 2, -1, 4],
[ -1, -3, -1, 0, 0, -1, -3, -1],
[ -1, -3, -1, 0, 0, -1, -3, -1],
[ 4, -1, 2, -1, -1, 2, -1, 4],
[-11,-16, -1, -3, -3, -1,-16,-11],
[ 45,-11, 4, -1, -1, 4,-11, 45]
];
private var board:Array;
private var turn:int;
private var putPos:Vector.<Point> = new Vector.<Point>();
private var clickable:Boolean = true;
private var delayTimer:Timer;
private var passButton:PushButton;
private var aiColor:int = State.WHITE;
private var passCount:int = 0;
private var blackCount:int = 2;
private var whiteCount:int = 2;
private var countLabel:Label;
private var turnCount:int = 0;
public function Board(stage:Stage)
{
countLabel = new Label(this, 270, 50);
countLabel.scaleX = countLabel.scaleY = 2;
passButton = new PushButton(this, 300, 100, "PASS", pass);
passButton.visible = false;
delayTimer = new Timer(500, 1);
delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE, AIProcess2);
board = [];
for (var y:int = 0; y < HEIGHT; y++)
{
board[y] = [];
for (var x:int = 0; x < WIDTH; x++)
{
board[y][x] = State.NONE;
}
}
board[3][3] = board[4][4] = State.WHITE;
board[3][4] = board[4][3] = State.BLACK;
turn = State.BLACK;
passCheck();
stage.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function pass(event:Event = null):void
{
turnChange();
passButton.visible = false;
passCheck();
}
private function onMouseClick(event:MouseEvent):void
{
if (!clickable) return;
var tx:int = mouseX / SIZE;
var ty:int = mouseY / SIZE;
if (!onBoard(tx, ty)) return;
var vec:Vector.<Point> = flipCheck(turn, tx, ty);
if (vec.length != 0)
{
put(tx, ty, vec, turn);
updateCount();
turnCount++;
turnChange();
passCheck();
}
}
private function AIProcess():void
{
putPos.length = 0;
clickable = false;
delayTimer.start();
}
private function AIProcess2(event:TimerEvent = null):void
{
var p:Point = solve();
var vec:Vector.<Point> = flipCheck(turn, p.x, p.y);
put(p.x, p.y, vec, turn);
updateCount();
turnCount++;
turnChange();
passCheck();
clickable = true;
}
private function flipCheck(color:int, x:int, y:int):Vector.<Point>
{
var vec:Vector.<Point> = new Vector.<Point>();
if (board[y][x] == State.NONE)
{
for (var dy:int = -1; dy <= 1; dy++)
{
for (var dx:int = -1; dx <= 1; dx++)
{
vec = vec.concat(flipCheck2(color, x, y, dx, dy));
}
}
}
return vec;
}
private function putSearch(color:int):void
{
putPos.length = 0;
for (var y:int = 0; y < HEIGHT; y++)
{
for (var x:int = 0; x < WIDTH; x++)
{
if (flipCheck(color, x, y).length != 0)
{
putPos.push(new Point(x, y));
}
}
}
}
private function passCheck():void
{
putSearch(turn);
draw();
if (putPos.length == 0)
{
turnChange();
putSearch(turn);
turnChange();
if (putPos.length == 0)
{
gameOver();
}
else
{
putPos.length = 0;
passButton.label = (turn == State.BLACK) ? "Black PASS" : "White PASS";
passButton.visible = true;
}
}
else
{
if (turn == aiColor) AIProcess();
}
}
private function gameOver():void
{
draw();
var text:String = (whiteCount == blackCount) ? "draw" : (whiteCount > blackCount) ? "White Win" : "Black Win";
var label:Label = new Label(this, 300, 200, text);
label.scaleX = label.scaleY = 2;
}
private function flipCheck2(color:int, x:int, y:int, dx:int, dy:int):Vector.<Point>
{
var vec:Vector.<Point> = new Vector.<Point>();
while (true)
{
x += dx;
y += dy;
if (!onBoard(x, y) || board[y][x] == State.NONE)
{
vec.length = 0;
break;
}
if (board[y][x] == color) break;
vec.push(new Point(x, y));
}
return vec;
}
private function onBoard(x:int, y:int):Boolean
{
if (x < 0 || WIDTH <= x) return false;
if (y < 0 || HEIGHT <= y) return false;
return true;
}
private function turnChange():void
{
if (turn == State.BLACK) turn = State.WHITE;
else turn = State.BLACK;
}
private function put(x:int, y:int, vec:Vector.<Point>, color:int):void
{
board[y][x] = color;
for each (var p:Point in vec)
{
if (board[p.y][p.x] == State.BLACK) board[p.y][p.x] = State.WHITE;
else board[p.y][p.x] = State.BLACK;
}
}
private function updateCount():void
{
blackCount = whiteCount = 0;
for (var y:int = 0; y < HEIGHT; y++)
{
for (var x:int = 0; x < WIDTH; x++)
{
if (board[y][x] == State.BLACK) blackCount++;
else if (board[y][x] == State.WHITE) whiteCount++;
}
}
}
private function solve(turnAI:Boolean = true, depth:int = 0, prevPass:Boolean = false):*
{
var score:int;
var highScorePoint:Point = new Point();
if (depth == DEPTH_MAX) return getScore();
if (turnAI) score = int.MIN_VALUE;
else score = int.MAX_VALUE;
for (var y:int = 0; y < HEIGHT; y++)
{
for (var x:int = 0; x < WIDTH; x++)
{
var vec:Vector.<Point> = flipCheck(turn, x, y);
if (vec.length != 0)
{
put(x, y, vec, turn);
turnChange();
var childScore:int = solve(!turnAI, depth + 1);
if (turnAI)
{
if (childScore > score)
{
score = childScore;
highScorePoint.x = x;
highScorePoint.y = y;
}
}
else
{
if (childScore < score)
{
score = childScore;
highScorePoint.x = x;
highScorePoint.y = y;
}
}
put(x, y, vec, State.NONE);
turnChange();
}
}
}
if (depth == 0) return new Point(highScorePoint.x, highScorePoint.y);
else if (score != int.MIN_VALUE && score != int.MAX_VALUE) return score;
else if (prevPass) return getScore();
else
{
turnChange();
score = solve(!turn, depth + 1, true);
turnChange();
return score;
}
}
private function getScore():int
{
var score:int = 0;
if (turnCount > END_GAME) score += getPieceNumScore();
else
{
score += getTableScore();
score += getPutNumScore();
}
return score;
}
private function getTableScore():int
{
var score:int = 0;
for (var y:int = 0; y < HEIGHT; y++)
{
for (var x:int = 0; x < WIDTH; x++)
{
if (board[y][x] == aiColor) score += SCORE_TABLE[y][x];
else if (board[y][x] != State.NONE) score -= SCORE_TABLE[y][x];
}
}
return score;
}
private function getPutNumScore():int
{
putSearch(aiColor);
var score:int = putPos.length * 3;
putPos.length = 0;
return score;
}
private function getPieceNumScore():int
{
updateCount();
if (aiColor == State.BLACK) return blackCount - whiteCount;
else return whiteCount - blackCount;
}
private function draw():void
{
graphics.clear();
countLabel.text = "Black " + blackCount + " : White " + whiteCount;
for (var y:int = 0; y < HEIGHT; y++)
{
for (var x:int = 0; x < WIDTH; x++)
{
var tx:int = x * SIZE;
var ty:int = y * SIZE;
graphics.lineStyle(1.0);
graphics.beginFill(0xA0C000);
graphics.drawRect(tx, ty, SIZE, SIZE);
graphics.endFill();
if (board[y][x] == State.NONE) continue;
graphics.beginFill(Color.LIST[board[y][x]]);
graphics.drawCircle(tx + SIZE / 2, ty + SIZE / 2, SIZE / 3);
graphics.endFill();
}
}
if (turn == aiColor) return;
for each (var p:Point in putPos)
{
tx = p.x * SIZE;
ty = p.y * SIZE;
graphics.beginFill(0x008000, 1.0);
graphics.drawRect(tx, ty, SIZE, SIZE);
graphics.endFill();
}
}
}
class State
{
public static const NONE:int = 0;
public static const BLACK:int = 1;
public static const WHITE:int = 2;
}
class Color
{
public static const LIST:Array = [0, 0x0, 0xFFFFFF];
}