// Only selects a random piece and position when there is no plays better than the one originally selected public static winningMove RandomPlay(winningMove winChoice) { int rand; var rnd = new Random(); List <int> playablePieces; List <int> playablePositions; if (winChoice.heuristicValue == 0) { playablePositions = AIFunctions.makePlayablePositionList(winChoice.winningNode.gameBoard); if (playablePositions.Count() == 0) { return(winChoice); } else if (playablePositions.Count() - 1 == 0) { rand = 0; } else { rand = rnd.Next(0, playablePositions.Count() - 1); } winChoice.winningNode.moveOnBoard = playablePositions[rand]; playablePieces = AIFunctions.makePlayablePiecesOnly(winChoice.winningNode.pieces); if (playablePieces.Count() == 0) { return(winChoice); } else if (playablePieces.Count() - 1 == 0) { rand = 0; } else { rand = rnd.Next(0, playablePieces.Count() - 1); } winChoice.winningNode.pieceToPlay = playablePieces[rand]; } return(winChoice); }
// Generates all the piece selections that could possibly be made for a given gamestate. public static void generateChildrenPiece(Node currentNode, Node parentNode, int maxDepth, int depth) { int pieceMapCount = 0; int childCount = 0; while (pieceMapCount < MAXGAMEBOARD) { if (currentNode.pieces[pieceMapCount].getPlayablePiece()) { totalGamestates++; Node nextNode = new Node(); for (int counter = 0; counter < MAXGAMEBOARD; counter++) { string value = currentNode.gameBoard[counter]; nextNode.gameBoard[counter] = value; } nextNode.pieceToPlay = pieceMapCount; int newMove = currentNode.moveOnBoard; nextNode.moveOnBoard = newMove; nextNode.parent = parentNode; parentNode.children[childCount] = nextNode; AIFunctions.copyPieceMap(nextNode, currentNode, pieceMapCount); childCount++; if (depth < maxDepth) { Node childNode = nextNode; Node nextParentNode = childNode; int piece = nextNode.pieceToPlay; int newDepth = depth + 1; generateChildrenGamestate(childNode, nextParentNode, piece, maxDepth, newDepth); } } pieceMapCount++; } }
// Generates all the moves that could possibly be made for a given gamestate and piece. public static void generateChildrenGamestate(Node currentNode, Node parentNode, int piece, int maxDepth, int depth) { int boardPosCount = 0; int childCount = 0; while (boardPosCount < MAXGAMEBOARD) { if (currentNode.gameBoard[boardPosCount] == null) { Node nextNode = new Node(); for (int counter = 0; counter < MAXGAMEBOARD; counter++) { string value = currentNode.gameBoard[counter]; nextNode.gameBoard[counter] = value; } nextNode.gameBoard[boardPosCount] = currentNode.pieces[piece].getPiece(); nextNode.moveOnBoard = boardPosCount; nextNode.parent = parentNode; parentNode.children[childCount] = nextNode; AIFunctions.copyPieceMap(nextNode, currentNode, piece); nextNode.pieceToPlay = NULLPIECE; childCount++; if (depth < maxDepth) { Node childNode = nextNode; Node nextParentNode = childNode; int newDepth = depth + 1; generateChildrenPiece(childNode, nextParentNode, maxDepth, newDepth); } } boardPosCount++; } }
public moveData generateTree(string[] newGameBoard, int piece, Piece[] currentPieces, int difficulty) { int piecesOnBoard; int maxDepth; int positionToBlock; bool boardBlockable = false; string moveToSend; string pieceOnDeck; Node newNode = new Node(); newNode.gameBoard = newGameBoard; newNode.pieceToPlay = piece; root = newNode; Node currentNode = root; Node parentNode; parentNode = currentNode; currentNode.pieces = currentPieces; positionToBlock = AIFunctions.findWinningPositionToBlock(newGameBoard, currentPieces[piece].piece); if (difficulty == 3 && positionToBlock != -1 && Heuristic.calculateHeuristic(newGameBoard, currentPieces[piece].piece) > 0) { boardBlockable = true; } // Sets tree depth according to how many pieces are on the board piecesOnBoard = AIFunctions.countPiecesOnBoard(newGameBoard); maxDepth = AIFunctions.setTreeDepth(piecesOnBoard, difficulty); // Generates game tree generateChildrenGamestate(currentNode, parentNode, piece, maxDepth, 0); // Finds the best move in the game tree based on a heuristic. winningMove move = NegaMax.searchForBestPlay(currentNode, maxDepth, 0, -MAXGAMEBOARD, MAXGAMEBOARD, true); if (boardBlockable && !move.isWin && piecesOnBoard != MAXGAMEBOARD - 1) { // Erases old winning move then adds new move to board. // Also sets old piece to playable again. move.winningNode.gameBoard[move.winningNode.moveOnBoard] = null; move.winningNode.gameBoard[positionToBlock] = currentPieces[piece].piece; move.winningNode.pieces[move.winningNode.pieceToPlay].setPlayable(true); move.winningNode = AIFunctions.checkForOpponentWin(move.winningNode, currentPieces[piece].piece); pieceOnDeck = move.winningNode.pieceToPlay == NULLPIECE? NULLPIECE.ToString() : move.winningNode.pieces[move.winningNode.pieceToPlay].piece; moveToSend = move.winningNode.pieces[positionToBlock].piece; } else { if (piecesOnBoard != 0 && move.winningNode.pieceToPlay != NULLPIECE) { move.winningNode = AIFunctions.checkForOpponentWin(move.winningNode, null); } moveToSend = move.winningNode.pieces[move.winningNode.moveOnBoard].piece; //Checks for win by opponent, given the piece chosen //If win it makes it equal to the next child and so on pieceOnDeck = move.winningNode.pieceToPlay == NULLPIECE? NULLPIECE.ToString() : move.winningNode.pieces[move.winningNode.pieceToPlay].piece; } return(new moveData { lastMoveOnBoard = moveToSend, pieceToPlay = pieceOnDeck }); }
public moveData generateTree(string[] newGameBoard, int piece, Piece[] currentPieces, int difficulty) { // hashing function would go here // Followed by a lookup in the transposition table //HashFunction.ZobristHash zash = new HashFunction.ZobristHash(); //zash.init_zobristHash(); totalGamestates = 0; int piecesOnBoard; int maxDepth; int positionToBlock; bool boardBlockable = false; string moveToSend; positionToBlock = AIFunctions.findWinningPositionToBlock(newGameBoard, currentPieces[piece].piece); if (difficulty == 3 && positionToBlock != -1 && Heuristic.calculateHeuristic(newGameBoard, currentPieces[piece].piece) > 0) { boardBlockable = true; } Node newNode = new Node(); newNode.gameBoard = newGameBoard; newNode.pieceToPlay = piece; root = newNode; Node currentNode = root; Node parentNode; parentNode = currentNode; currentNode.pieces = currentPieces; // Sets tree depth according to how many pieces are on the board piecesOnBoard = AIFunctions.countPiecesOnBoard(newGameBoard); maxDepth = AIFunctions.setTreeDepth(piecesOnBoard, difficulty); generateChildrenGamestate(currentNode, parentNode, piece, maxDepth, 0); winningMove move = NegaMax.searchForBestPlay(currentNode, maxDepth, 0, -MAXGAMEBOARD, MAXGAMEBOARD, true); //Checks for win by opponent, given the piece chosen //If win it makes it equal to the next child and so on if (piecesOnBoard != 0 && move.winningNode.pieceToPlay != NULLPIECE && difficulty > 1) { move.winningNode = AIFunctions.checkForOpponentWin(move.winningNode); } // This is bad but it works. string pieceOnDeck = move.winningNode.pieceToPlay == NULLPIECE? NULLPIECE.ToString() : move.winningNode.pieces[move.winningNode.pieceToPlay].piece; if (boardBlockable) { moveToSend = move.winningNode.pieces[positionToBlock].piece; } else { moveToSend = move.winningNode.pieces[move.winningNode.moveOnBoard].piece; } return(new moveData { lastMoveOnBoard = moveToSend, pieceToPlay = pieceOnDeck }); }