public void Update(double value, UTTTMove bestMove, UTTTState currentState, Dictionary <int, StateRecord> statesSeen, int iteration) { this.value = value; this.bestMove = bestMove; this.iteration = iteration; statesSeen.Add(currentState.GetHashCode(), this); }
// gets best move AFTER an iteration has been completed private UTTTMove GetBestMove() { StateRecord rec = new StateRecord(); statesSeen.TryGetValue(startState.GetHashCode(), out rec); return(rec.bestMove); }
// state : The root of the (sub)-tree this search expands // alpha : Value used for AlphaBeta pruning - maximum value maximizing player can definitely get // beta : Value used for AlphaBeta pruning - minimum value minimizing player can definitely get // depthLeft : How many more depths we are allowed to explore private double AlphaBetaSearch(UTTTState state, double alpha, double beta, int depthLeft) { // throw an exception if our player is forced to stop if (sw.ElapsedMilliseconds > msGiven) { throw new OutOfTimeException(); } // if final depth reached, then return the value of this leaf if (depthLeft == 0 || state.IsFinal()) { return(state.Evaluate()); } // if not final depth, then generate all possible branches List <UTTTMove> moves = state.GetPossibleMoves(); // if (moves.Count == 0) { throw new OutOfTimeException(); } // if only a single move is possible, don't decrease depth if (moves.Count == 1) { depthLeft++; } // if the state has been seen before, then continue // tracing the best move of the previous iteration by putting the old move // in the first position to be evaluated. This leads to better pruning. StateRecord rec = null; statesSeen.TryGetValue(state.GetHashCode(), out rec); if (rec != null) { if (rec.iteration == iteration) { return(rec.value); } if (rec.bestMove != null) { FindCopyAndSwap(rec.bestMove, moves, moves.First()); } statesSeen.Remove(state.GetHashCode()); } else { rec = new StateRecord(); } // keep track of the best move // update the StateRecord in the dictionary after we have finished analyzing the state Boolean min = state.MinimizingHasTurn(); UTTTMove bestMove = null; foreach (UTTTMove move in moves) { state.DoMove(move); double result = AlphaBetaSearch(state, alpha, beta, depthLeft - 1); state.UndoMove(move); if ((min && result < beta) || (!min && result > alpha)) { bestMove = move; if (min) { beta = result; } else { alpha = result; } } if (alpha >= beta) { // update record and return double res = (alpha + beta) / 2; rec.Update(res, bestMove, state, statesSeen, iteration); return(res); } } // update record and return if (min) { rec.Update(beta, bestMove, state, statesSeen, iteration); return(beta); } else { rec.Update(alpha, bestMove, state, statesSeen, iteration); return(alpha); } }