Ejemplo n.º 1
0
        // Runs an entire game using a parallelized version of MCTS limited by time
        public State RunParallelTimeLimitedMCTS(bool print, int timeLimit)
        {
            // update deck memory initially with observed cards on board
            this.UpdateDeckMemory(0, true);
            int nextCard = this.gameEngine.nextCard;

            while (true)
            {
                currentState = new State(BoardHelper.CloneGrid(this.gameEngine.currentState.Grid), GameEngine.PLAYER);

                if (print)
                {
                    Program.CleanConsole();
                    Console.WriteLine(BoardHelper.ToString(currentState.Grid));
                }

                DIRECTION result = ParallelTimeLimitedMCTS(currentState, timeLimit, deck.Clone());
                PlayerMove move = new PlayerMove();
                move.Direction = result;
                if (result == (DIRECTION)(-1))
                {
                    // game over
                    return currentState;
                }
                gameEngine.SendUserAction(move);

                // update deck memory only if the new card is not a bonus card (we know what value the new card has by keeping track of nextcard
                if (nextCard > 0) this.UpdateDeckMemory(nextCard, false);
                nextCard = this.gameEngine.nextCard;
            }
        }
Ejemplo n.º 2
0
 // Returns a list of all player moves
 private List<Move> GetAllPlayerMoves()
 {
     List<Move> moves = new List<Move>();
     foreach (DIRECTION direction in Enum.GetValues(typeof(DIRECTION)))
     {
         if (IsValidMove(direction))
         {
             PlayerMove move = new PlayerMove(direction);
             moves.Add(move);
         }
     }
     return moves;
 }
Ejemplo n.º 3
0
        // Recursive part of iterative deepening
        private Tuple<Move, bool> RecursiveIterativeDeepening(State state, int depth, double alpha, double beta, int timeLimit, Stopwatch timer, Deck deck)
        {
            Move bestMove;
            if (depth == 0 || state.IsGameOver())
            {
                if (state.Player == GameEngine.PLAYER)
                {
                    bestMove = new PlayerMove(); // default constructor creates dummy action
                    bestMove.Score = AI.Evaluate(state);
                    return new Tuple<Move, Boolean>(bestMove, true);
                }
                else if (state.Player == GameEngine.COMPUTER)
                {
                    bestMove = new ComputerMove(); // default constructor creates dummy action
                    bestMove.Score = AI.Evaluate(state);
                    return new Tuple<Move, Boolean>(bestMove, true);
                }
                else
                {
                    throw new Exception();
                }
            }
            if (state.Player == GameEngine.PLAYER){

                bestMove = new PlayerMove();
                double highestScore = Double.MinValue, currentScore = Double.MinValue;

                List<Move> moves = state.GetAllMoves();

                foreach (Move move in moves)
                {
                    State resultingState = state.ApplyMove(move);
                    currentScore = RecursiveIterativeDeepening(resultingState, depth - 1, alpha, beta, timeLimit, timer, deck).Item1.Score;
                    if (currentScore > highestScore)
                    {
                        highestScore = currentScore;
                        bestMove = (PlayerMove)move;
                    }
                    alpha = Math.Max(alpha, highestScore);
                    if (beta <= alpha)
                        break;
                    if (timer.ElapsedMilliseconds > timeLimit)
                    {
                        bestMove.Score = highestScore;
                        return new Tuple<Move, Boolean>(bestMove, false); // recursion not completed, return false
                    }
                }

                bestMove.Score = highestScore;
                return new Tuple<Move, Boolean>(bestMove, true);
            }
            else
            {
                bestMove = new ComputerMove();
                double lowestScore = Double.MaxValue, currentScore = Double.MaxValue;

                List<Move> moves = null;
                if (depth == definedDepth - 1)
                {
                    int nextCard = game.nextCard;
                    moves = state.GetAllComputerMoves(nextCard);
                }
                else
                {
                    if (deck.IsEmpty()) deck = new Deck();
                    moves = state.GetAllComputerMoves(deck);
                }

                foreach (Move move in moves)
                {
                    deck.Remove(((ComputerMove)move).Card);
                    State resultingState = state.ApplyMove(move);
                    currentScore = RecursiveIterativeDeepening(resultingState, depth - 1, alpha, beta, timeLimit, timer, deck).Item1.Score;
                    if (currentScore < lowestScore)
                    {
                        lowestScore = currentScore;
                        bestMove = (ComputerMove)move;
                    }
                    beta = Math.Min(beta, lowestScore);
                    if (beta <= alpha)
                        break;
                    deck.Add(((ComputerMove)move).Card);
                    if (timer.ElapsedMilliseconds > timeLimit)
                    {
                        bestMove.Score = lowestScore;
                        return new Tuple<Move, Boolean>(bestMove, false); // recursion not completed, return false
                    }
                }
                bestMove.Score = lowestScore;
                return new Tuple<Move, Boolean>(bestMove, true);
            }
        }
Ejemplo n.º 4
0
        // Runs an entire game using a parallelized version of iterative deepening minimax
        private Move ParallelIterativeDeepening(State state, int timeLimit, Deck deck)
        {
            Move bestMove = new PlayerMove();

            List<Move> moves = state.GetMoves(deck);
            ConcurrentBag<Tuple<double, Move>> scores = new ConcurrentBag<Tuple<double, Move>>();

            if (moves.Count == 0)
            {
                // game over
                return bestMove;
            }

            // create the resulting states before starting the threads
            List<State> resultingStates = new List<State>();
            foreach (Move move in moves)
            {
                State resultingState = state.ApplyMove(move);
                resultingStates.Add(resultingState);
            }

            Parallel.ForEach(resultingStates, resultingState =>
            {
                double score = IterativeDeepening(resultingState, timeLimit, deck.Clone()).Score;
                scores.Add(new Tuple<double, Move>(score, resultingState.GeneratingMove));
            });
            // find the best score
            double highestScore = Double.MinValue;
            foreach (Tuple<double, Move> score in scores)
            {
                PlayerMove move = (PlayerMove)score.Item2;
                if (score.Item1 > highestScore)
                {
                    highestScore = score.Item1;
                    bestMove = score.Item2;
                }
            }
            return bestMove;
        }
Ejemplo n.º 5
0
 // Classic Minimax using alpha-beta pruning
 private Move MinimaxAlgorithm(State state, int depth, double alpha, double beta, Deck deck)
 {
     Move bestMove;
     if (depth == 0 || state.IsGameOver())
     {
         if (state.Player == GameEngine.PLAYER)
         {
             bestMove = new PlayerMove(); // default constructor creates dummy action
             bestMove.Score = AI.Evaluate(state);
             return bestMove;
         }
         else if (state.Player == GameEngine.COMPUTER)
         {
             bestMove = new ComputerMove(); // default constructor creates dummy action
             bestMove.Score = AI.Evaluate(state);
             return bestMove;
         }
         else
         {
             throw new Exception();
         }
     }
     if (state.Player == GameEngine.PLAYER)
         return Max(state, depth, alpha, beta);
     else
         return Min(state, depth, alpha, beta);
 }
Ejemplo n.º 6
0
        // MAX part of Minimax
        Move Max(State state, int depth, double alpha, double beta)
        {
            PlayerMove bestMove = new PlayerMove();
            double highestScore = Double.MinValue, currentScore = Double.MinValue;

            List<Move> moves = state.GetAllMoves();

            foreach (Move move in moves)
            {
                State resultingState = state.ApplyMove(move);
                currentScore = MinimaxAlgorithm(resultingState, depth - 1, alpha, beta, deck).Score;
                if (currentScore > highestScore)
                {
                    highestScore = currentScore;
                    bestMove = (PlayerMove)move;
                }
                alpha = Math.Max(alpha, highestScore);
                if (beta <= alpha)
                    break;
            }
            bestMove.Score = highestScore;
            return bestMove;
        }
Ejemplo n.º 7
0
        // Starts a game for the user to play
        private static void StartGame()
        {
            GameEngine game = new GameEngine();
            bool gameOver = false;
            CleanConsole();

            // main game loop
            while (!gameOver)
            {
                CleanConsole();
                String nextCard = "";
                if (game.nextCard == -1) nextCard = "BONUS CARD";
                else nextCard = game.nextCard.ToString();
                Console.WriteLine("Next card: " + nextCard);
                Console.WriteLine(BoardHelper.ToString(game.currentState.Grid));

                DIRECTION action = GetUserInput();
                PlayerMove move = new PlayerMove(action);
                gameOver = game.SendUserAction(move);
            }
            CleanConsole();

            Console.WriteLine("Next card: ");
            Console.WriteLine(BoardHelper.ToString(game.currentState.Grid));
            Console.WriteLine("GAME OVER! Final score: " + game.currentState.CalculateFinalScore());
            Console.ReadLine(); // to avoid console closing immediately
        }
Ejemplo n.º 8
0
        // Takes a player action and executes it, updates peek card and
        // generates a new random tile
        public bool SendUserAction(PlayerMove action)
        {
            currentState = currentState.ApplyMove(action);

            // only continue game if action was valid (if something moved on the grid)
            if (currentState.columnsOrRowsWithMovedTiles.Count != 0)
            {
                 GenerateNewCard();
                 if (CheckForGameOver())
                 {
                    return true;
                }
                UpdatePeekCard();
            }
            return false;
        }