/// <summary> /// 対局開始のためにGameSettingの設定に従い、ゲームを初期化する。 /// </summary> /// <param name="gameSetting"></param> private void GameStart(GameSetting gameSetting) { // エンジン検討中であるなら、まずそれを停止させる。(通常検討モードに移行する) // これは、GameModeへの代入によって自動的に処理がなされる。 if (GameMode.IsConsiderationWithEngine()) { GameMode = GameModeEnum.ConsiderationWithoutEngine; } // 持ち時間などの設定が必要なので、 // GameStart()時点のGameSettingをこのクラスのpropertyとしてコピーしておく。 GameSetting = gameSetting; var nextGameMode = GameModeEnum.InTheGame; // -- 連続対局の回数をセット var misc = gameSetting.MiscSettings; // CPU同士の時のみ連続対局が有効である。 // ContinuousGameの初期化 { continuousGame.SetPlayLimit( gameSetting.PlayerSetting(Color.BLACK).IsCpu&& gameSetting.PlayerSetting(Color.WHITE).IsCpu&& misc.ContinuousGameEnable ? misc.ContinuousGame : 0 ); // 連続対局時にはプレイヤー入れ替えなどで壊す可能性があるのでClone()して保存しておく。 continuousGame.GameSetting = gameSetting.Clone(); // 対局開始時の振り駒のアニメーションのため、こちらにコピーして使う。 continuousGame.EnablePieceToss = gameSetting.MiscSettings.EnablePieceToss; // 振り駒をするのかのチェック CheckPieceToss(nextGameMode); } // 以下の初期化中に駒が動かされるの気持ち悪いのでユーザー操作を禁止しておく。 CanUserMove = false; Initializing = true; var config = TheApp.app.Config; // 音声:「よろしくお願いします。」 TheApp.app.SoundManager.Stop(); // 再生中の読み上げをすべて停止 if (config.ReadOutGreeting != 0) { 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); } // Players[]の生成が終わったので、必要ならば画面に「エンジン初期化中」の画像を描画する。 UpdateEngineInitializing(); foreach (var c in All.Colors()) { // これ書くの2度目だが、まあ、しゃーない。 var gamePlayer = gameSetting.PlayerSetting(c); var playerType = gamePlayer.IsHuman ? PlayerTypeEnum.Human : PlayerTypeEnum.UsiEngine; 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(); // View側の都合により選択行が移動してしまう可能性がある。 // 連続対局が設定されているなら、現在の局面を棋譜文字列として保存しておく。 if (continuousGame.IsContinuousGameSet()) { continuousGame.Kif = kifuManager.ToString(KifuFileType.KIF); } } else // if (gameSetting.Board.BoardTypeEnable) { kifuManager.Init(); kifuManager.InitBoard(gameSetting.BoardSetting.BoardType); } // 本譜の手順に変更したので現在局面と棋譜ウィンドウのカーソルとを同期させておく。 UpdateKifuSelectedIndex(int.MaxValue /* 末尾に移動 */); // エンジンに与えるHashSize,Threadsの計算 var firstOfContinuousGame = continuousGame.PlayCount == 0; // 連続対局の初回局である if (UsiEngineHashManager.CalcHashSize(firstOfContinuousGame) != 0) { // Hash足りなくてダイアログ出した時にキャンセルボタン押されとる Disconnect(); // ゲームが終局したことを通知するために音声があったほうがよさげ。 TheApp.app.SoundManager.ReadOut(SoundEnum.End); return; } // エンジンを開始させることが確定したので実際に子プロセスとして起動する。 // 1) このタイミングにしないと、Hashが足りなくてユーザーがキャンセルする可能性があって、 // それまでにエンジンがタイムアウトになりかねない。 // 2) エンジンを起動させてから、Hashの計算をするのでは、エンジンを起動させる時間が無駄である。 foreach (var c in All.Colors()) { // これ書くの3度目だが、まあしゃーない…。 var gamePlayer = gameSetting.PlayerSetting(c); var playerType = gamePlayer.IsHuman ? PlayerTypeEnum.Human : PlayerTypeEnum.UsiEngine; if (playerType == PlayerTypeEnum.UsiEngine) { var engineDefineEx = TheApp.app.EngineDefines.Find(x => x.FolderPath == gamePlayer.EngineDefineFolderPath); var usiEnginePlayer = Players[(int)c] as UsiEnginePlayer; // これで子プロセスとして起動する。 StartEngine(usiEnginePlayer, engineDefineEx); } } // Restart処理との共通部分 GameStartInCommon(nextGameMode); // 新規対局で手番が変わった。 //NotifyTurnChanged(); // → エンジンの初期化が現時点では終わっていない。 // ゆえに、UpdateInitializing()のなかで初期化が終わったタイミングでNotifyTurnChanged()を呼ぶ。 // それまではTimeUpの処理をしてはならない。 }
/// <summary> /// プレイヤー情報を検討ダイアログにリダイレクトする設定をする。 /// </summary> private void InitEngineConsiderationInfo(GameModeEnum nextGameMode) { // CPUの数をNumberOfEngineに反映。 int num = 0; if (nextGameMode.IsConsiderationWithEngine()) { num = 1; // エンジンによる検討モードなら出力は一つ。 } else { foreach (var c in All.Colors()) { if (GameSetting.PlayerSetting(c).IsCpu) { ++num; } } } NumberOfEngine = num; // エンジン数が確定したので、検討ウィンドウにNumberOfInstanceメッセージを送信してやる。 ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.NumberOfInstance, number = NumberOfEngine, }; ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.SetGameMode, data = nextGameMode }; // 各エンジンの情報を検討ウィンドウにリダイレクトするようにハンドラを設定 num = 0; foreach (var c in All.Colors()) { if ((nextGameMode == GameModeEnum.InTheGame && GameSetting.PlayerSetting(c).IsCpu) || (nextGameMode.IsConsiderationWithEngine() && c == Color.BLACK) // // 検討用エンジンがぶら下がっていると考えられる。 ) { var num_ = num; // copy for capturing var engineName = GetEngineDefine(c).EngineDefine.DisplayName; var engineName2 = continuousGame.PresetName(c) == null ? engineName : $"{engineName} { continuousGame.PresetName(c)}"; var playerName = (nextGameMode.IsConsiderationWithEngine() || DisplayName(c) == engineName) ? // 検討時には、エンジンの名前をそのまま表示。 engineName2 : // 通常対局モードなら対局者名に括弧でエンジン名を表記。 $"{DisplayName(c)}({engineName2})"; ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.SetEngineName, number = num_, // is captured data = playerName, }; // UsiEngineのThinkReportプロパティを捕捉して、それを転送してやるためのハンドラをセットしておく。 var engine_player = Player(c) as UsiEnginePlayer; engine_player.Engine.AddPropertyChangedHandler("ThinkReport", (args) => { //// 1) 読み筋の抑制条件その1 //// 人間対CPUで、メニューの「ウィンドウ」のところで表示するになっていない場合。 //var surpress1 = NumberOfEngine == 1 && !TheApp.app.config.EngineConsiderationWindowEnableWhenVsHuman; if (ThinkReportEnable /* && !(surpress1) */) { var report = args.value as UsiThinkReport; // このクラスのpropertyのsetterを呼び出してメッセージを移譲してやる。 ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.UsiThinkReport, number = num_, // is captrued data = report, }; } }); num++; } } }
/// <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 InitEngineConsiderationInfo(GameModeEnum nextGameMode) { // CPUの数をNumberOfEngineに反映。 int num = 0; foreach (var c in All.Colors()) { if (GameSetting.Player(c).IsCpu) { ++num; } } NumberOfEngine = num; // エンジン数が確定したので、検討ウィンドウにNumberOfInstanceメッセージを送信してやる。 ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.NumberOfInstance, number = NumberOfEngine, }; ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.SetGameMode, data = nextGameMode }; // 各エンジンの情報を検討ウィンドウにリダイレクトするようにハンドラを設定 num = 0; foreach (var c in All.Colors()) { if (GameSetting.Player(c).IsCpu) { var num_ = num; // copy for capturing // 検討モードなら、名前は.. var name = (nextGameMode == GameModeEnum.ConsiderationWithEngine) ? "検討用エンジン" : (nextGameMode == GameModeEnum.ConsiderationWithMateEngine) ? "詰将棋エンジン" : DisplayName(c); ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.SetEngineName, number = num_, // is captured data = name, }; // UsiEngineのThinkReportプロパティを捕捉して、それを転送してやるためのハンドラをセットしておく。 var engine_player = Player(c) as UsiEnginePlayer; engine_player.engine.AddPropertyChangedHandler("ThinkReport", (args) => { //// 1) 読み筋の抑制条件その1 //// 人間対CPUで、メニューの「ウィンドウ」のところで表示するになっていない場合。 //var surpress1 = NumberOfEngine == 1 && !TheApp.app.config.EngineConsiderationWindowEnableWhenVsHuman; if (ThinkReportEnable /* && !(surpress1) */) { var report = args.value as UsiThinkReport; // このクラスのpropertyのsetterを呼び出してメッセージを移譲してやる。 ThinkReport = new UsiThinkReportMessage() { type = UsiEngineReportMessageType.UsiThinkReport, number = num_, // is captrued data = report, }; } }); num++; } } }
/// <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> /// 対局開始のためにGameSettingの設定に従い、ゲームを初期化する。 /// </summary> /// <param name="gameSetting"></param> private void GameStart(GameSetting gameSetting) { // -- 連続対局の回数をセット var misc = gameSetting.MiscSettings; // CPU同士の時のみ連続対局が有効である。 ContinuousGame = gameSetting.PlayerSetting(Color.BLACK).IsCpu&& gameSetting.PlayerSetting(Color.WHITE).IsCpu&& misc.ContinuousGameEnable ? misc.ContinuousGame : 0; ContinuousGameCount = 0; // 以下の初期化中に駒が動かされるの気持ち悪いのでユーザー操作を禁止しておく。 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); } // Players[]の生成が終わったので、必要ならば画面に「エンジン初期化中」の画像を描画する。 UpdateInitializing(); foreach (var c in All.Colors()) { // これ書くの2度目だが、まあ、しゃーない。 var gamePlayer = gameSetting.PlayerSetting(c); var playerType = gamePlayer.IsHuman ? PlayerTypeEnum.Human : PlayerTypeEnum.UsiEngine; 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の計算 var firstOfContinuousGame = ContinuousGameCount == 0; // 連続対局の初回局である if (UsiEngineHashManager.CalcHashSize(firstOfContinuousGame) != 0) { // Hash足りなくてダイアログ出した時にキャンセルボタン押されとる Disconnect(); // ゲームが終局したことを通知するために音声があったほうがよさげ。 TheApp.app.SoundManager.ReadOut(SoundEnum.End); return; } // 持ち時間などの設定が必要なので、コピーしておく。 GameSetting = gameSetting; // Restart処理との共通部分 GameStartInCommon(nextGameMode); }