public void PlaceDomino(DominoController domino) { if (!mFirstDominoSet) { mFirstDominoSet = true; } mPickNewDomino = true; GameOnHold = true; mBoardController.AddDomino(domino); }
/// <summary> /// Alpha Beta search for optimal move /// /// </summary> /// <param name="board"></param> /// <param name="domino"></param> /// <param name="mAlpha"></param> /// <param name="beta"></param> /// <param name="depth">depth to search - 0 is base case</param> /// <param name="maxDepth">maximize vs. minimize</param> /// <returns></returns> public int AlphaBeta(BoardController board, int alpha, int beta, int depth, bool maximizeScore, bool player1Playing, ref int optimalRow, ref int optimalCol, ref int optimalRotation, List <IDomino> myDominoes, List <IDomino> enemyDominoes, out IDomino playedDomino) { playedDomino = null; // if we're at depth zero , just return board value if (depth == 0) { #if TESTALPHABETA Debug.WriteLine("alphaBeta depth 0 Calculate Board Value"); #endif return(player1Playing ? -board.GetBoardValue() : board.GetBoardValue()); } // search bounds int minRow, maxRow, minColumn, maxColumn; //For the First Move only Domino Rotation is allowed; if (!(GamePlayManager.Instance.FirstDominoSet)) { minRow = board.StartPosition; maxRow = board.StartPosition + 1; minColumn = board.StartPosition; maxColumn = board.StartPosition + 1; } else { minRow = Math.Max(0, board.BoundingBox.RowMin - 2); maxRow = Math.Min(board.Size, board.BoundingBox.RowMax + 3); minColumn = Math.Max(0, board.BoundingBox.ColumnMin - 2); maxColumn = Math.Min(board.Size, board.BoundingBox.ColumnMax + 3); } // first time this is called, we'll use this to restore int boardRowMin = board.BoundingBox.RowMin; int boardRowMax = board.BoundingBox.RowMax; int boardColumnMin = board.BoundingBox.ColumnMin; int boardColumnMax = board.BoundingBox.ColumnMax; // counts number of follow on moves (if zero, we're at a leaf) int positionsAvailable = 0; #if TESTALPHABETA if (depth == mComputerDepth) { Debug.WriteLine("Start Main Alpha Beta : depth " + mComputerDepth); } else if (depth > 0) { Debug.WriteLine(""); Debug.WriteLine("Start recursive alpha beta depth " + depth); Debug.WriteLine("myDominoes"); foreach (IDomino idomino in myDominoes) { if (!(idomino == null)) { Debug.WriteLine(" Domino row " + idomino.Controller.Row + " Column " + idomino.Controller.Column + " label " + idomino.Controller.Label); } } Debug.WriteLine("Ennemy Dominoes"); foreach (IDomino idomino in enemyDominoes) { if (!(idomino == null)) { Debug.WriteLine(" Domino row " + idomino.Controller.Row + " Column " + idomino.Controller.Column + " label " + idomino.Controller.Label); } } if (maximizeScore) { Debug.WriteLine("Max Node " + "beta " + beta + " alpha" + alpha); } else { Debug.WriteLine("Min Node " + "beta " + beta + " alpha" + alpha); } } #endif //state of bag //Pick Random Domino in the Bag // start in a random location int dominoIndex = mRandom.Next(0, myDominoes.Count) - 1; int randomStartRow = mRandom.Next(minRow, maxRow) - 1; int randomStartColumn = mRandom.Next(minColumn, maxColumn) - 1; int randomStartRotationState = mRandom.Next(0, 4) - 1; DominoController domino; for (int index = 0; index < myDominoes.Count; index++) { dominoIndex++; if (dominoIndex == myDominoes.Count) { dominoIndex = 0; } domino = myDominoes[dominoIndex].Controller; #if TESTALPHABETA Debug.WriteLine(""); Debug.WriteLine("Check Domino Label " + domino.Label + " depth " + depth + " computer depth " + mComputerDepth); #endif domino.Row = randomStartRow; domino.Column = randomStartColumn; domino.RotationState = randomStartRotationState; // perform a grid search (row, col, rotation) for (int row = 0; row < (maxRow - minRow); row++) { domino.Row++; if (domino.Row == maxRow) { domino.Row = minRow; } for (int column = 0; column < (maxColumn - minColumn); column++) { domino.Column++; if (domino.Column == maxColumn) { domino.Column = minColumn; } for (int rotationState = 0; rotationState < 4; rotationState++) { domino.RotationState++; if (domino.RotationState == 4) { domino.RotationState = 0; } // Debug.WriteLine("Domino Index"+dominoIndex+" Label"+domino.Label+" Row "+ domino.Row+ " Column "+domino.Column+ " RotationState"+ domino.RotationState); // if we can place a domino here, then we'll // begin the recursive search if (GamePlayManager.Instance.IsLegalMove(domino)) { #if TESTALPHABETA Debug.WriteLine("AlphaBetaDepth" + depth + "(" + mComputerDepth + ")"); #endif // marks this as a possible move positionsAvailable++; #if TESTALPHABETA if (positionsAvailable == 2) { rotationState = 4; row = maxRow - minRow; column = maxColumn - minColumn; index = myDominoes.Count; } #endif // place the domino on the board board.AddDomino(domino); myDominoes.Remove(domino.Parent); if (maximizeScore) { // this is the recursive call int score = AlphaBeta(board, alpha, beta, (depth - 1), !maximizeScore, player1Playing, enemyDominoes, myDominoes); #if TESTALPHABETA Debug.WriteLine("Score" + score); #endif // prune if (score >= beta) { #if TESTALPHABETA Debug.WriteLine("mScore >= beta: End AlphaBeta with Depth" + depth); Debug.WriteLine("CUTOFF"); Debug.WriteLine(""); #endif // undoes the move on the board and bag myDominoes.Insert(dominoIndex, domino.Parent); board.PopUndo(domino); // return(beta); } if (score > alpha) { alpha = score; #if TESTALPHABETA Debug.WriteLine("New alpha " + alpha); #endif if (depth == mComputerDepth) { #if TESTALPHABETA Debug.WriteLine("New Optimal Domino: Label " + domino.Label + " Row " + domino.Row + " Column " + domino.Column + " RotationState " + domino.RotationState); #endif optimalRow = domino.Row; optimalCol = domino.Column; optimalRotation = domino.RotationState; playedDomino = domino.Parent; } } } else { // this is the recursive call int score = AlphaBeta(board, alpha, beta, (depth - 1), !maximizeScore, player1Playing, enemyDominoes, myDominoes); #if TESTALPHABETA Debug.WriteLine("Score" + score); #endif // prune if (score <= alpha) { #if TESTALPHABETA Debug.WriteLine("mScore<=alpha End AlphaBeta with Depth" + depth); Debug.WriteLine("CUTOFF"); Debug.WriteLine(""); #endif //// undoes the move on the board myDominoes.Insert(dominoIndex, domino.Parent); board.PopUndo(domino); return(alpha); } if (score < beta) { beta = score; #if TESTALPHABETA Debug.WriteLine("New beta " + beta); #endif if (depth == mComputerDepth) { optimalRow = domino.Row; optimalCol = domino.Column; optimalRotation = domino.RotationState; playedDomino = domino.Parent; } } } // restore board state myDominoes.Insert(dominoIndex, domino.Parent); board.PopUndo(domino); } } } } #if TESTALPHABETA Debug.WriteLine(positionsAvailable + " Positions Available: try another Domino in the Bag "); #endif } // restore the board's row min/max state board.BoundingBox.RowMin = boardRowMin; board.BoundingBox.RowMax = boardRowMax; board.BoundingBox.ColumnMin = boardColumnMin; board.BoundingBox.ColumnMax = boardColumnMax; // leaf case if (positionsAvailable == 0) { #if TESTALPHABETA Debug.WriteLine("No Position Available (Leaf Case)"); Debug.WriteLine("Board Value" + board.GetBoardValue()); Debug.WriteLine("End AlphaBeta with Depth" + depth); //TODO domino.UpdateDominoLocation(); Debug.WriteLine(""); Debug.WriteLine(""); #endif return(player1Playing ? -board.GetBoardValue() : board.GetBoardValue()); } else { #if TESTALPHABETA Debug.WriteLine(positionsAvailable + " Positions Available "); if (mComputerDepth == depth) { Debug.WriteLine("End Main AlphaBeta with Depth" + depth); } else { Debug.WriteLine("End Recursive AlphaBeta with Depth" + depth); } if (maximizeScore) { Debug.WriteLine("return Max alpha " + alpha); } else { Debug.WriteLine("return Min Beta " + beta); } #endif // return alpha value return(maximizeScore ? alpha : beta); } }