int EvaluationFunction(BoardSpace[][] currentBoard, BoardSpace color, bool isGameCompleted) { int totalDifference = 0; foreach (BoardSpace[] row in currentBoard) { foreach (BoardSpace space in row) { if (space == color) { totalDifference++; } else if (space != BoardSpace.EMPTY) { totalDifference--; } } } if (isGameCompleted) { if (totalDifference > 0) { return(currentBoard.Length * currentBoard[0].Length); } if (totalDifference < 0) { return(currentBoard.Length * currentBoard[0].Length * -1); } } return(BoardScript.GetValidMoves(currentBoard, color == BoardSpace.BLACK ? 0u : 1u).Count); }
private int negamax(BoardSpace[][] node, uint depth, int color) { //Debug.Log("negamax function start"); if (depth == maxDepth - 2) { int retVal = -1000000; List <KeyValuePair <int, int> > moves = BoardScript.GetValidMoves(node, BoardScript.GetTurnNumber() + maxDepth); foreach (KeyValuePair <int, int> n in moves) { int temp = rateMoveSelect(moves, n); if (temp > retVal) { retVal = temp; } } return(retVal); } else { int value = -100000; //go through each valid move for this board state foreach (KeyValuePair <int, int> n in BoardScript.GetValidMoves(node, BoardScript.GetTurnNumber())) { BoardSpace[][] nodeCopy = new BoardSpace[8][]; for (int x = 0; x < 8; x++) { nodeCopy[x] = new BoardSpace[8]; System.Array.Copy(node[x], nodeCopy[x], 8); } if (color == -1) { nodeCopy[n.Value][n.Key] = BoardSpace.BLACK; } else { nodeCopy[n.Value][n.Key] = BoardSpace.WHITE; } //simulate the changes each move would result in List <KeyValuePair <int, int> > simulatedChanges = BoardScript.GetPointsChangedFromMove(nodeCopy, BoardScript.GetTurnNumber() + depth, n.Key, n.Value); foreach (KeyValuePair <int, int> spot in simulatedChanges) { if (nodeCopy[spot.Value][spot.Key] == BoardSpace.BLACK) { nodeCopy[spot.Value][spot.Key] = BoardSpace.WHITE; } else { nodeCopy[spot.Value][spot.Key] = BoardSpace.BLACK; } } //recurse value = Mathf.Max(value, -1 * negamax(nodeCopy, depth + 1, -1 * color)); } return(value); } }
private float ABnegaMax(BoardSpace[][] currentBoard, int current_depth, int Max_depth, uint turn_number, float alpha, float beta) { BoardSpace enemyColor = turn_number % 2 == 0 ? BoardSpace.WHITE : BoardSpace.BLACK; BoardSpace ourColor = turn_number % 2 == 0 ? BoardSpace.BLACK : BoardSpace.WHITE; uint current_player = turn_number % 2; List <KeyValuePair <int, int> > possible_moves = BoardScript.GetValidMoves(currentBoard, turn_number); if (current_depth >= Max_depth || possible_moves.Count == 0) { return(Evaluation(currentBoard, turn_number)); } List <float> score = new List <float>(); //Debug.Log("current depth: " + current_depth + " move size: " + possible_moves.Count); foreach (KeyValuePair <int, int> move in possible_moves) { BoardSpace[][] newer_board = new BoardSpace[8][]; for (int i = 0; i < 8; ++i) { newer_board[i] = new BoardSpace[8]; for (int j = 0; j < 8; ++j) { newer_board[i][j] = currentBoard[i][j]; } } newer_board[move.Key][move.Value] = ourColor; List <KeyValuePair <int, int> > changed = BoardScript.GetPointsChangedFromMove(newer_board, turn_number, move.Value, move.Key); //Debug.Log("changed: " + string.Join(",", changed)); foreach (KeyValuePair <int, int> change in changed) { newer_board[change.Key][change.Value] = ourColor; } //add a variable that stores alpha //instead of compiling scores, compare with beta. if >=, just return //negaMax w/ alpha and beta being -beta, -<variable> float value = (-ABnegaMax(newer_board, current_depth + 1, Max_depth, turn_number + 1, -beta, -alpha)); score.Add(value); if (value >= beta) { break; } if (value >= alpha) { alpha = value; } } //Debug.Log("score: " + string.Join(",", score)); return(score.Max()); }
private KeyValuePair <float, KeyValuePair <int, int> > AlphaBetaNegamax(BoardSpace[][] curBoard, List <KeyValuePair <int, int> > availableMoves, int curDepth, float alpha, float beta, uint turnNumber) { turnNumber++; KeyValuePair <int, int> bestMove; float bestScore = int.MinValue;; KeyValuePair <float, KeyValuePair <int, int> > bestPair; List <KeyValuePair <int, int> > actions = BoardScript.GetValidMoves(curBoard, turnNumber); if (curDepth <= 0 || actions.Count == 0) { float score = betterEvaluationFunction(curBoard); //float score = bestEvaluationFunction(curBoard); // Doesn't work as I hoped :/ if (score < bestScore) { return(new KeyValuePair <float, KeyValuePair <int, int> >(bestScore, bestMove)); } else { KeyValuePair <int, int> lastAction = new KeyValuePair <int, int>(7, 7); return(new KeyValuePair <float, KeyValuePair <int, int> >(score, lastAction)); } } foreach (KeyValuePair <int, int> action in actions) { BoardSpace[][] successor = updateBoard(curBoard, action, turnNumber); KeyValuePair <float, KeyValuePair <int, int> > currentMove = AlphaBetaNegamax(successor, availableMoves, curDepth - 1, -beta, -alpha, turnNumber); float value = currentMove.Key; float currentScore = -value; if (currentScore >= bestScore) { bestScore = currentScore; bestMove = action; } if (alpha < currentScore) { alpha = currentScore; } if (alpha >= beta) { break; } } bestPair = new KeyValuePair <float, KeyValuePair <int, int> >(bestScore, bestMove); return(bestPair); }
public int Negamax(BoardSpace[][] board, int depth, bool isBlack) { //Generate List of possible moves List <KeyValuePair <int, int> > possibleMoves = BoardScript.GetValidMoves(board, isBlack ? ((uint)2) : ((uint)1)); //If hit end, bubble up if (depth <= 0 || possibleMoves.Count == 0) { if (BoardScript.betterSEF) { return(BetterSEF(board)); } else { return(UniformSEF(board)); } } if (isBlack) { int maxScore = -9999; foreach (KeyValuePair <int, int> move in possibleMoves) { BoardSpace[][] newBoard = createNewBoard(board, move, isBlack); int currentScore = Negamax(newBoard, depth - 1, false); if (currentScore > maxScore) { maxScore = currentScore; } } return(maxScore); } else { int minScore = 9999; foreach (KeyValuePair <int, int> move in possibleMoves) { BoardSpace[][] newBoard = createNewBoard(board, move, isBlack); int currentScore = Negamax(newBoard, depth - 1, true); if (currentScore < minScore) { minScore = currentScore; } } return(minScore); } }
public float MaxValue(BoardSpace[][] curBoard, int curDepth, float alpha, float beta, uint turnNumber) { float value = Mathf.NegativeInfinity; List <KeyValuePair <int, int> > actions = BoardScript.GetValidMoves(curBoard, turnNumber); foreach (KeyValuePair <int, int> action in actions) { BoardSpace[][] successor = updateBoard(curBoard, action, turnNumber); float newActionScore = Value(successor, (curDepth - 1), alpha, beta, turnNumber++); value = Mathf.Max(value, newActionScore); alpha = Mathf.Max(alpha, value); if (alpha >= beta) { break; } } return(value); }
/************************************************* AlphaBeta Minimax implementation /*************************************************/ public float Value(BoardSpace[][] curBoard, int curDepth, float alpha, float beta, uint turnNumber) { turnNumber++; List <KeyValuePair <int, int> > actions = BoardScript.GetValidMoves(curBoard, turnNumber); if (curDepth <= 0 || actions.Count == 0) { return(betterEvaluationFunction(curBoard)); } if (turnNumber % 2 == 0) { return(MaxValue(curBoard, curDepth, alpha, beta, turnNumber)); } else { return(MinValue(curBoard, curDepth, alpha, beta, turnNumber)); } }
private int negamax(BoardSpace[][] node, uint depth, int color) { if (depth == maxDepth /* || node.Count == 1*/) { //return SEF(node) return(1); } else { int value = -100000; //go through each valid move for this board state foreach (KeyValuePair <int, int> n in BoardScript.GetValidMoves(node, BoardScript.GetTurnNumber())) { BoardSpace[][] nodeCopy = (BoardSpace[][])node.Clone(); if (color == 1) { nodeCopy[n.Key][n.Value] = BoardSpace.BLACK; } else { nodeCopy[n.Key][n.Value] = BoardSpace.WHITE; } //simulate the changes each move would result in List <KeyValuePair <int, int> > simulatedChanges = BoardScript.GetPointsChangedFromMove(nodeCopy, BoardScript.GetTurnNumber() + depth, n.Key, n.Value); foreach (KeyValuePair <int, int> spot in simulatedChanges) { if (nodeCopy[spot.Key][spot.Value] == BoardSpace.BLACK) { nodeCopy[spot.Key][spot.Value] = BoardSpace.WHITE; } else { nodeCopy[spot.Key][spot.Value] = BoardSpace.BLACK; } } //recurse value = Mathf.Max(value, -1 * negamax(nodeCopy, depth + 1, -1 * color)); } return(value); } }
BoardSpace[][][] GetChildrenNodes(BoardSpace[][] node, BoardSpace color) // find all the nodes that are children of this one { List <KeyValuePair <int, int> > validMoves = BoardScript.GetValidMoves(node, color == BoardSpace.BLACK ? 0u : 1u); BoardSpace[][][] childrenNodes = new BoardSpace[validMoves.Count][][]; for (int i = 0; i < validMoves.Count; ++i) { childrenNodes[i] = CopyBoard(node); childrenNodes[i][validMoves[i].Key][validMoves[i].Value] = color; List <KeyValuePair <int, int> > changedSpaces = BoardScript.GetPointsChangedFromMove(childrenNodes[i], color == BoardSpace.BLACK ? 0u : 1u, validMoves[i].Value, validMoves[i].Key); foreach (KeyValuePair <int, int> changed in changedSpaces) { childrenNodes[i][changed.Key][changed.Value] = color; } } return(childrenNodes); }
private int[] HMinimizeOpponentsMoves(List <KeyValuePair <int, int> > availableMoves) { List <Vector2> enemyMoves = new List <Vector2>(); int[] retval = new int[availableMoves.Count]; for (int i = 0; i < availableMoves.Count; i++) { KeyValuePair <int, int> temp = availableMoves[i]; int tempKey = temp.Key; int tempValue = temp.Value; BoardSpace[][] tempBoard = board; //Debug.Log(BoardScript.GetTurnNumber()); tempBoard[tempKey][tempValue] = getColor(BoardScript.GetTurnNumber()); enemyMoves.Add(new Vector2(i, BoardScript.GetValidMoves(tempBoard, BoardScript.GetTurnNumber() + 1).Count)); retval[i] = enemyMoves.Count; //Debug.Log(enemyMoves[i].x + " " + enemyMoves[i].y); tempBoard[tempKey][tempValue] = BoardSpace.EMPTY; } return(retval); }
//determines if theres no more valid possible moves for either player bool IsGameCompleted(BoardSpace[][] node) { return(BoardScript.GetValidMoves(node, 0).Count == 0 && BoardScript.GetValidMoves(node, 1).Count == 0); }
private int negamaxAB(BoardSpace[][] node, uint depth, int alpha, int beta, int color) { //Debug.Log("negamax function start"); if (depth == maxDepth - 2) { int retVal = -1000000; List <KeyValuePair <int, int> > moves = BoardScript.GetValidMoves(node, BoardScript.GetTurnNumber() + depth); foreach (KeyValuePair <int, int> n in moves) { int temp = -1000; if (ai == 1) { temp = rateMoveSelect(moves, n); } else if (ai == 3) { temp = NaiveRateMoveSelect(moves, n); } if (temp > retVal) { retVal = temp; } } return(retVal); } else { int value = -100000; //go through each valid move for this board state List <KeyValuePair <int, int> > possibleMoves = BoardScript.GetValidMoves(node, BoardScript.GetTurnNumber() + depth); foreach (KeyValuePair <int, int> n in possibleMoves) { BoardSpace[][] nodeCopy = new BoardSpace[8][]; for (int x = 0; x < 8; x++) { nodeCopy[x] = new BoardSpace[8]; System.Array.Copy(node[x], nodeCopy[x], 8); } if (color == -1) { nodeCopy[n.Value][n.Key] = BoardSpace.BLACK; } else { nodeCopy[n.Value][n.Key] = BoardSpace.WHITE; } //simulate the changes each move would result in List <KeyValuePair <int, int> > simulatedChanges = BoardScript.GetPointsChangedFromMove(nodeCopy, BoardScript.GetTurnNumber() + depth, n.Key, n.Value); foreach (KeyValuePair <int, int> spot in simulatedChanges) { if (nodeCopy[spot.Value][spot.Key] == BoardSpace.BLACK) { nodeCopy[spot.Value][spot.Key] = BoardSpace.WHITE; } else { nodeCopy[spot.Value][spot.Key] = BoardSpace.BLACK; } } //recurse int temp = -1 * negamaxAB(nodeCopy, depth + 1, -1 * alpha, -1 * beta, -1 * color); //value = Mathf.Max(value, -1 * negamaxAB(nodeCopy, depth + 1, -1 * alpha, -1 * beta, -1 * color)); if (Mathf.Abs(temp - value) <= 30) { if (Random.value < .5) { value = temp; } } else if (temp >= value) { value = temp; } int a = alpha; a = Mathf.Max(a, value); if (a >= beta) { break; } } return(value); } }