// Returns the best move from some particular state for the player which has the turn, within the time given
        // Returns random move if not enough time is given
        // pre: startState != null && !startState.isFinal()
        public UTTTMove FindBestMove(UTTTState startState, int msGiven)
        {
            if (startState == null || startState.IsFinal())
            {
                throw new ArgumentException("TimedSearcher.FindBestMove: Invalid startState passed.");
            }

            // stopwatch keeps track of how much time we have left
            Stopwatch sw = new Stopwatch();

            sw.Start();

            // iterative deepening
            UTTTMove          bestMove  = null;
            double            bestScore = 0;
            TimedAlphaBetaWIP timedAB   = new TimedAlphaBetaWIP(sw, msGiven, startState);

            for (int depthLeft = 1; sw.ElapsedMilliseconds < msGiven; depthLeft++)
            {
                List <UTTTMove> newMoveList = new List <UTTTMove>();
                TimedAlphaBetaWIP.AlphaBetaIterationResult res = timedAB.computeNextIteration();
                if (res.outOfTime)
                {
                    break;
                }
                else
                {
                    bestMove  = res.bestMove;
                    bestScore = res.bestMoveValue;
                }
            }

            // if no time to find any move, return random move
            if (bestMove == null)
            {
                bestMove = startState.GetPossibleMoves().First();
            }

            sw.Stop();
            Console.Error.WriteLine(bestScore);
            return(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);
            }
        }