In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: Reversi

リバーシ
@mxmlc -o bin/Reversi.swf -load-config+=obj\Alltest3Config.xml
@author jc at bk-zen.com
Get Adobe Flash player
by osamX 01 Dec 2009
/**
 * Copyright osamX ( http://wonderfl.net/user/osamX )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xX3L
 */

// forked from bkzen's Reversi
package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.Loader;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	
	/**
	 * リバーシ
	 * @mxmlc -o bin/Reversi.swf -load-config+=obj\Alltest3Config.xml
	 * @author jc at bk-zen.com
	 */
	[SWF (backgroundColor = "0xFFFFFF", frameRate = "30", width = "465", height = "465")]
	public class Reversi extends Sprite
	{
		private const phaseInit: int = 0;
		private const phaseStart: int = 1;
		private const phaseTurnInit: int = 5;
		private const phaseTurnWait: int = 6;
		private const phaseTurnStoneMove: int = 7;
		private const phaseTurnChange: int = 8;
		private const phaseResult: int = 50;
		private const phaseEnd: int = 100;
		private const STN_URL: String = "http://assets.wonderfl.net/images/related_images/b/bc/bc29/bc29dba5e4eb1b1e57129ac8dc783a8347c5c2f3";
		private var phase: int = phaseInit;
		private var board: Board;
		private var boardBase: Shape;
		private var boardView: BitmapData;
		private var cellNavi: Sprite;
		private var cellBtns: Array = [];
		private var cellBtnFirst: CellBtn;
		private var stnRect: Rectangle;
		private var stnPoint: Point;
		private var player1: Player;
		private var player2: Player;
		private var nowTurn: int;
		private var pass: int;
		private var infoTxt: TextField;
		private var stoneBmd: BitmapData;
		private var loader: Loader;
		
		private const DEPTH:uint = LENGTH;
		
		public function Reversi() 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e: Event = null): void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			//
			loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComp);
			loader.load(new URLRequest(STN_URL), new LoaderContext(true));
		}
		
		/**
		 * 石画像読み込み完了
		 * @param	e
		 */
		private function onComp(e: Event): void 
		{
			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComp);
			stoneBmd = Bitmap(loader.content).bitmapData;
			make();
			addEventListener(Event.ENTER_FRAME, loop);
		}
		
		/**
		 * 色々作る
		 */
		private function make():void
		{
			board = new Board();
			boardBase = new Shape();
			cellNavi = new Sprite();
			var g: Graphics = boardBase.graphics;
			var m: Matrix = new Matrix();
			m.createGradientBox(SIZE, SIZE, 45 * Math.PI / 180);
			g.beginGradientFill(GradientType.LINEAR, [0x00CC00, 0x006600], [1, 1], [0x00, 0xFF], m);
			g.lineStyle(1);
			var ix: int, iy: int, beforeBtn: CellBtn;
			for (var i:int = 0; i < LENGTH; i++) 
			{
				ix = (i % 8) * CEL_SIZE;
				iy = (i >> 3) * CEL_SIZE;
				var cellBtn: CellBtn = new CellBtn(ix, iy, i, onClickCell);
				cellNavi.addChild(cellBtn);
				cellBtns.push(cellBtn);
				if (beforeBtn == null) cellBtnFirst = beforeBtn = cellBtn;
				else beforeBtn = beforeBtn.next = cellBtn;
				g.drawRect(ix, iy, CEL_SIZE, CEL_SIZE);
			}
			var bmp: Bitmap = new Bitmap(boardView = new BitmapData(SIZE, SIZE, true, 0x0), "auto", true);
			bmp.x = boardBase.x = cellNavi.x = board.x;
			bmp.y = boardBase.y = cellNavi.y = board.y;
			addChild(boardBase);
			addChild(bmp);
			addChild(cellNavi);
			stnRect = new Rectangle(0, 0, CEL_SIZE, CEL_SIZE);
			stnPoint = new Point();
			infoTxt = new TextField();
			infoTxt.background = infoTxt.border = true;
			infoTxt.width = stage.stageWidth - board.x * 2;
			infoTxt.height = stage.stageHeight - SIZE - board.y * 3;
			infoTxt.x = board.x;
			infoTxt.y = board.y * 2 + SIZE;
			addChild(infoTxt);
		}
		
		/**
		 * セルをクリックしたときのイベントハンドラ
		 * @param	e
		 */
		private function onClickCell(e: MouseEvent):void
		{
			var i: int = CellBtn(e.target).index;
			var cb: CellBtn = cellBtnFirst;
			do { cb.visible = false; } while (cb = cb.next);
			board.put(i, nowTurn);
			phase = phaseTurnStoneMove;
		}
		
		private function loop(e: Event ): void 
		{
			var c: Cell, cs: Cells, nowColor: String = "", i: int;
			switch (phase)
			{
				case phaseInit:
					/**
					 * 初期化
					 */
					boardView.lock();
					boardView.fillRect(boardView.rect, 0x0);
					c = board.first;
					do
					{
						if (c.stone != STN_N) 
						{
							stnPoint.x = c.posX;
							stnPoint.y = c.posY;
							stnRect.x = c.frame * CEL_SIZE;
							boardView.copyPixels(stoneBmd, stnRect, stnPoint);
						}
					}
					while (c = c.next);
					boardView.unlock();
					phase = phaseStart;
				break;
				case phaseStart:
					/**
					 * スタート。何かもっとやることあったようなきがしたけど忘れた。
					 */
					nowTurn = STN_B;
					pass = 0;
					phase = phaseTurnInit;
					log("開始");
					//trace(board.numStnB + " : " + board.numStnW);
				break;
				case phaseTurnInit:
					/**
					 * ターン開始。
					 * おける場所をハイライトする。
					 */
					nowColor = (nowTurn == STN_B ? "黒" : "白");
					log(nowColor + "の番です", false);
					cs = board.canPuts(nowTurn);
					//trace(cs.length);
					if (cs.length == 0) 
					{
						pass++;
						log(nowColor + "は置ける場所がないのでパスします。", false);
						phase = phaseTurnChange;
						if (pass == 2)
						{
							phase = phaseResult;
							return;
						}
						return;
					}
					else 
					{
						pass = 0;
						c = cs.first;
						do
						{
							CellBtn(cellBtns[c.index]).visible = true;
						}
						while (c = c.next);
					}
					cs.clear();
					phase = phaseTurnWait;
				break;
				case phaseTurnWait:
					if(nowTurn == STN_W){
						cs = board.canPuts(nowTurn);
						board.put(comMotion(STN_W), nowTurn);
						
						var cb: CellBtn = cellBtnFirst;
						do { cb.visible = false; } while (cb = cb.next);
						cs.clear();
						phase = phaseTurnStoneMove;
					}
					// 待ち
				break;
				case phaseTurnStoneMove:
					/**
					 * 石を動かす
					 */
					boardView.lock();
					boardView.fillRect(boardView.rect, 0x0);
					c = board.first;
					do
					{
						if (c.moveF != 0) 
						{
							c.frame += c.moveF;
							if (c.frame == 0 || c.frame == STN_F) c.moveF = 0;
							else i++
						}
						if (c.stone != STN_N) 
						{
							stnPoint.x = c.posX;
							stnPoint.y = c.posY;
							stnRect.x = c.frame * CEL_SIZE;
							boardView.copyPixels(stoneBmd, stnRect, stnPoint);
						}
					}
					while (c = c.next);
					boardView.unlock();
					if (i == 0) phase = phaseTurnChange;
				break;
				case phaseTurnChange:
					/**
					 * ターン終了して相手のターンに変える。
					 */
					if (board.numStnB + board.numStnW == LENGTH) 
					{
						phase = phaseResult;
						return;
					}
					nowTurn = nowTurn ^ 3;
					phase = phaseTurnInit;
				break;
				case phaseResult:
					/**
					 * 結果表示
					 */
					log("終了です。", false);
					log("黒 : 白 = " + board.numStnB + " : " + board.numStnW + " で " + (board.numStnB == board.numStnW ? "引き分けです。" : board.numStnB < board.numStnW ? "白の勝ちです。" : "黒の勝ちです。"));
					phase = phaseEnd;
				break;
			}
		}
		
		/**
		 * ログ表示
		 * @param	str
		 * @param	clear
		 */
		private function log(str: String, clear: Boolean = false): void
		{
			if (clear) infoTxt.text = str;
			else infoTxt.appendText(str + "\n");
			infoTxt.scrollV = infoTxt.maxScrollV;
		}
		
		/**
		 * 盤面の評価 ここを変えればもっと強くなるはず 開放度理論とか使えばいいかも?
		 * @param	bd
		 * @param	dp
		 * @param	stn
		 */
		private function eval(bd:Board, dp:uint, stn:int):Number {
			var score:Number = 0;
			score += stn == STN_W ? -bd.canPuts(STN_B).length * dp : bd.canPuts(STN_W).length * dp;
			score += (bd.numStnW - bd.numStnB) * (LENGTH-dp);
			const map:Array = bd.dataToArray(bd.toData());
			const KADO:Number = 100 * dp;
			if (map[ 0] != STN_N) score += map[ 0]==STN_W ? KADO : -KADO;
			if (map[ 7] != STN_N) score += map[ 7]==STN_W ? KADO : -KADO;
			if (map[56] != STN_N) score += map[56]==STN_W ? KADO : -KADO;
			if (map[63] != STN_N) score += map[63]==STN_W ? KADO : -KADO;
			
			return score;
		}
		
		/**
		 * COMはあほの子 バグ持ち?
		 * @param stn
		 */
		private function comMotion(stn:int):Number {
			var cell:Cell = board.canPuts(stn).first;
			var bestScore:Number = -9999999;
			var bestMotion:uint = 0;
			for (var i:uint = 0; i < board.canPuts(stn).length; i++) {
				var tmpbd:Board = board.clone();
				tmpbd.put(cell.index, stn);
				var tmpScore:Number = minmax(DEPTH, tmpbd, stn^3, eval(tmpbd, DEPTH, stn));
				//trace(board.toData());
				//trace(tmpbd.toData());
				if (tmpScore > bestScore) {
					bestScore = tmpScore;
					bestMotion = i;
				}
				tmpbd.clear();
				cell = cell.next;
			}
			cell = board.canPuts(stn).first;
			for (var j:uint = 0; j < bestMotion; j++) cell = cell.next;	//cellに最善の手を代入
			var ans:int = cell.index;
			cell.clear();
			trace("ans" + bestScore);
			return ans;
		}
		
		/**
		 * MINMAXでゲーム木探索
		 * @param	dp
		 * @param	bd
		 * @param	stn
		 * @param	sc
		 */
		private function minmax(dp:uint, bd:Board, stn:int, sc:Number):Number {
			if (dp <= 1 || bd.numStnB + bd.numStnW >= LENGTH) {
				return sc + eval(bd, dp, stn);
			}
			if (bd.canPuts(stn).length == 0) return minmax(dp - 1, bd, stn ^ 3, sc + eval(bd, dp, stn));
			
			var bestScore:Number = stn == STN_W ? -9999999 : 9999999;
			for (var cell:Cell = bd.canPuts(stn).first; cell; cell = cell.next) { //最善の手をさがす
				var tmpbd:Board = bd.clone();
				tmpbd.put(cell.index, stn);
				var tmpScore:Number = minmax(dp - 1, tmpbd, stn ^ 3, sc + eval(bd, dp, stn));
				if (stn == STN_W && bestScore < tmpScore) {			//俺のターン!
					bestScore = tmpScore;
				}else if (stn == STN_B && bestScore > tmpScore) {	//プレイヤーのターン!
					bestScore = tmpScore;
				}
				tmpbd.clear();
				cell.clear();
			}
			//trace("stn" + stn + " dp" + dp + " len" + bd.canPuts(stn).length + " best" + bestScore);
			return bestScore;
		}
	}
}

const STN_N: int	 = 0;	// 何もなし
const STN_B: int	 = 1;	// 黒
const STN_W: int	 = 2;	// 白
const STN_F: int	 = 6;	// 石のフレーム最後尾(0スタート)
const CEL_SIZE: int	 = 50;	// セルのサイズ
const SIZE: int		 = CEL_SIZE * 8;	// 盤のサイズ
const LENGTH: int	 = 64;	// セルの総数

class Board
{
	private const DEF_BOARD: Array = [
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 1, 2, 0, 0, 0,
		0, 0, 0, 2, 1, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0
	];
	public var first: Cell;
	public var cells: Array;
	private var _numStnB: int;
	private var _numStnW: int;
	
	public var x: int = 5;
	public var y: int = 5;
	
	function Board(arr: Array = null)
	{
		if (arr == null) arr = DEF_BOARD.concat();
		makeBoard(arr);
	}
	
	/**
	 * この場所におけるかチェック(多分使わない)
	 * @param	index
	 * @return
	 */
	public function canPut(index: int): Boolean
	{
		return false;
	}
	
	/**
	 * 置けるセルを取得
	 * @param	stn
	 * @return
	 */
	public function canPuts(stn: int): Cells
	{
		var c: Cell = first, res: Cell, tmp: Cell, l: int;
		var opp: int = stn ^ 3;
		do
		{
			if (c.stone == STN_N && checkLine(c, stn, opp))
			{
				if (res == null) tmp = res = c.clone();
				else tmp = tmp.next = c.clone();
				l++;
			}
		}
		while (c = c.next);
		return new Cells(res, l);
	}
	
	/**
	 * index の場所に 石をおく
	 * @param	index
	 * @param	stn
	 */
	public function put(index: int, stn: int): void
	{
		var cell: Cell = cells[index], c: Cell, opp: int = stn ^ 3, i: int = 1, mf: int = stn == STN_B ? -1 : 1;
		cell.frame = stn == STN_B ? 0 : STN_F;
		cell.stone = stn;
		c = cell.tl; // 左上
		if (c && c.stone == opp && checkTL(c, stn)) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.tl); }
		
		c = cell.t; // 上
		if (c && c.stone == opp && checkT(c, stn) ) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.t); }
		
		c = cell.tr; // 右上
		if (c && c.stone == opp && checkTR(c, stn)) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.tr); }
		
		c = cell.l; // 左
		if (c && c.stone == opp && checkL(c, stn) ) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.l); }
		
		c = cell.r; // 右
		if (c && c.stone == opp && checkR(c, stn) ) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.r); }
		
		c = cell.bl; // 左下
		if (c && c.stone == opp && checkBL(c, stn)) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.bl); }
		
		c = cell.b; // 下
		if (c && c.stone == opp && checkB(c, stn) ) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.b); }
		
		c = cell.br; // 右下
		if (c && c.stone == opp && checkBR(c, stn)) { do {
			if (c.stone == stn) break;
			c.moveF = mf, i++, c.stone = stn;
		} while (c = c.br); }
		
		if (stn == STN_B) 
		{
			_numStnB += i;
			_numStnW -= i - 1;
		}
		else 
		{
			_numStnW += i;
			_numStnB -= i - 1;
		}
	}
	
	/**
	 * どこかのラインが取れるかチェック
	 * @param	cell
	 * @param	stn
	 * @param	opp
	 * @return
	 */
	private function checkLine(cell: Cell, stn: int, opp: int): Boolean
	{
		var c: Cell;
		c = cell.tl; // 左上
		if (c && c.stone == opp && checkTL(c, stn)) return true;
		c = cell.t; // 上
		if (c && c.stone == opp && checkT(c, stn) ) return true;
		c = cell.tr; // 右上
		if (c && c.stone == opp && checkTR(c, stn)) return true;
		c = cell.l; // 左
		if (c && c.stone == opp && checkL(c, stn) ) return true;
		c = cell.r; // 右
		if (c && c.stone == opp && checkR(c, stn) ) return true;
		c = cell.bl; // 左下
		if (c && c.stone == opp && checkBL(c, stn)) return true;
		c = cell.b; // 下
		if (c && c.stone == opp && checkB(c, stn) ) return true;
		c = cell.br; // 左下
		if (c && c.stone == opp && checkBR(c, stn)) return true;
		
		return false;
	}
	
	// その方向に取れるのがあるかどうかをチェックする。TL(左上), T(上), TR(右上), L(左), R(右), BL(左下), B(下), BR(右)
	
	private function checkTL(c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.tl); return false; }
	private function checkT( c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.t ); return false; }
	private function checkTR(c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.tr); return false; }
	private function checkL( c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.l ); return false; }
	private function checkR( c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.r ); return false; }
	private function checkBL(c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.bl); return false; }
	private function checkB( c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.b ); return false; }
	private function checkBR(c: Cell, stn: int): Boolean { do { if (c.stone == stn) return true; else if (c.stone == STN_N) return false; } while (c = c.br); return false; }
	
	
	/**
	 * ボードの初期化
	 * @param	arr
	 */
	private function makeBoard(arr: Array):void
	{
		var i: int, n: int = arr.length, c: Cell, tmp: Array = [], s: int;
		tmp.push(first = c = new Cell(i, arr[i]));
		for (i = 1; i < n; i++) 
		{
			tmp.push(c.next = c = new Cell(i, s = arr[i]));
			if (s == STN_B) _numStnB ++;
			else if (s == STN_W) _numStnW ++; 
		}
		i = 0, c = first;
		do
		{
			if (i % 8)
			{
				if (i >> 3) c.tl = tmp[i - 9];
				if (63 - i >> 3) c.bl = tmp[i + 7];
				c.l = tmp[i - 1];
			}
			if (i % 8 != 7)
			{
				if (i >> 3) c.tr = tmp[i - 7];
				if (63 - i >> 3) c.br = tmp[i + 9];
				c.r = tmp[i + 1];
			}
			if (i >> 3) c.t = tmp[i - 8];
			if (63 - i >> 3) c.b = tmp[i + 8];
			i++;
		}
		while (c = c.next);
		cells = tmp;
	}
	
	/**
	 * 何かに使うかもってことでとりあえず作った str から Array に変える
	 * @param	str
	 * @return
	 */
	public function dataToArray(str: String): Array
	{
		return str.split(":");
	}
	
	/**
	 * 現在のマップをStringに変える。
	 * @return
	 */
	public function toData(): String
	{
		var c: Cell, res: String = "";
		c = first;
		do
		{
			res += c.stone + ":";
		}
		while (c = c.next);
		return res.slice(0, res.length - 1);
	}
	
	/**
	 * 黒の数
	 */
	public function get numStnB(): int { return _numStnB; }
	
	/**
	 * 白の数
	 */
	public function get numStnW(): int { return _numStnW; }
	
	public function clear():void {
		first.clear();
		cells.splice(0);
	}
	
	public function clone():Board {
		var bd:Board = new Board(dataToArray(toData()));
		return bd;
	}
}
/**
 * 1マス
 */
class Cell
{
	public var next: Cell;
	
	public var tl: Cell, t: Cell, tr: Cell, l: Cell, r: Cell, bl: Cell, b: Cell, br: Cell;
	public var index: int;
	public var stone: int;
	public var data1: Cell;
	public var data2: int;
	public var frame: int;
	public var moveF: int;
	public var posX: int, posY: int;
	
	function Cell(i: int, s: int)
	{
		index = i;
		stone = s;
		frame = s == STN_W ? STN_F : 0;
		posX = (index % 8) * CEL_SIZE;
		posY = (index >> 3) * CEL_SIZE;
	}
	
	public function clone(): Cell
	{
		var c: Cell = new Cell(index, stone);
		c.tl = tl, c.t = t, c.tr = tr, c.l = l, c.r = r, c.bl = bl, c.b = b, c.br = br;
		return c;
	}
	
	/**
	 * Cloneしたときはこれで消さないと GC対象にならないので注意。
	 */
	public function clear(): void
	{
		tl = t = tr = l = r = bl = b = br = next = data1 = null;
	}
}
/**
 * マスの塊。
 */
class Cells
{
	public var first: Cell;
	public var length: int;
	
	function Cells(f: Cell, l: int)
	{
		first = f;
		length = l;
	}
	
	public function clear(): void
	{
		var c: Cell = first, next: Cell;
		if (c == null) return;
		do
		{
			next = c.next;
			c.clear();
		}
		while ((c = next));
		first = null;
	}
}
import flash.display.Sprite;
import flash.events.MouseEvent;

/**
 * ボタン。ユーザーが取れる位置のボタン。
 */
class CellBtn extends Sprite
{
	public var next: CellBtn;
	private var _index: int;
	function CellBtn(ix: int, iy: int, i: int, handler: Function)
	{
		x = ix, y = iy, _index = i;
		graphics.beginFill(0xFFFFFF, 0.5);
		graphics.drawRect(0, 0, CEL_SIZE, CEL_SIZE);
		buttonMode = true, visible = false;
		addEventListener(MouseEvent.CLICK, handler);
	}
	
	public function get index(): int { return _index; }
}

/**
 * プレイヤー
 */
class Player
{
	protected var _stone: int;
	
	function Player(s: int) { _stone = s; }
	
	public function get stone(): int { return _stone; }
}