void GameResult(GameResultData g) { StartCoroutine(Coroutines.Lerp(0, 1, appearLength, (position) => { transform.localScale = Vector3.one * position; })); g.resultObject.SetActive(true); g.resultObject.GetComponentInChildren <TextMeshProUGUI>().text = g.response[_random.Next(0, g.response.Length - 1)]; }
public async Task EndTurn() { lastMoveHighlight.Show(movesHistory.Actions.Last()); DisplayEngineTurn = false; UpdateFEN(); GameResultData resultData = gameState.GetResult(); if (resultData.Result == GameResult.Ongoing) { await StartTurn(); } else if (resultData.Result == GameResult.Win) { string color = resultData.Winner == 0 ? "White" : "Black"; MessageBox.Show($"{color} won by checkmate!"); GameEnded = true; } else { if (resultData.Reason == GameResultReason.Stalemate) { MessageBox.Show($"Draw by stalemate"); GameEnded = true; } else if (!ignoreDraw) { string drawMessage; if (resultData.Reason == GameResultReason.ThreefoldRepetition) { drawMessage = "Draw by threefold repetition"; } else { drawMessage = "Draw by 50-move rule"; } MessageBoxResult result = MessageBox.Show($"{drawMessage}.\nDo you wish to continue?", "Draw", MessageBoxButton.YesNo); if (result == MessageBoxResult.No) { GameEnded = true; } else { ignoreDraw = true; await StartTurn(); } } else { await StartTurn(); } } }
/// <summary> /// 棋譜の自動保存処理 /// </summary> private void AutomaticSaveKifu(Move lastMove) { try { var lastColor = Position.sideToMove; // 1) 勝敗のカウンターを加算 // (これは棋譜の自動保存が無効であってもなされなくてはならない) continuousGame.IncResult(lastMove, lastColor); // この対局棋譜を保存しなければならないなら保存する。 var setting = TheApp.app.Config.GameResultSetting; if (!setting.AutomaticSaveKifu) { return; } // 2) 棋譜ファイルを保存する。 // プレイヤー名を棋譜上に反映させる。 // → これは、DisplayName()と同等であればすでに設定されている。 var kifu = kifuManager.ToString(setting.KifuFileType); var filename = $"{continuousGame.GetKifuSubfolder()}{DefaultKifuFileName()}{setting.KifuFileType.ToExtensions()}"; var filePath = Path.Combine(setting.KifuSaveFolder, filename); FileIO.WriteFile(filePath, kifu); // 3) csvファイルに情報をappendする。 var table = new GameResultTable(); var csv_path = setting.CsvFilePath(); var handicapped = Position.Handicapped; var timeSettingStrings = !handicapped ? $"先手:{TimeSettingString(Color.BLACK)},後手:{TimeSettingString(Color.WHITE)}" : $"下手:{TimeSettingString(Color.BLACK)},上手:{TimeSettingString(Color.WHITE)}"; var result = new GameResultData() { PlayerNames = new[] { DisplayNameWithPreset(Color.BLACK), DisplayNameWithPreset(Color.WHITE) }, StartTime = continuousGame.StartTime, EndTime = continuousGame.EndTime, KifuFileName = filename, LastMove = lastMove, LastColor = lastColor, GamePly = Position.gamePly - 1 /* 31手目で詰まされている場合、棋譜の手数としては30手であるため。 */, BoardType = kifuManager.Tree.rootBoardType, TimeSettingString = timeSettingStrings, Handicapped = handicapped, Comment = null, }; table.AppendLine(csv_path, result); // 連続対局の最終局であるなら、連続対局のトータルの結果を出力する。 if (continuousGame.IsLastGame()) { // これが連続対局の最終局であったのなら、結果を書き出す。 result = new GameResultData() { Comment = continuousGame.GetGameResultString() }; table.AppendLine(csv_path, result); } } catch (Exception ex) { // ファイルの書き出しに失敗などで例外が出て落ちるのはちょっと格好が悪いので捕捉しておく。 TheApp.app.MessageShow(ex, false); } }
public int Evaluate(int depth, GameStage gameStage, int engineColor) { GameResultData resultData = gameState.GetResult(); if (resultData.Result != GameResult.Ongoing) { if (resultData.Result == GameResult.Win) { return(-CHECKMATE_SCORE - depth); } else { return(GetDrawScore(engineColor)); } } int score = 0; ulong[,] pieceAttacks = new ulong[2, 5]; ulong[] kingAttacks = new ulong[2]; int[] kingAttacksScore = new int[2]; ulong[] kingSurrounding = new ulong[2]; int[] kingFile = { BitboardUtils.GetFile(BitboardUtils.BitScanForward(gameState.Pieces[0, (int)PieceType.King])), BitboardUtils.GetFile(BitboardUtils.BitScanForward(gameState.Pieces[1, (int)PieceType.King])) }; double[] kingAttackModifier = CalculateKingAttackModifier(kingFile); int[] material = new int[2]; for (int pl = 0; pl <= 1; pl++) { if (gameStage != GameStage.Endgame) { //rooks connected int rooksConnectedScore = EvaluateRooksConnected(pl); score += rooksConnectedScore; //king safety score += EvaluateKingFile(pl, kingFile[pl], rooksConnectedScore); int startFile = Math.Min(5, Math.Max(0, kingFile[pl] - 1)); int pawnProtectorsMoves = 0; for (int f = startFile; f <= startFile + 2; f++) { ulong fileMask = BitboardUtils.GetFileMask(f); //moved king pawns penalty pawnProtectorsMoves += GetPawnMovesOfFile(pl, f, kingFile[pl]); //pawn storm ulong enemyPawnsOnFile = fileMask & gameState.Pieces[1 - pl, (int)PieceType.Pawn]; score += EvaluatePawnStorm(1 - pl, enemyPawnsOnFile, kingAttackModifier[1 - pl]); //king open files penalty score += EvaluateOpenKingFile(pl, enemyPawnsOnFile, kingAttackModifier[1 - pl]); } score += EvaluateKingPawnMoves(pl, pawnProtectorsMoves, kingAttackModifier[1 - pl]); } //pawn structure score += EvaluatePawnStructure(pl); ulong opKing = gameState.Pieces[1 - pl, (int)PieceType.King]; int file = BitboardUtils.GetFile(BitboardUtils.BitScanForward(opKing)); kingSurrounding[1 - pl] = opKing | gameState.MoveGenerators[(int)PieceType.King].GenerateAttacks(1 - pl); ulong opKingQuarter = GetKingQuarter(1 - pl, file); for (int i = 0; i < 5; i++) { PieceType pieceType = (PieceType)i; //material score += EvaluateMaterial(pl, pieceType, material); if (pieceType != PieceType.Pawn) { ulong piece = gameState.Pieces[pl, i]; while (piece > 0) { int pieceSq = BitboardUtils.PopLSB(ref piece); ulong attacks = gameState.MoveGenerators[i].GenerateAttacksFromSquare(pieceSq); //mobility score += EvaluateMobility(pl, pieceType, attacks, gameStage); //center control score += EvaluatePieceCenterControl(pl, pieceType, attacks); if (pieceType == PieceType.Rook) { //rook on open file & 7th rank score += EvaluateRookOpenFile(pl, pieceSq); score += EvaluateRookRank(pl, pieceSq, gameStage); } else if (pieceType == PieceType.Knight) { //knight outpost score += EvaluateKnightSquare(pl, pieceSq); } if (gameStage != GameStage.Endgame) { //king attack ulong directKingAttacks = kingSurrounding[1 - pl] & attacks; ulong quarterKingAttacks = opKingQuarter & (attacks ^ directKingAttacks); kingAttacks[pl] |= directKingAttacks | quarterKingAttacks; CalculatePieceKingAttackScore(pl, pieceType, directKingAttacks, quarterKingAttacks, kingAttackModifier[pl], kingAttacksScore); pieceAttacks[pl, i] |= attacks; } } } } } if (gameStage != GameStage.Endgame) { //complete king attack analysis for (int pl = 0; pl <= 1; pl++) { for (int i = 0; i < 5; i++) { CalculatePieceKingDefenseScore(pl, (PieceType)i, pieceAttacks[pl, i], kingAttacks[1 - pl], kingSurrounding[pl], kingAttacksScore); } score += EvaluateAttackVsDefense(1 - pl, kingAttacksScore); } } else { //endgame specific parameters for (int pl = 0; pl <= 1; pl++) { //advanced king bonus score += EvaluateEndgameKingSquare(pl); //big material advantage //march king towards enemy king, and push enemy king to the corner score += EvaluateEndgameCornerMate(pl, material); //King & Pawn vs King score += EvaluateEndgameKPK(pl, material); } } return(score); }