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);
 }
 public TimedAlphaBetaWIP(Stopwatch sw, int msGiven, UTTTState startState)
 {
     this.sw         = sw;
     this.msGiven    = msGiven;
     this.statesSeen = new Dictionary <int, StateRecord>();
     this.startState = startState;
     this.iteration  = 0;
 }
        // 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);
        }
Пример #4
0
        private static void RealMainEatCheese()
        {
            TimedSearcher searcher      = new TimedSearcher();
            ZobristHasher zobristHasher = new ZobristHasher(9, 9, 2);
            UTTTState     currentState  = null;

            int    timePerMove;
            int    timebank;
            String field          = null;
            String macroboard     = null;
            bool   weArePlayerOne = false;

            while (true)
            {
                Thread.Sleep(10);
                String line = Console.In.ReadLine();
                if (line.Length == 0)
                {
                    continue;
                }
                Console.Error.WriteLine(line);
                String[] parts = line.Split(' ');
                switch (parts[0])
                {
                case "settings":
                    switch (parts[1])
                    {
                    case "time_per_move":
                        timePerMove = int.Parse(parts[2]);
                        break;

                    case "timebank":
                        timebank = int.Parse(parts[2]);
                        break;

                    case "field":
                        field = parts[2];
                        break;

                    case "macroboard":
                        macroboard = parts[2];
                        break;

                    case "your_botid":
                        weArePlayerOne = (int.Parse(parts[2]) == 1);
                        break;
                    }
                    break;

                case "update":
                    switch (parts[2])
                    {
                    case "field":
                        field = parts[3];
                        break;

                    case "macroboard":
                        macroboard = parts[3];
                        break;
                    }
                    break;

                case "action":
                    currentState = new UTTTState(field, macroboard, zobristHasher, weArePlayerOne);
                    UTTTMove chosen = searcher.FindBestMove(currentState, 2000);
                    Console.WriteLine($"place_move {chosen.x} {chosen.y}");
                    Console.Out.Flush();
                    break;

                default:
                    // error
                    break;
                }
            }
        }
        // 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);
            }
        }