/// <summary> /// Acts similarly to normal alpha beta search but instead of generating new board nodes, traverses existing board node list. /// </summary> /// <param name="_node"></param> /// <param name="_depth"></param> /// <param name="_alpha"></param> /// <param name="_beta"></param> /// <param name="_searchingPlayer"></param> /// <param name="_maximizingPlayer"></param> /// <param name="_player"></param> /// <param name="_accuracyMod"></param> /// <returns></returns> static public float TraverseNodeList(BoardNode _node, int _depth, float _alpha, float _beta, int _searchingPlayer, bool _maximizingPlayer, AI _player, float _accuracyMod) { float v; if (_depth == 0 || _node.MoveCount() == 0) { if (_maximizingPlayer) { v = (float)_node.GetValue(_player); if (_accuracyMod != 0) { System.Random random = new MathNet.Numerics.Random.SystemRandomSource(); v = v + (float)random.NextDouble() * (2 * _accuracyMod) - _accuracyMod; } return(v); } else { return(AlphaBeta(_node, _depth, _alpha, _beta, _searchingPlayer, _maximizingPlayer, _player, _accuracyMod)); } } if (!_node.IsEndNode()) { if (_maximizingPlayer) { v = -Mathf.Infinity; foreach (BoardNode b in _node.GetChildren()) { v = Mathf.Max(v, TraverseNodeList(b, _depth - 1, _alpha, _beta, _searchingPlayer, false, _player, _accuracyMod)); _alpha = Mathf.Max(_alpha, v); if (_beta <= _alpha) { break; } } return(v); } else { v = 1; foreach (BoardNode b in _node.GetChildren()) { v = Mathf.Min(v, TraverseNodeList(b, _depth - 1, _alpha, _beta, _searchingPlayer, true, _player, _accuracyMod)); _beta = Mathf.Min(_beta, v); if (_beta <= _alpha) { break; } } return(v); } } else { return(AlphaBeta(_node, _depth, _alpha, _beta, _searchingPlayer, _maximizingPlayer, _player, _accuracyMod)); } }
public override bool PerformTurn(Board _currentBoard, int _aiPlayer, PlayerType otherPlayer, bool _firstTurn, out StoneMove _move, int presetFirstMove) { ADRASMoveList.Clear(); if (boardNodes == null) { boardNodes = new List <BoardNode>(); } _move = new StoneMove(); List <StoneMove> possibleMoves = FindAllValidMoves(_currentBoard, _aiPlayer, true); System.Random rnd = new System.Random(); List <StoneMove> shuffledList = possibleMoves.OrderBy(item => rnd.Next()).ToList(); if (shuffledList.Count > 0) { StoneMove selectedMove = possibleMoves[0]; float selectedMoveValue = -Mathf.Infinity; if (_firstTurn) { FFData temp; float boardVal = GetBoardRating(_currentBoard, _aiPlayer, out temp); InitBoardVal[_aiPlayer - 1] = boardVal; if (_aiPlayer == 1) { if (presetFirstMove >= 0 && presetFirstMove < possibleMoves.Count && !GameManager.DEMO) { _move = possibleMoves[presetFirstMove]; } else { _move = shuffledList.First(); } return(true); } } else { bool existingNodeFound = false; BoardNode baseNode = new BoardNode(_currentBoard, _aiPlayer); if (boardNodes.Count > 0) { for (int i = 0; i < boardNodes.Count; i++) { if (boardNodes[i].boardState == _currentBoard) { existingNodeFound = true; baseNode = boardNodes[i]; break; } } } boardNodes = new List <BoardNode>(); if (existingNodeFound && !baseNode.IsEndNode()) { boardNodes.AddRange(baseNode.GetChildren()); } else { foreach (StoneMove m in shuffledList) { Board testBoard = _currentBoard.Clone(); testBoard.ResolveMove(m); BoardNode bn = new BoardNode(testBoard, 3 - _aiPlayer, m); boardNodes.Add(bn); } } foreach (BoardNode bn in boardNodes) { bool prevStateFound = false; foreach (Board b in CheckersMain.prevStates) { if (b == bn.boardState) { prevStateFound = true; } } float moveValue = Mathf.NegativeInfinity; if (!prevStateFound) { moveValue = Search.TraverseNodeList(bn, searchDepth - 1, Mathf.NegativeInfinity, Mathf.Infinity, _aiPlayer, false, this, 0); } if (moveValue >= 1 - accuracyMod) { ADRASMoveList.Add(bn); } if (moveValue > selectedMoveValue) { selectedMove = bn.GetMoveMade(); selectedMoveValue = moveValue; } } if (otherPlayer == PlayerType.Human) { List <BoardNode> newNodeList = new List <BoardNode>(0); foreach (BoardNode bn in boardNodes) { if (!bn.IsEndNode()) { newNodeList.AddRange(bn.GetChildren()); } } boardNodes = newNodeList; } } if (selectedMoveValue > 1 - accuracyMod) { selectedMove = ADRASMoveList.OrderBy(item => rnd.Next()).First().GetMoveMade(); } _move = selectedMove; return(true); } else { FFData data; GetBoardRating(_currentBoard, _aiPlayer, out data); return(false); } }
public virtual bool PerformTurn(Board _currentBoard, int _aiPlayer, PlayerType otherPlayer, bool _firstTurn, out StoneMove _move, int _presetFirstMove) { //initialize board node list if it isn't already if (boardNodes == null) { boardNodes = new List <BoardNode>(); } //Placeholder move in case no valid moves are found _move = new StoneMove(); //Generate list of possible moves for board state List <StoneMove> possibleMoves = FindAllValidMoves(_currentBoard, _aiPlayer, true); //Shuffle the list System.Random rnd = new System.Random(); List <StoneMove> shuffledList = possibleMoves.OrderBy(item => rnd.Next()).ToList(); if (shuffledList.Count > 0) { //set selected move to first move in the list & the value to infinity, this will likely be overwritten immediately. StoneMove selectedMove = possibleMoves[0]; float selectedMoveValue = -Mathf.Infinity; //If its the first turn, run some extra processing if (_firstTurn) { FFData temp; //Find the initial board value for the player. This is used for dynamic difficulty AI's float boardVal = GetBoardRating(_currentBoard, _aiPlayer, out temp); InitBoardVal[_aiPlayer - 1] = boardVal; //If player is black, select the preset first move from the list and exit. if (_aiPlayer == 1) { if (_presetFirstMove >= 0 && _presetFirstMove < possibleMoves.Count && !GameManager.DEMO) { _move = possibleMoves[_presetFirstMove]; } else { _move = shuffledList.First(); } return(true); } } //Main body else { bool existingNodeFound = false; BoardNode baseNode = new BoardNode(_currentBoard, _aiPlayer); //If we already have a list of board nodes to use the attempt to locate the current board in the list. if (boardNodes.Count > 0) { for (int i = 0; i < boardNodes.Count; i++) { if (boardNodes[i].boardState == _currentBoard) { existingNodeFound = true; baseNode = boardNodes[i]; break; } } } //Refresh board node list boardNodes = new List <BoardNode>(); //If we found a node, add the nodes children to the board node list if (existingNodeFound && !baseNode.IsEndNode()) { boardNodes.AddRange(baseNode.GetChildren()); } //otherwise, generate a new node from this board and add that nodes children to the list else { foreach (StoneMove m in shuffledList) { Board testBoard = _currentBoard.Clone(); testBoard.ResolveMove(m); BoardNode bn = new BoardNode(testBoard, 3 - _aiPlayer, m); boardNodes.Add(bn); } } //Go through the board nodes and begin search foreach (BoardNode bn in boardNodes) { bool prevStateFound = false; foreach (Board b in CheckersMain.prevStates) { if (b == bn.boardState) { prevStateFound = true; } } float moveValue = Mathf.NegativeInfinity; if (!prevStateFound) { moveValue = Search.TraverseNodeList(bn, searchDepth - 1, Mathf.NegativeInfinity, Mathf.Infinity, _aiPlayer, false, this, 0); } if (moveValue > selectedMoveValue) { selectedMove = bn.GetMoveMade(); selectedMoveValue = moveValue; } } //If the other player is human. Then the next board state will be skipped, so next board node list has to be 2 ply away. if (otherPlayer == PlayerType.Human) { List <BoardNode> newNodeList = new List <BoardNode>(0); foreach (BoardNode bn in boardNodes) { if (!bn.IsEndNode()) { newNodeList.AddRange(bn.GetChildren()); } } boardNodes = newNodeList; } } _move = selectedMove; return(true); } else { FFData data; GetBoardRating(_currentBoard, _aiPlayer, out data); return(false); } }
static public float AlphaBeta(BoardNode _node, int _depth, float _alpha, float _beta, int _searchingPlayer, bool _maximizingPlayer, AI _player, float _accuracyMod) { float v; //If we have reach the end of the search if (_depth == 0 || _node.MoveCount() == 0) { //If we are currently on the maximising player then find the board rating and return if (_maximizingPlayer) { v = (float)_node.GetValue(_player); if (_accuracyMod != 0) { System.Random random = new MathNet.Numerics.Random.SystemRandomSource(); v = v + (float)random.NextDouble() * (2 * _accuracyMod) - _accuracyMod; } return(v); } //If we are not currently on the maximising player then jump one extra layer. else { v = 1; foreach (StoneMove m in _node.GetMoveList()) { Board testBoard = _node.boardState.Clone(); testBoard.ResolveMove(m); _node.AddChild(new BoardNode(testBoard, _searchingPlayer, m)); } foreach (BoardNode b in _node.GetChildren()) { v = Mathf.Min(v, AlphaBeta(b, _depth - 1, _alpha, _beta, _searchingPlayer, true, _player, _accuracyMod)); _beta = Mathf.Min(_beta, v); if (_beta <= _alpha) { break; } } return(v); } } if (_maximizingPlayer) { v = -Mathf.Infinity; foreach (StoneMove m in _node.GetMoveList()) { Board testBoard = _node.boardState.Clone(); testBoard.ResolveMove(m); _node.AddChild(new BoardNode(testBoard, 3 - _searchingPlayer, m)); } foreach (BoardNode b in _node.GetChildren()) { v = Mathf.Max(v, AlphaBeta(b, _depth - 1, _alpha, _beta, _searchingPlayer, false, _player, _accuracyMod)); _alpha = Mathf.Max(_alpha, v); if (_beta <= _alpha) { break; } } return(v); } else { v = +Mathf.Infinity; foreach (StoneMove m in _node.GetMoveList()) { Board testBoard = _node.boardState.Clone(); testBoard.ResolveMove(m); _node.AddChild(new BoardNode(testBoard, _searchingPlayer, m)); } foreach (BoardNode b in _node.GetChildren()) { v = Mathf.Min(v, AlphaBeta(b, _depth - 1, _alpha, _beta, _searchingPlayer, true, _player, _accuracyMod)); _beta = Mathf.Min(_beta, v); if (_beta <= _alpha) { break; } } return(v); } }