public UCTNode(UCTNode parent, Move m, Board boardState) { if (m == null || boardState == null) throw new ArgumentNullException("m"); BoardState = boardState.Clone(); Parent = parent; Children = null; Position = new Move(m); Wins = 0; Visits = 0; }
public void CopyStateFrom(Board b) { TurnNumber = b.TurnNumber; Passes = b.Passes; ActivePlayer = b.ActivePlayer; State = b.State; for (int i = 0; i < Size; i++) for (int j = 0; j < Size; j++) { _visited[i, j] = b._visited[i, j]; _board[i, j] = b[i, j]; _lastPosition[i, j] = b._lastPosition[i, j]; } }
int GetAvailableMoves(Board b) { if (_availableMoves == null) _availableMoves = new Move[Size*Size+1]; int moveCount = 0; for (int i = 0; i < Size; i++) { for (int j = 0; j < Size; j++) { //is on empty space on the board and not a friendly eye if (b[i, j] == 0 && b.IsEye(i, j) != b.ActivePlayer) { _availableMoves[moveCount++] = new Move(i, j); } } } return moveCount; }
public int PlaySimulation() { if (_testingBoard == null) _testingBoard = new Board(); _testingBoard.CopyStateFrom(_startingTestingBoard); int turnsSimulated = 0; while (turnsSimulated < GameParameters.GameDepth && _testingBoard.IsGameOver() == false) { turnsSimulated++; Move m = new Move(-1, -1); do { m.row= RandomGen.Next(-1, GameParameters.BoardSize); m.column = RandomGen.Next(-1, GameParameters.BoardSize); } while (_testingBoard.PlaceStone(m) == false); } int winner = _testingBoard.DetermineWinner(); return winner; }
double GetWinrate(Move move) { if (_startingTestingBoard == null) _startingTestingBoard = new Board(); _startingTestingBoard.CopyStateFrom(_actualBoard); if (_startingTestingBoard.PlaceStone(move) == false) return -1; UInt64 sim = 0; int wins = 0; while (sim < GameParameters.RandomSimulations) { int winner = PlaySimulation(); if (winner != 0) { sim++; if (winner == _actualBoard.ActivePlayer) wins++; } } return sim > 0 ? (double)wins / sim : -1; }
public int PlaySimulation() { if (_testingBoard == null) _testingBoard = new Board(); _testingBoard.CopyStateFrom(_startingTestingBoard); int turnsSimulated = 0; while (turnsSimulated < GameParameters.GameDepth && _testingBoard.IsGameOver() == false) { turnsSimulated++; int moveCount = GetAvailableMoves(_testingBoard); Move pass = new Move(-1, -1); //добавить в список возможных ходов пас _availableMoves[moveCount++] = pass; _availableMoves.Shuffle(moveCount); for (int i = 0; i < moveCount; i++) { if (_testingBoard.PlaceStone(_availableMoves[i]) == true) { break; } } } int winner = _testingBoard.DetermineWinner(); return winner; }
public Board Clone() { Board result = new Board(); result.CopyStateFrom(this); return result; }
private static int ApplyHeuristics(Board board, int turnCount) { int k = 0; int j = 0; if (board.TurnNumber < 5) { while (j < turnCount) { Move m = _availableMoves[j++]; if (m.row > 1 && m.row < 7 && m.column > 1 && m.column < 7) _availableMoves[k++] = m; } } else if (board.TurnNumber < 10) { while (j < turnCount) { Move m = _availableMoves[j++]; if (m.row > 0 && m.row < 8 && m.column > 0 && m.column < 8) _availableMoves[k++] = m; } } else k = turnCount; return k; }
private int PlaySimulation(UCTNode n) { if (_boardClone == null) _boardClone = new Board(); int randomWinner = 0; if (n.IsSolved == true) //should always be false (only for single thread! - can be true for multiple threads) { int solvedCurrentPlayerWins = n.SolvedWinner == _player ? 1 : 0; n.Update(solvedCurrentPlayerWins); //update node (Node-wins are associated with moves in the Nodes) return n.SolvedWinner; } if (n.Children == null && n.Visits < GameParameters.UCTExpansion && n.IsSolved == false) { if (_boardClone == null) _boardClone = new Board(); randomWinner = PlayMoreOrLessRandomGame(n); } else { if (n.HasChildren == false) n.CreateChildren(); UCTNode next = UCTSelect(n); // select a move if (next == null) //only happens in finished positions and solved nodes - we can start backpropagating ideal result { n.IsSolved = true; if (n.Children.Count == 0) //this is a terminal position - there can be no nodes after it { n.SolvedWinner = n.BoardState.DetermineWinner(); } else //this is a non-terminal position for which all possible subsequent moves have been checked { if (n.BoardState.ActivePlayer == _player) //if, for this node, it's this player's turn, then we take the best result { foreach (UCTNode child in n.Children) { if (child.IsSolved == false) throw new ImpossibleException("solved node's child is not solved", "PlaySimulation"); if (child.SolvedWinner == _player) //if we find a choice that leads to sure win for current player, we immediately take it { n.SolvedWinner = _player; n.Update(1); return 1; } //if we don't find a node that leads to current player's victory n.SolvedWinner = 3 - _player; n.Update(0); return 0; } } else //if it's enemy's turn on this node, then we take the worst result { foreach (UCTNode child in n.Children) { if (child.IsSolved == false) throw new ImpossibleException("solved node's child is not solved", "PlaySimulation"); if (child.SolvedWinner != _player) //if we find a choice that leads to sure win for enemy, we immediately take it { n.SolvedWinner = 3 - _player; n.Update(0); return 0; } //if we don't find a node that leads to enemy's victory, we assume that this is our winning node n.SolvedWinner = _player; n.Update(1); return 1; } } } } else { randomWinner = PlaySimulation(next); } } int currentPlayerWins = randomWinner == _player ? 1 : 0; n.Update(currentPlayerWins); //update node (Node-wins are associated with moves in the Nodes) return randomWinner; }
public static void PlayGame(IPlayer blackPlayer, IPlayer whitePlayer) { gameRecord.AppendLine("(;FF[4]GM[1]SZ[9]AP[dotNetGo]"); gameRecord.AppendLine(String.Format("PB[{0}]", blackPlayer.Name)); gameRecord.AppendLine("HA[0]"); gameRecord.AppendLine(String.Format("PW[{0}]", whitePlayer.Name)); gameRecord.AppendLine("KM[6.5]"); gameRecord.AppendLine("RU[Chinese]"); gameRecord.AppendLine(""); gameRecord.AppendLine(""); Board board = new Board(); while (board.IsGameOver() == false) { Move move; switch (board.ActivePlayer) { case 1: move = blackPlayer.GetMove(); break; default: //case 2: move = whitePlayer.GetMove(); break; } if (blackPlayer.ReceiveTurn(move) == false) throw new ImpossibleException("somehow invalid turn made it through", "PlayGame"); if (whitePlayer.ReceiveTurn(move) == false) throw new ImpossibleException("somehow invalid turn made it through", "PlayGame"); if (move.row >= 0 && move.column >= 0) gameRecord.AppendFormat(";{0}[{1}{2}]", board.ActivePlayer == 1? "B": "W", alphabet[move.column], alphabet[move.row]); if (board.PlaceStone(move) == false) throw new ImpossibleException("somehow invalid turn made it through", "PlayGame"); Console.WriteLine(board); //Console.ReadLine(); } switch (board.State) { case Board.GameState.BlackSurrendered: Console.WriteLine("White won by resignation, last position:"); break; case Board.GameState.WhiteSurrendered: Console.WriteLine("Black won by resignation, last position:"); break; case Board.GameState.DoublePass: double blackScore, whiteScore; board.DetermineWinner(out blackScore, out whiteScore); gameRecord.AppendFormat(";RE[{0}+{1}]", blackScore > whiteScore?"B":"W", Math.Abs(blackScore-whiteScore)); Console.WriteLine(board); Console.WriteLine("Turn: {0}", board.TurnNumber); Console.WriteLine("Black score: {0}; White score: {1}", blackScore, whiteScore); Console.WriteLine("last position:"); break; } Console.WriteLine(board); gameRecord.Append(")"); DateTime dt = DateTime.Now; string filename = String.Format("{0}-{1}-{2}-{3}-{4}-{5}.sgf", dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second); File.WriteAllText(filename, gameRecord.ToString(), Encoding.UTF8); }