ぬるーむ

Unity初心者が誰もが知っているゲームの模倣をしています。個人的な備忘録ですが、入門書を読み終えたばかりの初心者の方は「こんなへなちょこでもいいのか!」「俺の方がうまく作れる」と作成意欲がわいたりするかもしれません。

Unityでリバーシを作ってみた 2


スポンサードリンク

Boardクラス

主に以下のことを行う。

  • LogicBoardを用いて盤の状態の更新、合法手の取得。
  • ViewBoardを用いて石、合法手の表示。
  • プレイヤー、ターンの管理。
public class Board : MonoBehaviour
{
    private Player[] players;
    private LogicBoard logicBoard;
    private ViewBoard viewBoard;
    private ulong movable;
    private int turn;

    public Player CurrentPlayer { get => players[turn % 2]; }
    public bool IsThinking { get; private set; }

    public void SetUp(Player[] players)
    {
        this.players = players;

        foreach(var p in players)
        {
            var cmp = p as Computer;

            if (cmp == null) continue;

            cmp.LogicBoard = logicBoard;
            //コンピュータが石を置いたときのイベントを登録
            cmp.Move += (s, e) => Move(e.MovePoint);
        }

        logicBoard.Move(3, 3, Stone.ColorType.Black);
        logicBoard.Move(4, 3, Stone.ColorType.White);
        logicBoard.Move(4, 4, Stone.ColorType.Black);
        logicBoard.Move(3, 4, Stone.ColorType.White);

        turn = 0;
    }

    //合法手があるか判定
    public bool ExistsMovablePoint()
    {
        IsThinking = true;

        movable = logicBoard.GetMovableBitBoard(CurrentPlayer.Color);

        return movable > 0;
    }

    //合法手のセルにマークを表示
    public void Render()
    {
        var movables = LogicBoard.BitToPoints(movable);

        viewBoard.RenderMarks(movables, CurrentPlayer.Color);
    }

   //全てを再描画
    public void RenderAll()
    {
        var bits = logicBoard.CurrentBitBoards;

        int black = (int)Stone.ColorType.Black;
        int white = (int)Stone.ColorType.White;
        var blacks = LogicBoard.BitToPoints(bits[black]);
        var whites = LogicBoard.BitToPoints(bits[white]);

        if (blacks.Count == 0 && whites.Count == 0) return;

        movable = logicBoard.GetMovableBitBoard(CurrentPlayer.Color);
        var movables = LogicBoard.BitToPoints(movable);

        viewBoard.RenderAll(blacks, whites, movables, CurrentPlayer.Color);
    }

    public void Next()
    {
        turn++;
        TurnChanged?.Invoke(this, EventArgs.Empty);
    }
    
    public void Previous()
    {
        turn--;
    }

    public void OnTurn()
    {
        CurrentPlayer.OnTurn();
    }

    public void Move(Vector2Int p)
    {
        StartCoroutine(CoroutineMove(p));
    }

    public void Pass()
    {
        logicBoard.Log();
    }

    private void Awake()
    {
        logicBoard = new LogicBoard();

        viewBoard = GetComponent<ViewBoard>();
        
        //セルをクリックしたとき処理を登録
        viewBoard.Setup((s, e) =>
        {
            if (!(CurrentPlayer is Human)) return;

            var cell = s as Cell;

            var mps = LogicBoard.BitToPoints(movable);

            if (!mps.Exists(p => p.x == cell.X && p.y == cell.Y))
            {
                Debug.Log("can't move");
                return;
            }

            if (cell != null)
            {
                var p = new Vector2Int(cell.X, cell.Y);
                StartCoroutine(CoroutineMove(p));
            }
        });

        movable = 0;
    }

    //石を置いた時の処理。石の回転を表示する為にコルーチンを用いる
    private IEnumerator CoroutineMove(Vector2Int p)
    {
        while (true)
        {
            //描画のみ。ビットボードの更新はReverse実行時
            viewBoard.RenderOne(p, CurrentPlayer.Color);

            logicBoard.Log();
            var r = logicBoard.Reverse(p.x, p.y, CurrentPlayer.Color);
            var rps = LogicBoard.BitToPoints(r);
            viewBoard.Reverse(rps);

            //石を回転中
            yield return new WaitWhile(() => !viewBoard.HasAllReversed);

            IsThinking = false;
            break;
        }
    }
}