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);
            }
        }