Пример #1
0
 private Turn GetTurnNormal(Game originalGame)
 {
     try {
         GameClientStatsCollector?.StartGetTurn(originalGame);
         int             maxMoves    = GetMaxMoves(originalGame); // MaxMoves
         AlphaBetaSearch abs         = new AlphaBetaSearch(originalGame, maxMoves, Evaluator, false, DoPrune, CollectStats, DoLog);
         var             gameResults = abs.GetGameResult();
         if (gameResults.Item1 == AlphaBetaSearch.GameResultWinning)
         {
             Turn winningTurn = originalGame.GetDirectlyWinningTurn();
             if (winningTurn != null)
             {
                 return(winningTurn);
             }
         }
         GameResult      = gameResults.Item1;
         EvaluationScore = abs.EvaluationScore;
         NodeInfos       = abs.NodeInfos;
         return(gameResults.Item2.OrderByDescending(kvp => kvp.Value).First().Key);
     } finally {
         GameClientStatsCollector?.EndGetTurn();
     }
 }
Пример #2
0
        public Turn GetTurn(Game game)
        {
            var tup = new MiniMax(game, 2, doChecks: false).GetGameResult();

            if (tup.Item1 == MiniMax.GameResultLosing)
            {
                // we're f****d
            }
            else if (tup.Item1 == MiniMax.GameResultWinning)
            {
                // we're winning.
                // let's not extend the misery of the opponent and take a directly winning turn when we get one.
                Turn winningTurn = game.GetDirectlyWinningTurn();
                if (winningTurn != null)
                {
                    return(winningTurn);
                }

                var turn = tup.Item2.First(kvp => kvp.Value == MiniMax.GameResultWinning).Key;
                return(turn);
            }

            //Turn capturingTurn = MiniMax.GetCapturingTurn(game);
            //if (capturingTurn != null) return capturingTurn;

            // make the move that brings the pawns closest to the target
            Vector     target        = GetTarget(game);
            var        pawns         = game.GameState.InTurnPlayerPieces.Where(p => p is Pawn).ToList();
            List <int> bestDistances = pawns.Select(p => Board.GetDistance(target, p.Position)).OrderBy(_ => _).ToList();
            Turn       bestTurn      = null;

            foreach (Turn turn in game.GetValidTurns())
            {
                Vector position = turn.OriginalPosition;
                Piece  piece    = game.GameState.Board[position.X, position.Y];
                piece.Position = turn.OriginalPosition.Add(turn.Move);
                List <int> trialDistances = pawns.Select(p => Board.GetDistance(target, p.Position)).OrderBy(_ => _).ToList();
                piece.Position = position;

                if (Compare(trialDistances, bestDistances) < 0)
                {
                    if (tup.Item2.ContainsKey(turn) && tup.Item2[turn] == MiniMax.GameResultLosing)
                    {
                        // skip, don't play a losing move (if possible)
                    }
                    else
                    {
                        bestDistances = trialDistances;
                        bestTurn      = turn;
                    }
                }
            }
            if (bestTurn != null)
            {
                return(bestTurn);
            }

            if (tup.Item1 != MiniMax.GameResultLosing)
            {
                // make any non-losing move
                return(tup.Item2.First(kvp => kvp.Value != MiniMax.GameResultLosing).Key);
            }
            else
            {
                // we're f****d anyway, make any move
                return(game.GetAnyTurn());
            }
        }
Пример #3
0
        /// <summary>
        /// Returns all neighbouring states and whether or not the move to the neighbouring state is winning or not and the neighbouring gameStateId.
        /// Changes Game.GameState during loop.
        /// Return neighbours in order of score of evaluation function if DoPrune is true.
        /// </summary>
        private IEnumerable <Tuple <Turn, bool, long?> > GetNeighbours(bool isMaxNode, int movesDone)
        {
            GetNeighboursCount++;

            if (movesDone == MaxMoves - 1 || !DoPrune)
            {
                // we don't want to calculate the evaluation score of all leave nodes (to sort on them)
                // because that's slower than traversing them unsorted and then (due to ABS pruning) NOT calculating the evaluation score of some of the leaves at all.
                // so, getting neighbours for the almost-leave-nodes is different than for the other nodes.
                foreach (Turn turn in Game.GetValidTurns())
                {
                    TurnResult turnResult = null;
                    try {
                        turnResult = Game.GameState.PlayTurn(turn, DoChecks);
                        if (turnResult.GameIsFinished)
                        {
                            yield return(Tuple.Create(turn, true, (long?)null));
                        }
                        else
                        {
                            yield return(Tuple.Create(turn, false, (long?)null));
                        }
                    } finally {
                        // roll back
                        Game.GameState.UndoTurn(turn, turnResult, DoChecks);
                    }
                }
            }
            else
            {
                List <Tuple <Turn, double, long?> > turnsWithScore = new List <Tuple <Turn, double, long?> >();

                foreach (Turn turn in Game.GetValidTurns())
                {
                    TurnResult turnResult = null;
                    try {
                        turnResult = Game.GameState.PlayTurn(turn, DoChecks);
                        long?  gameStateId = GetUniqueIdentifier(Game.GameState); // don't calculate gameStateId again in the ABS min/max loop, so pass it on.
                        double score       = GetEvaluationScore(gameStateId.Value);
                        turnsWithScore.Add(Tuple.Create(turn, score, gameStateId));
                    } finally {
                        // roll back
                        Game.GameState.UndoTurn(turn, turnResult, DoChecks);
                    }
                }

                if (isMaxNode)
                {
                    turnsWithScore.Sort((tup1, tup2) => - 1 * tup1.Item2.CompareTo(tup2.Item2)); // descending by score for max nodes.
                }
                else
                {
                    turnsWithScore.Sort((tup1, tup2) => 1 * tup1.Item2.CompareTo(tup2.Item2)); // ascending by score for min nodes.
                }

                foreach (var tup in turnsWithScore)
                {
                    Turn       turn        = tup.Item1;
                    TurnResult turnResult  = null;
                    long?      gameStateId = tup.Item3;
                    try {
                        turnResult = Game.GameState.PlayTurn(turn, DoChecks);
                        if (turnResult.GameIsFinished)
                        {
                            yield return(Tuple.Create(turn, true, gameStateId));
                        }
                        else
                        {
                            yield return(Tuple.Create(turn, false, gameStateId));
                        }
                    } finally {
                        // roll back
                        Game.GameState.UndoTurn(turn, turnResult, DoChecks);
                    }
                }
            }
        }
 private bool IsForwardTurn(Turn turn)
 {
     return(turn.Move.Y > 0 && turn.Player.PlayerIndex == 0 || turn.Move.Y < 0 && turn.Player.PlayerIndex == 1);
 }
Пример #5
0
 public Board(GameState gameState)
 {
     GameState = gameState;
     LastTurn  = null;
 }
Пример #6
0
 public TurnEventArgs(Game game, Turn turn, TurnResult turnResult)
 {
     Game       = game;
     Turn       = turn;
     TurnResult = turnResult;
 }
Пример #7
0
        /// <summary>
        /// Returns whether or not the game is finished after this move.
        /// </summary>
        public TurnResult PlayTurn(Turn turn, bool doChecks = true)
        {
            MiniMax.PlayTurnCount++;
            AlphaBetaSearch.PlayTurnCount++;

            Piece piece = Board[turn.OriginalPosition.X, turn.OriginalPosition.Y];

            if (doChecks)   // set doChecks to false for performance if necessary
            {
                if (piece == null)
                {
                    throw new ArgumentException("Invalid Turn, bad OriginalPosition");
                }
                if (piece.PlayerIndex != InTurnPlayerIndex)
                {
                    throw new ArgumentException("Invalid Turn, wrong piece");
                }
                if (piece.IsCaptured)
                {
                    throw new ArgumentException("Invalid Turn, piece was already captured");
                }
                if (!InTurnPlayerCards.Contains(turn.Card))
                {
                    throw new ArgumentException("Invalid Turn, wrong card");
                }
                if (!turn.Card.GetMoves(InTurnPlayerIndex).Contains(turn.Move))
                {
                    throw new ArgumentException("Invalid Turn, bad move for card");
                }
                if (!IsValidMove(piece, turn.Move))
                {
                    throw new ArgumentException("Invalid Turn, bad move");
                }
            }

            // move pieces
            Vector newPosition = turn.OriginalPosition.Add(turn.Move);
            Piece  captured    = Board[newPosition.X, newPosition.Y];

            Board[turn.OriginalPosition.X, turn.OriginalPosition.Y] = null;
            piece.Position = newPosition;
            Board[newPosition.X, newPosition.Y] = piece;

            if (captured != null)
            {
                captured.IsCaptured = true;
                CapturedPieces.Push(captured);
            }

            // swap played card with middle card
            Card tmp = GameCards[MiddleCardIndex];

            GameCards[MiddleCardIndex] = GameCards[PlayerCardIndices[InTurnPlayerIndex][turn.CardIndex]];
            GameCards[PlayerCardIndices[InTurnPlayerIndex][turn.CardIndex]] = tmp;

            bool gameIsFinshed = false;

            if (captured != null && captured is King)
            {
                gameIsFinshed = true;
            }
            else if (piece is King && newPosition.Equals(Domain.Board.PlayerBases[1 - InTurnPlayerIndex]))
            {
                gameIsFinshed = true;
            }

            if (gameIsFinshed)
            {
                WinningPlayerIndex = InTurnPlayerIndex;
            }

            InTurnPlayerIndex = 1 - InTurnPlayerIndex; // let's toggle this for consistency, even when the game has just been finished.

            return(new TurnResult(captured, gameIsFinshed));
        }