Пример #1
0
        public Node(Move m)
        {
            Pos = new Move(m);
            Winrate = 0;
//            Wins = 0;
//            Simulations = 0;
        }
Пример #2
0
 public Move GetMove()
 {
     Board cloneBoard = b.Clone();
     while (true)
     {
         Console.WriteLine("Enter row and column for move coordinates, split by space");
         string moveCoordsString = Console.ReadLine();
         if (String.IsNullOrWhiteSpace(moveCoordsString) == true)
             continue;
         string[] coords = moveCoordsString.Split(' ');
         if (coords.Length != 2)
             continue;
         int row;
         int column;
         if (int.TryParse(coords[0], out row) == true)
         {
             if (int.TryParse(coords[1], out column) == true)
             {
                 Move result = new Move(row, column);
                 if (cloneBoard.PlaceStone(result) == true)
                     return result;
             }
         }
     }
 }
Пример #3
0
 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;
 }
Пример #4
0
 private int PlayRandomGame(UCTNode node)
 {
     _boardClone.CopyStateFrom(node.BoardState);
     int turnsSimulated = 0;
     while (turnsSimulated < GameParameters.GameDepth && _boardClone.IsGameOver() == false)
     {
         turnsSimulated++;
         Move m = new Move(-5, -5);
         do
         {
             m.row = RandomGen.Next(-1, GameParameters.BoardSize);
             m.column = RandomGen.Next(-1, GameParameters.BoardSize);
         } while (_boardClone.PlaceStone(m) == false);
     }
     int winner = _boardClone.DetermineWinner();
     return winner;
 }
Пример #5
0
 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;
 }
Пример #6
0
 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;
 }
Пример #7
0
 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;
 }
Пример #8
0
 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;
 }
Пример #9
0
 public bool IsOnBoard(Move m)
 {
     return m.row >= 0 & m.row < Size && m.column >= 0 && m.column < Size;
 }
Пример #10
0
 public int IsEye(Move move) //false eyes fixed
 {
     return IsEye(move.row, move.column);
 }
Пример #11
0
 int RemoveDragon(Move m)
 {
     return RemoveDragon(m.row, m.column);
 }
Пример #12
0
 public bool IsFree(Move m)
 {
     return IsOnBoard(m) && _board[m.row, m.column] == 0;
 }
Пример #13
0
 public bool ReceiveTurn(Move m)
 {
     return _actualBoard.PlaceStone(m);
 }
Пример #14
0
        public Move GetMove()
        {
            DateTime start = DateTime.Now;
            int turnCount = GetAvailableMoves(_actualBoard);
            //most simple logic for the first couple of turns
            //reduces required computations and forbids AI from making stupid turns (should not do them anyway)
            turnCount = ApplyHeuristics(_actualBoard, turnCount);
            Node[] nodes = new Node[turnCount];
            for (int i = 0; i < turnCount; i++)
                nodes[i] = new Node(_availableMoves[i]);
            Parallel.For(0, turnCount, (i) =>
            {
                if (_availableMoves == null)
                    _availableMoves = new Move[Size*Size + 1];
                nodes[i].Winrate = GetWinrate(nodes[i].Pos);
            });
//            for (int i = 0; i < turnCount; i++)
//            {
//                if (_availableMoves == null)
//                    _availableMoves = new Move[Size * Size + 1];
//                nodes[i].Winrate = GetWinrate(nodes[i].Pos, b);
//            }
            double maxWin = -1;
            int maxWinIndex = -1;
            for (int i = 0; i < turnCount; i++)
            {
                if (nodes[i].Winrate > maxWin && nodes[i].Winrate >= 0)
                {
                    maxWin = nodes[i].Winrate;
                    maxWinIndex = i;
                }
            }
            DateTime end = DateTime.Now;
            TimeSpan ts = end - start;
            Move bestMove;
            if (maxWin < 0)
            {
                bestMove = new Move(-1, -1);
            }
            else
            {
                bestMove = nodes[maxWinIndex].Pos;
            }
            Console.WriteLine("StupidTurbo-{1} has found move {2}({3},{4}) in {0} after {5} total sims", ts, _actualBoard.ActivePlayer == 1 ? "Black" : "White", _actualBoard.TurnNumber, bestMove.row, bestMove.column, GameParameters.RandomSimulations*turnCount);
            return bestMove;
        }
Пример #15
0
 public bool ReceiveTurn(Move m)
 {
     if (Root.Children != null)
     {
         foreach (UCTNode child in Root.Children)
         {
             if (child.Position.Equals(m))
             {
                 Console.WriteLine("UCTTurbo-{0} had {1} nodes, lost {2} nodes and now has {3} nodes", _player==1?"Black":"White", Root.MeasureTree(), Root.MeasureTree()-child.MeasureTree(), child.MeasureTree());
                 Root = child;
                 Root.Parent.Children = null;
                 child.Parent = null;
                 if (child.Children == null)
                     child.CreateChildren();
                 return true;
             }
         }
     }
     Board newBoard = Root.BoardState.Clone();
     if (newBoard.PlaceStone(m) == false)
         throw new ArgumentException("invalid turn");
     Console.WriteLine("UCTTurbo-{0} had {1} nodes, lost {1} nodes and now has {2} nodes", _player == 1 ? "Black" : "White", Root.MeasureTree(), 1);
     Root.Children = null; //break the link for garbage collection
     UCTNode newRoot = new UCTNode(null, new Move(m), newBoard);
     newRoot.CreateChildren();
     Root = newRoot;
     return true;
 }
Пример #16
0
 private int PlayLessRandomGame(UCTNode node)
 {
     if (_availableMoves == null)
         _availableMoves = new Move[Size*Size+1];
     _boardClone.CopyStateFrom(node.BoardState);
     int turnsSimulated = 0;
     while (turnsSimulated < GameParameters.GameDepth && _boardClone.IsGameOver() == false)
     {
         turnsSimulated++;
         int moveCount = GetAvailableMoves(_boardClone);
         _availableMoves.Shuffle(moveCount);
         Move pass = new Move(-1, -1); //add pass to possible moves
         _availableMoves[moveCount++] = pass;
         for (int i = 0; i < moveCount; i++)
         {
             if (_boardClone.PlaceStone(_availableMoves[i]) == true)
             {
                 break;
             }
         }
     }
     int winner = _boardClone.DetermineWinner();
     return winner;
 }
Пример #17
0
 public bool ReceiveTurn(Move m)
 {
     return(_actualBoard.PlaceStone(m));
 }
Пример #18
0
 public void CreateChildren()
 {
     lock (this)
     {
         int size = Board.Size;
         Board b = BoardState;
         if (Children != null)
             return;
         if (Parent == null || Parent.Children == null)
         {
             Children = new List<UCTNode>(size*size);
         }
         else
         {
             Children = new List<UCTNode>(Parent.Children.Count);
         }
         for (int i = 0; i < size; i++)
         {
             for (int j = 0; j < size; j++)
             {
                 //is on empty space on the board
                 if (b[i, j] == 0 && b.IsEye(i, j) != b.ActivePlayer)
                 {
                     Board anotherCloneBoard = b.Clone();
                     Move m = new Move(i, j);
                     if (anotherCloneBoard.PlaceStone(m) == true)
                         Children.Add(new UCTNode(this, m, anotherCloneBoard));
                 }
             }
         }
         Children.Shuffle();
         HasChildren = true;
     }
 }
Пример #19
0
 public byte this[Move m]
 {
     get { return _board[m.row, m.column]; }
     set { _board[m.row, m.column] = value; }
 }
Пример #20
0
 public Move(Move m)
 {
     row = m.row;
     column = m.column;
 }
Пример #21
0
 // generate a move, using the uct algorithm
 public Move GetMove()
 {
     Move bestMove;
     DateTime start = DateTime.Now;
     if (_resetTreeEachTurn == true) //EXPERIMENTAL, HAS NOT BEEN TESTED AND MIGHT NOT WORK
         Root = new UCTNode(null, new Move(-5, -5), Root.BoardState.Clone());
     Console.WriteLine("Starting Tree size == {0}", Root.MeasureTree());
     _doneSims = 0;
     if (Root.Children.Any(_x => _x.IsSolved == true && _x.SolvedWinner == _player))
     {
         bestMove = Root.Children.First(_x => _x.IsSolved == true && _x.SolvedWinner == _player).Position;
     }
     else
     {
         for (int i = 0; i < Environment.ProcessorCount; i++)
             new Task(ParallelSimulations).Start();
         while (_doneSims < _sims)
         {
             Thread.Sleep(100);
         }
     UCTNode n = GetBestChild(Root);
     if (n == null)
         bestMove = new Move(-1, -1);
     else bestMove = new Move(n.Position);
     }
     TimeSpan ts = DateTime.Now - start;
     Root.Children.Sort((_x, _y) => _x.Visits.CompareTo(_y.Visits));
     foreach (UCTNode child in Root.Children)
     {
         Console.WriteLine(child);
     }
     Root.Children.Shuffle();
     Console.WriteLine("Current tree size == {0}, and there are {1} solved nodes", Root.MeasureTree(), Root.CountSolvedNodes());
     Console.WriteLine("UCTTurbo-{1} has found move {2}({3},{4}) in {0} after {5} sims", ts, Root.BoardState.ActivePlayer == 1 ? "Black" : "White", Root.BoardState.TurnNumber, bestMove.row, bestMove.column, _doneSims);
     return bestMove;
 }
Пример #22
0
        public bool PlaceStone(Move move)
        {
            if (State != GameState.GameIsNotOver)
                return false;
            if (move.row == -1 && move.column == -1)
            {
                Pass();
                return true;
            }
            //check if the move is on the board
            if (IsOnBoard(move) == false)
            {
                return false;
            }
            //check if the intersection is already occupied
            if (_board[move.row, move.column] != 0)
            {
                return false;
            }
            //check if the move is forbidden because of the Ko rule
            if (IsKo(move.row, move.column))
            {
                return false;
            }
            Array.Copy(_board, _buffer, _board.Length);
            this[move] = ActivePlayer;

            //if there is an enemy dragon nearby, it won't contain newly-placed stone - have to check each one individually
            Array.Clear(_visited, 0, _visited.Length);
            bool isSuicide = true; //для более быстрого определения возможности хода. Если рядом с новым камнем есть свободное пересечение, то это точно не суицид
            for (int i = 0; i < DirectionCount; i++) //first check opponent's dragons
            {
                int testRow = move.row + CardinalDirections[i, 0];
                int testCol = move.column + CardinalDirections[i, 1];
                //если клетка находится за доской или на ней стоит союзный камень - пропускаем. проверка союзных камней будет позже
                //if an intersection is outside the board or has allied stone - skip it for now. allied checks will come later
                if (IsOnBoard(testRow, testCol) == false || _board[testRow, testCol] == ActivePlayer)
                    continue;
                else if (_board[testRow, testCol] == 0)
                    //if a neighbouring intersection is empty, then the new stone will definitely have at least 1 liberty
                {
                    isSuicide = false;
                    continue;
                }
                if (_board[testRow, testCol] == OppositePlayer)
                {
                    if (_visited[testRow, testCol] == true)
                        continue;
                    else
                    {
                        Array.Clear(_visited, 0, _visited.Length);
                        if (IsDragonDead(testRow, testCol) == true)
                        {
                            RemoveDragon(testRow, testCol);
                        }
                    }
                }
            }
            Array.Clear(_visited, 0, _visited.Length);
            //если рядом с новым камнем есть дракон, то он включает в себя и этот камень
            //if there is a nearby friendly dragon, it will contain newly-placed stone
            if (isSuicide == true && IsDragonDead(move.row, move.column) == true)
            {
                this[move] = 0;
                return false;
            }

            ActivePlayer = OppositePlayer;
            //TODO: possibly add ko checks
            Passes = 0;
            TurnNumber++;
            Array.Copy(_buffer, _lastPosition, _lastPosition.Length);
            return true;
        }
Пример #23
0
 public bool ReceiveTurn(Move m)
 {
     return b.PlaceStone(m);
 }