Exemplo n.º 1
0
        /// <summary>
        /// GameStart()とGameRestart()の共通部分
        /// </summary>
        private void GameStartInCommon(GameModeEnum nextGameMode)
        {
            var gameSetting = GameSetting;

            // 現在の時間設定を、KifuManager.Treeに反映させておく(棋譜保存時にこれが書き出される)
            kifuManager.Tree.KifuTimeSettings = gameSetting.KifuTimeSettings;

            // 対局者氏名の設定
            // 対局設定ダイアログの名前をそのまま引っ張ってくる。
            foreach (var c in All.Colors())
            {
                var name = gameSetting.PlayerSetting(c).PlayerName;
                SetPlayerName(c, name);
            }

            // 持ち時間設定の表示文字列の構築(最初に構築してしまい、対局中には変化させない)
            foreach (var c in All.Colors())
            {
                var pc = PlayTimer(c);
                pc.KifuTimeSetting = GameSetting.KifuTimeSettings.Player(c);
                pc.GameStart();

                var    left  = pc.KifuTimeSetting.ToShortString();
                var    right = PresetWithBoardTypeString(c);
                string total;
                if (right.Empty())
                {
                    total = left;
                }
                else if (left.Empty())
                {
                    total = right;                  // このとき連結のための"/"要らない
                }
                else if (left.UnicodeLength() + right.UnicodeLength() < 24)
                {
                    total = $"{left}/{right}";      // 1行で事足りる
                }
                else
                {
                    total = $"{left}\r\n{right}";   // 2行に分割する。
                }
                timeSettingStrings[(int)c] = total;
            }

            // rootの持ち時間設定をここに反映させておかないと待ったでrootまで持ち時間が戻せない。
            // 途中の局面からだとここではなく、現局面のところに書き出す必要がある。
            kifuManager.Tree.SetKifuMoveTimes(PlayTimers.GetKifuMoveTimes());

            // コンピュータ vs 人間である場合、人間側を手前にしてやる。
            // 人間 vs 人間の場合も最初の手番側を手前にしてやる。
            // ただし、人間 vs 人間で振り駒でこの手番が決まったのであれば、
            // それを反映しなければならない。

            var stm = kifuManager.Position.sideToMove;

            if (gameSetting.PlayerSetting(stm).IsHuman)
            {
                // 1. 両方が人間である場合、普通は手番側が手前だが、振り駒をしたなら
                //  対局設定の左側のプレイヤーがつねに手前。
                if (gameSetting.PlayerSetting(stm.Not()).IsHuman)
                {
                    BoardReverse = (stm == Color.WHITE) ^ continuousGame.Swapped;
                }

                // 2. 手番側が人間である場合(非手番側がCPU)
                else
                {
                    BoardReverse = (stm == Color.WHITE);
                }
            }
            // 3. 手番側がCPUで、非手番側が人間である場合。
            else if (gameSetting.PlayerSetting(stm).IsCpu&& gameSetting.PlayerSetting(stm.Not()).IsHuman)
            {
                BoardReverse = (stm == Color.BLACK);
            }

            // プレイヤー情報などを検討ダイアログに反映させる。
            InitEngineConsiderationInfo(nextGameMode);

            // 検討モードならそれを停止させる必要があるが、それはGameModeのsetterがやってくれる。
            GameMode = nextGameMode;
        }
Exemplo n.º 2
0
        /// <summary>
        /// 指し手が指されたかのチェックを行う
        /// </summary>
        private void CheckPlayerMove()
        {
            // 現状の局面の手番側
            var stm       = Position.sideToMove;
            var stmPlayer = Player(stm);

            var config = TheApp.app.Config;

            // -- 指し手

            Move bestMove;

            if (GameMode.IsConsiderationWithEngine())
            {
                // 検討モードなのでエンジンから送られてきたbestMoveの指し手は無視。
                bestMove = stmPlayer.SpecialMove;
            }
            else
            {
                // 対局設定ダイアログの「コンピューターは1手に必ずこれだけ使う」が設定されていれば、
                // その時間になるまでbest moveを無視する。
                var stmBestMove = stmPlayer.BestMove;
                if (stmBestMove != Move.NONE &&
                    GameMode == GameModeEnum.InTheGame && /* 通常対局中 */
                    stmPlayer.PlayerType == PlayerTypeEnum.UsiEngine &&
                    GameSetting.MiscSettings.EnableBestMoveIgnoreTimeForEngine &&
                    PlayTimer(stm).ElapsedTime() < GameSetting.MiscSettings.BestMoveIgnoreTimeForEngine
                    )
                {
                    stmBestMove = Move.NONE;
                }

                // TIME_UPなどのSpecialMoveが積まれているなら、そちらを優先して解釈する。
                bestMove = stmPlayer.SpecialMove != Move.NONE ? stmPlayer.SpecialMove : stmBestMove;
            }

            if (bestMove != Move.NONE)
            {
                PlayTimer(stm).ChangeToThemTurn(bestMove == Move.TIME_UP);

                stmPlayer.SpecialMove = Move.NONE; // クリア

                // 駒が動かせる状況でかつ合法手であるなら、受理する。

                bool specialMove = false;
                if (GameMode == GameModeEnum.InTheGame)
                {
                    // 送信されうる特別な指し手であるか?
                    specialMove = bestMove.IsSpecial();

                    // エンジンから送られてきた文字列が、illigal moveであるならエラーとして表示する必要がある。

                    if (specialMove)
                    {
                        switch (bestMove)
                        {
                        // 入玉宣言勝ち
                        case Move.WIN:
                            var rule = (EnteringKingRule)GameSetting.MiscSettings.EnteringKingRule;
                            if (Position.DeclarationWin(rule) != Move.WIN)
                            {
                                // 入玉宣言条件を満たしていない入玉宣言
                                goto ILLEGAL_MOVE;
                            }
                            break;

                        // 中断
                        // コンピューター同士の対局の時にも人間判断で中断できなければならないので
                        // 対局中であればこれを無条件で受理する。
                        case Move.INTERRUPT:
                        // 時間切れ
                        // 時間切れになるとBestMoveに自動的にTIME_UPが積まれる。これも無条件で受理する。
                        case Move.TIME_UP:
                            break;

                        // 投了
                        case Move.RESIGN:
                            break;     // 手番側の投了は無条件で受理

                        // それ以外
                        default:
                            // それ以外は受理しない
                            goto ILLEGAL_MOVE;
                        }
                    }
                    else if (!Position.IsLegal(bestMove))
                    {
                        // 合法手ではない
                        goto ILLEGAL_MOVE;
                    }


                    // -- bestMoveを受理して、局面を更新する。

                    kifuManager.Tree.AddNode(bestMove, PlayTimers.GetKifuMoveTimes());

                    // 受理できる性質の指し手であることは検証済み
                    // special moveであってもDoMove()してしまう。
                    kifuManager.DoMove(bestMove);

                    KifuDirty = true; // 新しいnodeに到達したので棋譜は汚れた扱い。

                    // -- 音声の読み上げ

                    var soundManager = TheApp.app.SoundManager;

                    // special moveはMoveを直接渡して再生。
                    if (bestMove.IsSpecial())
                    {
                        soundManager.ReadOut(bestMove);
                    }
                    else
                    {
                        // -- 駒音

                        PlayPieceSound(GameMode, bestMove.To(), stm);

                        // -- 棋譜の読み上げ

                        // 「先手」と「後手」と読み上げる。
                        if (!sengo_read_out[(int)stm] || config.ReadOutSenteGoteEverytime != 0)
                        {
                            sengo_read_out[(int)stm] = true;

                            // 駒落ちの時は、「上手(うわて)」と「下手(したて)」
                            if (!Position.Handicapped)
                            {
                                soundManager.ReadOut(stm == Color.BLACK ? SoundEnum.Sente : SoundEnum.Gote);
                            }
                            else
                            {
                                soundManager.ReadOut(stm == Color.BLACK ? SoundEnum.Shitate : SoundEnum.Uwate);
                            }
                        }

                        // 棋譜文字列をそのまま頑張って読み上げる。
                        // ただし、棋譜ウィンドウの表示形式を変更できるので…。

                        var kif = kifuManager.Tree.LastKifuString;
                        soundManager.ReadOut(kif);
                    }
                }

                // -- 次のPlayerに、自分のturnであることを通知してやる。

                if (!specialMove)
                {
                    // 相手番になったので諸々通知。
                    NotifyTurnChanged();
                }
                else
                {
                    // 特殊な指し手だったので、これにてゲーム終了
                    GameEnd(bestMove);
                }
            }

            return;

ILLEGAL_MOVE:

            // これ、棋譜に記録すべき
            Move m = Move.ILLEGAL_MOVE;

            kifuManager.Tree.AddNode(m, PlayTimers.GetKifuMoveTimes());
            kifuManager.Tree.AddNodeComment(m, stmPlayer.BestMove.ToUsi() /* String あとでなおす*/ /* 元のテキスト */);
            kifuManager.Tree.DoMove(m);

            GameEnd(m); // これにてゲーム終了。
        }
Exemplo n.º 3
0
        /// <summary>
        /// 対局開始のためにGameSettingの設定に従い、ゲームを初期化する。
        /// </summary>
        /// <param name="gameSetting"></param>
        private void GameStart(GameSetting gameSetting)
        {
            // 以下の初期化中に駒が動かされるの気持ち悪いのでユーザー操作を禁止しておく。
            CanUserMove  = false;
            Initializing = true;
            var nextGameMode = GameModeEnum.InTheGame;

            // 音声:「よろしくお願いします。」
            TheApp.app.soundManager.Stop(); // 再生中の読み上げをすべて停止
            TheApp.app.soundManager.ReadOut(SoundEnum.Start);

            // 初回の指し手で、「先手」「後手」と読み上げるためのフラグ
            sengo_read_out = new bool[2] {
                false, false
            };

            // プレイヤーの生成
            UsiEngineHashManager.Init();
            foreach (var c in All.Colors())
            {
                var gamePlayer = gameSetting.PlayerSetting(c);
                var playerType = gamePlayer.IsHuman ? PlayerTypeEnum.Human : PlayerTypeEnum.UsiEngine;
                Players[(int)c] = PlayerBuilder.Create(playerType);

                if (playerType == PlayerTypeEnum.UsiEngine)
                {
                    var engineDefineEx = TheApp.app.EngineDefines.Find(x => x.FolderPath == gamePlayer.EngineDefineFolderPath);
                    if (engineDefineEx == null)
                    {
                        TheApp.app.MessageShow("エンジンがありませんでした。" + gamePlayer.EngineDefineFolderPath, MessageShowType.Error);
                        return;
                    }
                    var usiEnginePlayer = Players[(int)c] as UsiEnginePlayer;
                    var ponder          = gamePlayer.Ponder;
                    InitUsiEnginePlayer(c, usiEnginePlayer, engineDefineEx, gamePlayer.SelectedEnginePreset, nextGameMode, ponder);
                }
            }

            // 局面の設定
            kifuManager.EnableKifuList = true;
            if (gameSetting.BoardSetting.BoardTypeCurrent)
            {
                // 現在の局面からなので、いま以降の局面を削除する。
                // ただし、いまの局面と棋譜ウィンドウとが同期しているとは限らない。
                // まず現在局面以降の棋譜を削除しなくてはならない。

                // 元nodeが、special moveであるなら、それを削除しておく。
                if (kifuManager.Tree.IsSpecialNode())
                {
                    kifuManager.Tree.UndoMove();
                }

                kifuManager.Tree.ClearForward();

                // 分岐棋譜かも知れないので、現在のものを本譜の手順にする。
                kifuManager.Tree.MakeCurrentNodeMainBranch();
            }
            else // if (gameSetting.Board.BoardTypeEnable)
            {
                kifuManager.Init();
                kifuManager.InitBoard(gameSetting.BoardSetting.BoardType);
            }

            // 本譜の手順に変更したので現在局面と棋譜ウィンドウのカーソルとを同期させておく。
            UpdateKifuSelectedIndex();

            // エンジンに与えるHashSize,Threadsの計算
            if (UsiEngineHashManager.CalcHashSize() != 0)
            {
                // Hash足りなくてダイアログ出した時にキャンセルボタン押されとる
                Disconnect();

                // ゲームが終局したことを通知するために音声があったほうがよさげ。
                TheApp.app.soundManager.ReadOut(SoundEnum.End);

                return;
            }

            // 現在の時間設定を、KifuManager.Treeに反映させておく(棋譜保存時にこれが書き出される)
            kifuManager.Tree.KifuTimeSettings = gameSetting.KifuTimeSettings;

            // 対局者氏名の設定
            // 人間の時のみ有効。エンジンの時は、エンジン設定などから取得することにする。
            foreach (var c in All.Colors())
            {
                var    player = Player(c);
                string name;
                switch (player.PlayerType)
                {
                case PlayerTypeEnum.Human:
                    name = gameSetting.PlayerSetting(c).PlayerName;
                    break;

                default:
                    name = c.Pretty();
                    break;
                }

                kifuManager.KifuHeader.SetPlayerName(c, name);
            }

            // 持ち時間などの設定が必要なので、コピーしておく。
            GameSetting = gameSetting;

            // 消費時間計算用
            foreach (var c in All.Colors())
            {
                var pc = PlayTimer(c);
                pc.KifuTimeSetting = GameSetting.KifuTimeSettings.Player(c);
                pc.GameStart();
                timeSettingStrings[(int)c] = pc.KifuTimeSetting.ToShortString();
            }

            // rootの持ち時間設定をここに反映させておかないと待ったでrootまで持ち時間が戻せない。
            // 途中の局面からだとここではなく、現局面のところに書き出す必要がある。
            kifuManager.Tree.SetKifuMoveTimes(PlayTimers.GetKifuMoveTimes());

            // コンピュータ vs 人間である場合、人間側を手前にしてやる。
            // 人間 vs 人間の場合も最初の手番側を手前にしてやる。
            var stm = kifuManager.Position.sideToMove;

            // 1. 手番側が人間である場合(非手番側が人間 or CPU)
            if (gameSetting.PlayerSetting(stm).IsHuman)
            {
                BoardReverse = (stm == Color.WHITE);
            }
            // 2. 手番側がCPUで、非手番側が人間である場合。
            else if (gameSetting.PlayerSetting(stm).IsCpu&& gameSetting.PlayerSetting(stm.Not()).IsHuman)
            {
                BoardReverse = (stm == Color.BLACK);
            }

            // プレイヤー情報などを検討ダイアログに反映させる。
            InitEngineConsiderationInfo(nextGameMode);

            // 検討モードならそれを停止させる必要があるが、それはGameModeのsetterがやってくれる。
            GameMode = nextGameMode;
        }
Exemplo n.º 4
0
        /// <summary>
        /// 対局開始のためにGameSettingの設定に従い、ゲームを初期化する。
        /// </summary>
        /// <param name="gameSetting"></param>
        private void GameStart(GameSetting gameSetting)
        {
            // 以下の初期化中に駒が動かされるの気持ち悪いのでユーザー操作を禁止しておく。
            CanUserMove      = false;
            lastInitializing = true;

            // 音声:「よろしくお願いします。」
            TheApp.app.soundManager.Stop(); // 再生中の読み上げをすべて停止
            TheApp.app.soundManager.ReadOut(SoundEnum.Start);

            // 初回の指し手で、「先手」「後手」と読み上げるためのフラグ
            sengo_read_out = new bool[2] {
                false, false
            };

            // プレイヤーの生成
            foreach (var c in All.Colors())
            {
                var playerType = gameSetting.Player(c).IsHuman ? PlayerTypeEnum.Human : PlayerTypeEnum.UsiEngine;
                Players[(int)c] = PlayerBuilder.Create(playerType);
            }

            // 局面の設定
            kifuManager.EnableKifuList = true;
            if (gameSetting.Board.BoardTypeCurrent)
            {
                // 現在の局面からなので、いま以降の局面を削除する。
                // ただし、いまの局面と棋譜ウィンドウとが同期しているとは限らない。
                // まず現在局面以降の棋譜を削除しなくてはならない。

                // 元nodeが、special moveであるなら、それを削除しておく。
                if (kifuManager.Tree.IsSpecialNode())
                {
                    kifuManager.Tree.UndoMove();
                }

                kifuManager.Tree.ClearForward();

                // 分岐棋譜かも知れないので、現在のものを本譜の手順にする。
                kifuManager.Tree.MakeCurrentNodeMainBranch();
            }
            else // if (gameSetting.Board.BoardTypeEnable)
            {
                kifuManager.Init();
                kifuManager.InitBoard(gameSetting.Board.BoardType);
            }

            // 本譜の手順に変更したので現在局面と棋譜ウィンドウのカーソルとを同期させておく。
            UpdateKifuSelectedIndex();

            // 現在の時間設定を、KifuManager.Treeに反映させておく(棋譜保存時にこれが書き出される)
            kifuManager.Tree.KifuTimeSettings = gameSetting.KifuTimeSettings;

            // 対局者氏名の設定
            // 人間の時のみ有効。エンジンの時は、エンジン設定などから取得することにする。(TODO:あとで考える)
            foreach (var c in All.Colors())
            {
                var    player = Player(c);
                string name;
                switch (player.PlayerType)
                {
                case PlayerTypeEnum.Human:
                    name = gameSetting.Player(c).PlayerName;
                    break;

                default:
                    name = c.Pretty();
                    break;
                }

                kifuManager.KifuHeader.SetPlayerName(c, name);
            }

            // 持ち時間などの設定が必要なので、コピーしておく。
            GameSetting = gameSetting;

            // 消費時間計算用
            foreach (var c in All.Colors())
            {
                var pc = PlayTimer(c);
                pc.KifuTimeSetting = GameSetting.KifuTimeSettings.Player(c);
                pc.GameStart();
            }

            // rootの持ち時間設定をここに反映させておかないと待ったでrootまで持ち時間が戻せない。
            // 途中の局面からだとここではなく、現局面のところに書き出す必要がある。
            kifuManager.Tree.SetKifuMoveTimes(PlayTimers.GetKifuMoveTimes());

            // コンピュータ vs 人間である場合、人間側を手前にしてやる。
            // 人間 vs 人間の場合も最初の手番側を手前にしてやる。
            var stm = kifuManager.Position.sideToMove;

            // 1. 手番側が人間である場合(非手番側が人間 or CPU)
            if (gameSetting.Player(stm).IsHuman)
            {
                BoardReverse = (stm == Color.WHITE);
            }
            // 2. 手番側がCPUで、非手番側が人間である場合。
            else if (gameSetting.Player(stm).IsCpu&& gameSetting.Player(stm.Not()).IsHuman)
            {
                BoardReverse = (stm == Color.BLACK);
            }

            // プレイヤー情報などを検討ダイアログに反映させる。
            var nextGameMode = GameModeEnum.InTheGame;

            InitEngineConsiderationInfo(nextGameMode);

            // 検討モードならそれを停止させる必要があるが、それはGameModeのsetterがやってくれる。
            GameMode = nextGameMode;
        }
Exemplo n.º 5
0
        /// <summary>
        /// 指し手が指されたかのチェックを行う
        /// </summary>
        private void CheckPlayerMove()
        {
            // 現状の局面の手番側
            var stm       = Position.sideToMove;
            var stmPlayer = Player(stm);

            var config = TheApp.app.config;

            // -- 指し手

            Move bestMove;

            if (GameMode.IsWithEngine())
            {
                // 検討モードなのでエンジンから送られてきたbestMoveの指し手は無視。
                bestMove = stmPlayer.SpecialMove;
            }
            else
            {
                // TIME_UPなどのSpecialMoveが積まれているなら、そちらを優先して解釈する。
                bestMove = stmPlayer.SpecialMove != Move.NONE ? stmPlayer.SpecialMove : stmPlayer.BestMove;
            }

            if (bestMove != Move.NONE)
            {
                PlayTimer(stm).ChageToThemTurn(bestMove == Move.TIME_UP);

                stmPlayer.SpecialMove = Move.NONE; // クリア

                // 駒が動かせる状況でかつ合法手であるなら、受理する。

                bool specialMove = false;
                if (GameMode == GameModeEnum.InTheGame)
                {
                    // 送信されうる特別な指し手であるか?
                    specialMove = bestMove.IsSpecial();

                    // エンジンから送られてきた文字列が、illigal moveであるならエラーとして表示する必要がある。

                    if (specialMove)
                    {
                        switch (bestMove)
                        {
                        // 入玉宣言勝ち
                        case Move.WIN:
                            if (Position.DeclarationWin(EnteringKingRule.POINT27) != Move.WIN)
                            {
                                // 入玉宣言条件を満たしていない入玉宣言
                                goto ILLEGAL_MOVE;
                            }
                            break;

                        // 中断
                        // コンピューター同士の対局の時にも人間判断で中断できなければならないので
                        // 対局中であればこれを無条件で受理する。
                        case Move.INTERRUPT:
                        // 時間切れ
                        // 時間切れになるとBestMoveに自動的にTIME_UPが積まれる。これも無条件で受理する。
                        case Move.TIME_UP:
                            break;

                        // 投了
                        case Move.RESIGN:
                            break;     // 手番側の投了は無条件で受理

                        // それ以外
                        default:
                            // それ以外は受理しない
                            goto ILLEGAL_MOVE;
                        }
                    }
                    else if (!Position.IsLegal(bestMove))
                    {
                        // 合法手ではない
                        goto ILLEGAL_MOVE;
                    }


                    // -- bestMoveを受理して、局面を更新する。

                    kifuManager.Tree.AddNode(bestMove, PlayTimers.GetKifuMoveTimes());

                    // 受理できる性質の指し手であることは検証済み
                    // special moveであってもDoMove()してしまう。
                    kifuManager.DoMove(bestMove);

                    // -- 音声の読み上げ

                    var soundManager = TheApp.app.soundManager;

                    var kif = kifuManager.KifuList[kifuManager.KifuList.Count - 1];
                    // special moveはMoveを直接渡して再生。
                    if (bestMove.IsSpecial())
                    {
                        soundManager.ReadOut(bestMove);
                    }
                    else
                    {
                        // -- 駒音

                        if (TheApp.app.config.PieceSoundInTheGame != 0)
                        {
                            // 移動先の升の下に別の駒があるときは、駒がぶつかる音になる。
                            var to    = bestMove.To();
                            var delta = stm == Color.BLACK ? Square.SQ_D : Square.SQ_U;
                            var to2   = to + (int)delta;
                            // to2が盤外であることがあるので、IsOk()を通すこと。
                            var e = (to2.IsOk() && Position.PieceOn(to2) != Piece.NO_PIECE)
                                ? SoundEnum.KOMA_B1 /*ぶつかる音*/: SoundEnum.KOMA_S1 /*ぶつからない音*/;

#if false
                            // あまりいい効果音作れなかったのでコメントアウトしとく。
                            if (TheApp.app.config.CrashPieceSoundInTheGame != 0)
                            {
                                // ただし、captureか捕獲する指し手であるなら、衝撃音に変更する。
                                if (Position.State().capturedPiece != Piece.NO_PIECE || Position.InCheck())
                                {
                                    e = SoundEnum.KOMA_C1;
                                }
                            }
#endif
                            soundManager.PlayPieceSound(e);
                        }

                        // -- 棋譜の読み上げ

                        // 「先手」と「後手」と読み上げる。
                        if (!sengo_read_out[(int)stm] || config.ReadOutSenteGoteEverytime != 0)
                        {
                            sengo_read_out[(int)stm] = true;

                            // 駒落ちの時は、「上手(うわて)」と「下手(したて)」
                            if (!Position.Handicapped)
                            {
                                soundManager.ReadOut(stm == Color.BLACK ? SoundEnum.Sente : SoundEnum.Gote);
                            }
                            else
                            {
                                soundManager.ReadOut(stm == Color.BLACK ? SoundEnum.Shitate : SoundEnum.Uwate);
                            }
                        }

                        // 棋譜文字列をそのまま頑張って読み上げる。
                        soundManager.ReadOut(kif);
                    }
                }

                // -- 次のPlayerに、自分のturnであることを通知してやる。

                if (!specialMove)
                {
                    NotifyTurnChanged();
                }
                else
                {
                    // 特殊な指し手だったので、これにてゲーム終了
                    GameEnd();
                }
            }

            return;

ILLEGAL_MOVE:

            // これ、棋譜に記録すべき
            Move m = Move.ILLEGAL_MOVE;
            kifuManager.Tree.AddNode(m, PlayTimers.GetKifuMoveTimes());
            kifuManager.Tree.AddNodeComment(m, stmPlayer.BestMove.ToUsi() /* String あとでなおす*/ /* 元のテキスト */);
            kifuManager.Tree.DoMove(m);

            GameEnd(); // これにてゲーム終了。
        }
Exemplo n.º 6
0
        /// <summary>
        /// 対局開始のためにGameSettingの設定に従い、ゲームを初期化する。
        /// </summary>
        /// <param name="gameSetting"></param>
        private void GameStart(GameSetting gameSetting)
        {
            // 音声:「よろしくお願いします。」
            TheApp.app.soundManager.Stop(); // 再生中の読み上げをすべて停止
            TheApp.app.soundManager.ReadOut(SoundEnum.Start);

            // 初期化中である。
            Initializing = true;

            // 初回の指し手で、「先手」「後手」と読み上げるためのフラグ
            sengo_read_out = new bool[2] {
                false, false
            };

            // プレイヤーの生成
            foreach (var c in All.Colors())
            {
                var playerType = gameSetting.Player(c).IsHuman ? PlayerTypeEnum.Human : PlayerTypeEnum.UsiEngine;
                Players[(int)c] = PlayerBuilder.Create(playerType);
            }

            // 局面の設定
            kifuManager.EnableKifuList = true;
            if (gameSetting.Board.BoardTypeCurrent)
            {
                // 現在の局面からなので、いま以降の局面を削除する。
                // ただし、いまの局面と棋譜ウィンドウとが同期しているとは限らない。
                // まず現在局面以降の棋譜を削除しなくてはならない。

                // 元nodeが、special moveであるなら、それを削除しておく。
                if (kifuManager.Tree.IsSpecialNode())
                {
                    kifuManager.Tree.UndoMove();
                }

                kifuManager.Tree.ClearForward();

                // 分岐棋譜かも知れないので、現在のものを本譜の手順にする。
                kifuManager.Tree.MakeCurrentNodeMainBranch();
            }
            else // if (gameSetting.Board.BordTypeEnable)
            {
                kifuManager.Init();
                kifuManager.InitBoard(gameSetting.Board.BoardType);
            }

            // 本譜の手順に変更したので現在局面と棋譜ウィンドウのカーソルとを同期させておく。
            UpdateKifuSelectedIndex();

            // 現在の時間設定を、KifuManager.Treeに反映させておく(棋譜保存時にこれが書き出される)
            kifuManager.Tree.KifuTimeSettings = gameSetting.KifuTimeSettings;

            // 対局者氏名の設定
            // 人間の時のみ有効。エンジンの時は、エンジン設定などから取得することにする。(TODO:あとで考える)
            foreach (var c in All.Colors())
            {
                var    player = Player(c);
                string name;
                switch (player.PlayerType)
                {
                case PlayerTypeEnum.Human:
                    name = gameSetting.Player(c).PlayerName;
                    break;

                default:
                    name = c.Pretty();
                    break;
                }

                kifuManager.KifuHeader.SetPlayerName(c, name);
            }

            // 持ち時間などの設定が必要なので、コピーしておく。
            GameSetting = gameSetting;

            // 消費時間計算用
            foreach (var c in All.Colors())
            {
                var pc = PlayTimer(c);
                pc.KifuTimeSetting = GameSetting.KifuTimeSettings.Player(c);
                pc.GameStart();
            }

            // rootの持ち時間設定をここに反映させておかないと待ったでrootまで持ち時間が戻せない。
            // 途中の局面からだとここではなく、現局面のところに書き出す必要がある。
            kifuManager.Tree.SetKifuMoveTimes(PlayTimers.GetKifuMoveTimes());

            // コンピュータ vs 人間である場合、人間側を手前にしてやる。
            foreach (var c in All.Colors())
            {
                if (gameSetting.Player(c).IsHuman&& gameSetting.Player(c.Not()).IsCpu)
                {
                    BoardReverse = (c == Color.WHITE);
                }
            }

            // 盤面編集中である可能性がある。リセットする。
            TheApp.app.config.InTheBoardEdit = false;

            InTheGame = true;
        }
Exemplo n.º 7
0
        /// <summary>
        /// GameStart()とGameRestart()の共通部分
        /// </summary>
        private void GameStartInCommon(GameModeEnum nextGameMode)
        {
            var gameSetting = GameSetting;

            // 現在の時間設定を、KifuManager.Treeに反映させておく(棋譜保存時にこれが書き出される)
            kifuManager.Tree.KifuTimeSettings = gameSetting.KifuTimeSettings;

            // 対局者氏名の設定
            // 人間の時のみ有効。エンジンの時は、エンジン設定などから取得することにする。
            foreach (var c in All.Colors())
            {
                var    player = Player(c);
                string name;
                switch (player.PlayerType)
                {
                case PlayerTypeEnum.Human:
                    name = gameSetting.PlayerSetting(c).PlayerName;
                    break;

                default:
                    name = c.Pretty();
                    break;
                }

                kifuManager.KifuHeader.SetPlayerName(c, name);
            }

            // 消費時間計算用
            foreach (var c in All.Colors())
            {
                var pc = PlayTimer(c);
                pc.KifuTimeSetting = GameSetting.KifuTimeSettings.Player(c);
                pc.GameStart();
                timeSettingStrings[(int)c] = pc.KifuTimeSetting.ToShortString();
            }

            // rootの持ち時間設定をここに反映させておかないと待ったでrootまで持ち時間が戻せない。
            // 途中の局面からだとここではなく、現局面のところに書き出す必要がある。
            kifuManager.Tree.SetKifuMoveTimes(PlayTimers.GetKifuMoveTimes());

            // コンピュータ vs 人間である場合、人間側を手前にしてやる。
            // 人間 vs 人間の場合も最初の手番側を手前にしてやる。
            var stm = kifuManager.Position.sideToMove;

            // 1. 手番側が人間である場合(非手番側が人間 or CPU)
            if (gameSetting.PlayerSetting(stm).IsHuman)
            {
                BoardReverse = (stm == Color.WHITE);
            }
            // 2. 手番側がCPUで、非手番側が人間である場合。
            else if (gameSetting.PlayerSetting(stm).IsCpu&& gameSetting.PlayerSetting(stm.Not()).IsHuman)
            {
                BoardReverse = (stm == Color.BLACK);
            }

            // プレイヤー情報などを検討ダイアログに反映させる。
            InitEngineConsiderationInfo(nextGameMode);

            // 検討モードならそれを停止させる必要があるが、それはGameModeのsetterがやってくれる。
            GameMode = nextGameMode;
        }