白黒ゲームの盤クラス

by hi.kurosawa
白黒ゲーム(Reversi)の盤クラスの試験用
プレイヤーは二人とも人間が打ちます。
(きれいさは無視しています。)
白黒ゲーム(Reversi)のルールは問題なく動きます。
盤のクラス:clsBoard
共通関数クラス:clsRevCom(4/19追加)
♥0 | Line 349 | Modified 2011-04-19 11:17:27 | MIT License
play

ActionScript3 source code

/**
 * Copyright hi.kurosawa ( http://wonderfl.net/user/hi.kurosawa )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/jxHd
 */

package {
    //------------------------------------------
    //黒白ゲーム(Reversi)の盤のクラス試験用
    // 黒も白も人間が打ちます
    // URL:http://programmingatelier.net/
    //------------------------------------------
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.events.Event;
    import flash.events.MouseEvent;
    
    public class ReversiBoard extends Sprite {
        public var txtMess1:TextField;
        public var txtMess2:TextField;
        //ボードクラス(ボードとルール)
        private var objBoard:clsBoard;
        //打つプレイヤー(1:黒先行、2:白後攻)
        private var ip:int;
        
        public function ReversiBoard():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            txtMess1 = new TextField();
            addChild(txtMess1);
            txtMess1.x = 0;
            txtMess1.y = 0;
            txtMess1.width = 300;
            txtMess1.height = 20;
            txtMess1.border =true;
            txtMess2 = new TextField();
            addChild(txtMess2);
            txtMess2.x = 300;
            txtMess2.y = 0;
            txtMess2.width = 150;
            txtMess2.height = 450;
            txtMess2.border = true;
            txtMess2.multiline = true;
            
            objBoard = new clsBoard();
            addChild(objBoard);
            objBoard.x = 0;
            objBoard.y = 20;
            fncStart();
        }
        //ゲーム開始
        public function fncStart(e:*= null):void {
            fncMess2Clear();
            fncMess2Set("盤の初期化");
            objBoard.initDataSet();
            ip = clsRevCom.getFirstPlayer();        //1:黒先行
            fncMess1Set(clsRevCom.getPlColNam(ip) + "が打つ番です。");
            //盤がクリックしたときの関数定義
            objBoard.fncSetFnc(fncOnxy);
        }
        //盤がクリックしたとき
        // iti:クリックした升目("a1"~"h8")
        public function fncOnxy(itiNam:String):void {
            var n:int = objBoard.okuIti(itiNam, ip);
            if (n > 0) {    //升目がOKか,駒を置く
                fncMess2Set(clsRevCom.getPlColNam(ip) + ":" + itiNam + ":" + (n-1) + "個変更");
                ip = clsRevCom.getOtherPlayer(ip);  //次に打つプレイヤー
            } else {
                return;        //打てない升目をクリック
            }
            //次に打つプレイヤーが打てる場所があるか?
            if ( objBoard.chkPlayer(ip) >0) {
                fncMess1Set(clsRevCom.getPlColNam(ip) + "が打つ番です。");
                return;
            }
            //次の次のプレイヤーが打てる場所があるか?
            ip = clsRevCom.getOtherPlayer(ip);  //次に打つプレイヤー
            if ( objBoard.chkPlayer(ip) >0) {
                fncMess1Set(clsRevCom.getPlColNam(ip) + "が打つ番です。");
                return;
            }
            //二人とも打てる場所なし->終了
            var ip1:int = clsRevCom.getFirstPlayer();
            var ip2:int = clsRevCom.getOtherPlayer(ip1);
            var ip1n:int = objBoard.Kekka(ip1);
            var ip2n:int = objBoard.Kekka(ip2);
            var strWin:String = "引き分けです。";
            if (ip1n > ip2n) { strWin = clsRevCom.getPlColNam(ip1)+"の勝ちです。"; }
            if (ip1n < ip2n) { strWin = clsRevCom.getPlColNam(ip2)+"の勝ちです。"; }
            
            fncMess2Set("終了しました。" +strWin+"\n"+ clsRevCom.getPlColNam(ip1) + ":" + ip1n +
                            "/" + clsRevCom.getPlColNam(ip2) + ":" + ip2n);
            fncMess1Set("盤をクリックしてください、再開します。");
            objBoard.fncSetFnc(fncReStart);
        }
        //ゲーム再開
        private function fncReStart(iti:String):void {
            fncStart();
        }
        //メッセージ表示
        private function fncMess1Set(strMess:String):void {
            txtMess1.text = strMess;
        }
        private function fncMess2Clear():void {
            txtMess2.text = "";
        }
        private function fncMess2Set(strMess:String):void {
            txtMess2.text = strMess+"\n"+txtMess2.text;
        }
        
    }
}
//===============================================================================
//黒白ゲーム(リバーシ)
//共通関数
class clsRevCom {
    //枡目の名称
    static private const arrYokoName:Array = ["a", "b", "c", "d", "e", "f", "g", "h" ];
    static private const arrTateName:Array = ["1", "2", "3", "4", "5", "6", "7", "8" ];

    //升目の横方向の名称
    static public function getYokoNam(iti:int):String {
        var strRet:String = "";
        if (iti >= 0 && iti < arrYokoName.length) { strRet = arrYokoName[iti];}
        return strRet;
    }
    //升目の縦方向の名称
    static public function getTateNam(iti:int):String {
        var strRet:String = "";
        if (iti >= 0 && iti < arrTateName.length) { strRet = arrTateName[iti];}
        return strRet;
    }
    //升目の名称より横方向の位置を求める
    static public function getYokoIti(itiNam:String):int {
        var iti:int = -1;
        if (itiNam.length != 2) { return iti; }
        var s:String = itiNam.substr(0, 1);
        for (var i:int = 0; i < arrYokoName.length;i++ ) {
            if (arrYokoName[i] == s) { iti = i;}
        }
        return iti;
    }
    //升目の名称より縦方向の位置を求める
    static public function getTateIti(itiNam:String):int {
        var iti:int = -1;
        if (itiNam.length != 2) { return iti; }
        var s:String = itiNam.substr(1, 1);
        for (var i:int = 0; i < arrTateName.length;i++ ) {
            if (arrTateName[i] == s) { iti = i ;}
        }
        return iti;
    }
    //プレイヤーの色名称
    // ip:プレイヤー
    static public function getPlColNam(ip:int):String {
        if (ip == 1) { return "黒"; }
        if (ip == 2) { return "白"; }
        return "";
    }
    //最初に打つプレイヤー
    // ip:プレイヤー
    static public function getFirstPlayer():int {
        return 1;
    }
    //相手のプレイヤー
    // ip:プレイヤー
    static public function getOtherPlayer(ip:int):int {
        if (ip == 1) { return 2;}
        return 1;
    }
}
//=============================================================================
//黒白ゲーム(リバーシ)
//盤クラス(ボードとルール)
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.events.Event;
import flash.events.MouseEvent;

class clsBoard extends Sprite {
    //盤データ(先手黒:1、後手白:2、未配置:0、盤の外:-1)
    //initDataSet()関数を参照
    private var boardData:Array;
    //打った升目の履歴
    // {Player:プレイヤー(1,2),MasuIti:升目の名称("a1"~"h8"),KomaSuu:反転した数+1}
    private var arrRireki:Array;
    //升目のサイズ
    private const mSize:Number = 30;
    //盤をクリックしたときに呼び出す関数(クラス外部の関数を登録)
    //  func(itiNam:String):void
    //      itiNam:升目の名称("a1"~"h8")
    private var fncMouseDown:Function = null;
    
    //コンストラクター================================================
    public function clsBoard():void {
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    //初期化
    private function init(e:Event = null):void {
        disText();
        stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
        initDataSet();
    }
    //升目の名称表示
    private function disText():void {
        var i:int;
        var textField:TextField;
        for (i = 1; i < 9; i++) {
            textField = new TextField();
            textField.autoSize = TextFieldAutoSize.LEFT;
            textField.width = 20;
            textField.wordWrap = true;
            textField.x = mSize-10;
            textField.y = mSize*i;
            textField.text = clsRevCom.getTateNam(i-1);
            addChild(textField);
            textField = new TextField();
            textField.autoSize = TextFieldAutoSize.LEFT;
            textField.width = 20;
            textField.wordWrap = true;
            textField.x = mSize*i;
            textField.y = mSize-18;
            textField.text = clsRevCom.getYokoNam(i-1);
            addChild(textField);
        }
    }

    //盤をクリックしたときに呼び出す関数の登録==============================
    public function fncSetFnc(fnc:Function):void {
        fncMouseDown = fnc;
    }
    //盤をクリックしたときの処理
    private function onMouseDown(event:MouseEvent):void {
        if(fncMouseDown==null) { return;}
        var itiX:int = mouseX / mSize;
        var itiY:int = mouseY / mSize;
        if (itiX <= 0 || itiX > 8 || itiY <= 0 || itiY > 8) { return;}
        fncMouseDown(clsRevCom.getYokoNam(itiX-1)+clsRevCom.getTateNam(itiY-1));
    }
    //盤の初期化==================================================
    public function initDataSet():void {
        var ip1:int = clsRevCom.getFirstPlayer();
        var ip2:int = clsRevCom.getOtherPlayer(ip1);
        boardData = new Array(
            new Array( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
            new Array( -1, 0, 0, 0, 0, 0, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, 0, 0, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, 0, 0, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, ip2, ip1, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, ip1, ip2, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, 0, 0, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, 0, 0, 0, 0, 0, -1),
            new Array( -1, 0, 0, 0, 0, 0, 0, 0, 0, -1),
            new Array( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1));
        arrRireki = new Array();
        disBoard();
    }

    //盤の表示(升目の名称以外)
    private function disBoard():void {
        var i:int;
        var j:int;
        var ip1:int = clsRevCom.getFirstPlayer();
        var ip2:int = clsRevCom.getOtherPlayer(ip1);

        graphics.clear();
        graphics.lineStyle(1, 0x000000);
        for (i = 0; i < 9; i++) {
            graphics.moveTo(mSize, i*mSize+mSize);
            graphics.lineTo(mSize*9, i*mSize+mSize);
            graphics.moveTo(i*mSize+mSize,mSize );
            graphics.lineTo(i*mSize+mSize,mSize*9);
        }
        
        for (i = 1; i < 9; i++) {
            for (j = 1; j < 9; j++) {
                if (boardData[i][j] == ip1) {
                    // 黒:円を描く (中を塗りつぶす)
                    graphics.lineStyle(1, 0x000000);
                    graphics.beginFill(0x000000);
                    graphics.drawCircle(mSize*i+mSize/2, mSize*j+mSize/2, mSize*0.4);
                    graphics.endFill();

                }else if (boardData[i][j] == ip2) {
                    // 白:円を描く (中を塗りつぶさない)
                    graphics.lineStyle(1, 0x000000);
                    graphics.drawCircle(mSize*i+mSize/2, mSize*j+mSize/2, mSize*0.4);
                    graphics.endFill();
                }
            }
        }
    }
    //指定升目に打てるかチェック=====================================
    // itiNam:升目の名称("a1"~"h8")
    // ip:プレイヤー(1,2)
    // 戻り値:反転する升目数+1(打った駒)、0=置けません
    public function chkIti(itiNam:String, ip:int):int {
        var intRet:int = 0;
        var itiX:int = clsRevCom.getYokoIti(itiNam)+1;
        var itiY:int = clsRevCom.getTateIti(itiNam)+1;
        if (itiX == 0 || itiY == 0) { return intRet; }
        intRet = chkItiXY(itiX, itiY, ip);
        return intRet;
    }
    // itiX,itiY:チェックする升目
    // ip:プレイヤー
    // 戻り値:反転する升目数+1(打った駒)、0=置けません
    private function chkItiXY(itiX:int,itiY:int, ip:int):int {
        var intRet:int = 0;
        var ip2:int =clsRevCom.getOtherPlayer(ip);
        //指定升目に何もない
        if (boardData[itiX][itiY] != 0) { return intRet; }
        //8方向をチェック、まず敵の色(繰り返し)、自分の色のチェックを行う
        for (var idx:int = -1; idx <= 1; idx++) {
            for (var idy:int = -1; idy <= 1; idy++) {
                if (idx != 0 || idy != 0) {
                    if (boardData[itiX+idx][itiY+idy] == ip2) {
                        var n:int = chkItiXYnext(itiX+idx, itiY+idy, idx, idy, ip,ip2);
                        if( n>0) { intRet+=n;}
                    }
                }
            }
        }
        if (intRet > 0) { intRet++;}
        return intRet;
    }
    //指定升目に打てるかチェック(再起関数)
    // itiX,itiY:チェックする升目
    // idx,idy:チェックする方向(8方向の1方向)
    // ip,ip2:自分と相手
    // 戻り値:true:配置できる
    private function chkItiXYnext(itiX:int, itiY:int, 
            idx:int, idy:int, ip:int, ip2:int):int {
        var intRet:int = 0;
        //自分の色ならOK
        if (boardData[itiX + idx][itiY + idy] == ip) { 
            intRet = 0;
        //敵の色なら次をチェック
        } else if(boardData[itiX + idx][itiY + idy] == ip2) { 
            intRet=chkItiXYnext(itiX+idx, itiY+idy, idx, idy, ip, ip2);
        } else {
            //その他(空、盤の外)ならNG
            intRet = -1;
        }
        if (intRet >= 0) { 
            intRet++;
        }
        return intRet;
    }
    //指定升目に駒を置く=====================================
    // itiNam:升目の名称("a1"~"h8")
    // ip:プレイヤー(1,2)
    // 戻り値:反転する升目数+1(打った駒)、0=置けません
    public function okuIti(itiNam:String, ip:int):int {
        var intRet:int = 0;
        var itiX:int = clsRevCom.getYokoIti(itiNam)+1;
        var itiY:int = clsRevCom.getTateIti(itiNam)+1;
        if (itiX == 0 || itiY == 0) { return intRet; }
        intRet = okuItiXY(itiX, itiY, ip);
        if (intRet>0) {
            disBoard();
            arrRireki.push({Player:ip,MasuIti:itiNam,KomaSuu:intRet});
        }
        return intRet;
    }
    // itiX,itiY:チェックする升目
    // ip:プレイヤー
    // 戻り値:反転する升目数+1(打った駒)、0=置けません
    private function okuItiXY(itiX:int,itiY:int, ip:int):int {
        var intRet:int = 0;
        var ip2:int =clsRevCom.getOtherPlayer(ip);
        if (chkItiXY(itiX, itiY, ip) ==0) { return intRet; }
        //8方向をチェックと駒を反転
        for (var idx:int = -1; idx <= 1; idx++) {
            for (var idy:int = -1; idy <= 1; idy++) {
                if (idx != 0 || idy != 0) {
                    if (boardData[itiX + idx][itiY + idy] == ip2) {
                        var n:int = setItiXYnext(itiX + idx, itiY + idy, idx, idy, ip, ip2);
                        if( n>0) { intRet+=n;}
                    }
                }
            }
        }
        //反転した駒があるとき指定場祖にお置く
        if (intRet > 0) { 
            boardData[itiX][itiY] = ip; 
            intRet++;
        }
        return intRet;
    }
    //指定升目に打てるかチェック、駒の反転(再起関数)
    // itiX,itiY:チェックする升目
    // idx,idy:チェックする方向(8方向の1方向)
    // ip,ip2:自分と相手
    // 戻り値:true:駒の反転あり
    private function setItiXYnext(itiX:int, itiY:int,
            idx:int, idy:int, ip:int, ip2:int):int {
        var intRet:int = 0;
        //自分と同じ駒ならOK
        if (boardData[itiX + idx][itiY + idy] == ip) {
            intRet = 0;
        //相手と同じなら次をチェック
        } else if (boardData[itiX + idx][itiY + idy] == ip2) { 
            intRet=setItiXYnext(itiX+idx, itiY+idy, idx, idy, ip, ip2);
        } else {
            intRet = -1;
        }
        //その他(空、盤の外)ならNG
        //OKなら戻るとき反転する
        if (intRet >= 0) { 
            boardData[itiX][itiY] = ip; 
            intRet++;
        }
        return intRet;
    }
    //指定プレーヤに打つ場所があるか=======================================
    // ip:プレイヤー
    // 戻り値:打つ場所の有(true)/無(false)
    public function chkPlayer(ip:int):Boolean {
        for (var itiX:int = 1; itiX < 9; itiX++) {
            for (var itiY:int = 1; itiY < 9; itiY++) {
                if (chkItiXY(itiX, itiY, ip) >0) { return true; }
            }
        }
        return false;
    }
    //指定プレーヤ、未配置の駒数=================================================
    // ip:プレイヤー(1,2)、0で未配置
    // 戻り値:駒数
    public function Kekka(ip:int):int {
        var kazu:int = 0;
        for (var itiX:int = 1; itiX < 9; itiX++) {
            for (var itiY:int = 1; itiY < 9; itiY++) {
                if (boardData[itiX][itiY] == ip) { kazu++;}
            }
        }
        return kazu;
    }
    //指定位置の枡の状態================================================
    // itiNam:升目の名称("a1"~"h8")
    //  戻り値:黒(1)、白(2)、未(0)、升目不正(-1)
    public function masuJyoutai(itiNam:String):int {
        var itiX:int = clsRevCom.getYokoIti(itiNam)+1;
        var itiY:int = clsRevCom.getTateIti(itiNam)+1;
        if (itiX == 0 || itiY == 0) { return -1; }
        return boardData[itiX][itiY];
    }
    //打った升目の履歴の取得=====================================================
    // no:no回前(0が一回前)の履歴を取得
    // 戻り値:履歴{Player:プレイヤー(1,2),MasuIti:升目名("a1","b5"),KomaSuu:反転した数+1}
    //      noが正しくないときnull
    public function getRireki(no:int):Object {
        var objRet:Object = null;
        if (no >= 0 && no < arrRireki.length) {
            objRet = arrRireki[arrRireki.length-no-1];
        }
        return objRet;
    }
}