/// <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; }
/// <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); // これにてゲーム終了。 }
/// <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; }
/// <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; }
/// <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(); // これにてゲーム終了。 }
/// <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; }
/// <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; }