/// <summary>
    /// Finds all the possible move sequences for the current player in a given match.
    /// </summary>
    /// <param name="match">Match to check against</param>
    /// <returns>A list of the possible move sequences</returns>
    public static List <MoveSequence> GenerateAllSequences(Match match)
    {
        List <Move>         validMoves   = GameLogic.GetValidMoves(match);
        List <MoveSequence> allSequences = new List <MoveSequence>();

        foreach (Move possibleMove in validMoves)
        {
            Match dummyMatch = match.Clone();
            switch (dummyMatch.board.ApplyMove(possibleMove))
            {
            case MoveType.Jump:
            case MoveType.Capture:
                List <MoveSequence> possibleSequences = new List <MoveSequence>();
                ExpandMoveSequences(new MoveSequence(), possibleMove, match.Clone(), possibleSequences);
                allSequences.AddRange(possibleSequences);
                break;

            case MoveType.Normal:
                MoveSequence basic = new MoveSequence();
                basic.AddMove(possibleMove);
                allSequences.Add(basic);
                break;
            }
        }
        return(allSequences);
    }
Example #2
0
    /// <summary>
    /// Finds the best position(s) to place new pieces at.
    /// </summary>
    /// <returns>An array with the best positions to place the new pieces at</returns>
    /// <remarks>Depending on how many unplaced pieces the player has, the returned array may contain one or two elements</remarks>
    public Position[] SpawnPieces()
    {
        List <Position[]> bestPositionSets = new List <Position[]>();
        int bestScore = int.MinValue;

        if (match.unplacedPieces == 2)
        {
            foreach (Position freeSlot1 in match.freeSlots)
            {
                foreach (Position freeSlot2 in match.freeSlots)
                {
                    if (freeSlot1.Equals(freeSlot2))
                    {
                        continue;
                    }
                    Match dummyMatch = match.Clone(); // Creates a copy of the match where each move can be simulated
                    dummyMatch.SpawnPiece(freeSlot1);
                    dummyMatch.SpawnPiece(freeSlot2);
                    int newScore = Minimax(dummyMatch, false, int.MinValue, int.MaxValue, 2) + BonusEvaluation(dummyMatch, 2);
                    if (newScore < bestScore)
                    {
                        continue;
                    }
                    Position[] positionSet = new Position[2];
                    positionSet[0] = freeSlot1;
                    positionSet[1] = freeSlot2;
                    if (newScore > bestScore)
                    {
                        bestScore = newScore;
                        bestPositionSets.Clear();
                    }
                    bestPositionSets.Add(positionSet);
                }
            }
        }
        else
        {
            foreach (Position freeSlot in match.freeSlots)
            {
                Match dummyMatch = match.Clone(); // Creates a copy of the match where each move can be simulated
                dummyMatch.SpawnPiece(freeSlot);
                int newScore = Minimax(dummyMatch, false, int.MinValue, int.MaxValue, 2) + BonusEvaluation(dummyMatch, 2);
                if (newScore < bestScore)
                {
                    continue;
                }
                Position[] positionSet = new Position[1];
                positionSet[0] = freeSlot;
                if (newScore > bestScore)
                {
                    bestScore = newScore;
                    bestPositionSets.Clear();
                }
                bestPositionSets.Add(positionSet);
            }
        }
        return(bestPositionSets[new System.Random().Next(bestPositionSets.Count)]);
    }
Example #3
0
        static void Main(string[] args)
        {
            Console.WriteLine("Final Example");

            //Inflate match information
            Match match = new Match();

            Console.WriteLine(match.Print());

            //Clone match information - Don't instantiate again
            Console.ForegroundColor = ConsoleColor.Green;
            Match clone = match.Clone() as Match;

            Console.WriteLine(clone.Print());

            Console.ForegroundColor = ConsoleColor.Red;
            BasketEndPoint basketApi = new BasketEndPoint();

            //Get basket match information to Api
            //API returns us a object with private constructors! We can't instantiate the class!
            BasketMatch basketMatch = basketApi.Get();

            Console.WriteLine(basketMatch.Print());

            //INTERNAL Constructors
            //BasketMatch.BasketMatch()' is inaccessible due to its protection level!
            //var newBasket = new BasketMatch();

            //The class can be cloned
            BasketMatch cloneBasketMatch = basketMatch.Clone() as BasketMatch;

            Console.WriteLine(cloneBasketMatch.Print());
        }
        internal Wildcard(Match.MatchOptions options, Match.MatchParameter parameter)
        {
            _Options = options.Clone();
            _Options.SynonymOutput = false;
            _Options.WildcardOutput = false;

            _Parameter = parameter.Clone();
        }
    /// <summary>
    /// Expands a move to form every possible capture or jump sequence from it.
    /// </summary>
    /// <param name="expandingSequence">Move sequence being expanded</param>
    /// <param name="move">Move to expand from</param>
    /// <param name="match">Match to check against</param>
    /// <param name="moveSeqList">List of the expanded move sequences</param>
    /// <remarks>
    /// The <paramref name="moveSeqList"/> should be initialized as a new object before the initial function call.
    /// </remarks>
    private static void ExpandMoveSequences(MoveSequence expandingSequence, Move move, Match match, List <MoveSequence> moveSeqList)
    {
        expandingSequence.AddMove(move);
        match.ExecuteMove(move);
        List <Position> nextDestinies = move.type == MoveType.Capture? GameLogic.GetCaptureMoveDestinies(match, move.endPosition) : GameLogic.GetJumpMoveDestinies(match, move.endPosition);

        if (nextDestinies.Count == 0)
        {
            moveSeqList.Add(expandingSequence);
            return;
        }
        List <Move> nextMoves = ToMovesList(move.endPosition, nextDestinies, move.type == MoveType.Capture? MoveType.Capture : MoveType.Jump);

        foreach (Move nextMove in nextMoves)
        {
            Match dummyMatch = match.Clone();
            dummyMatch.ExecuteMove(nextMove);
            MoveSequence moveSeqTemp = expandingSequence.Clone();
            ExpandMoveSequences(moveSeqTemp, nextMove, match.Clone(), moveSeqList);
        }
    }
Example #6
0
    /// <summary>
    /// Implementation of the Minimax algorithm.
    /// </summary>
    /// <param name="match">Match being evaluated</param>
    /// <param name="maximizing">True if the algorithm is being applied to the maximizing player, false otherwise</param>
    /// <param name="alpha">Best value that the maximizer can guarantee</param>
    /// <param name="beta">Best value that the maximizer can guarantee</param>
    /// <param name="depth">Search depth</param>
    /// <returns>The expected evaluation for the initially input <paramref name="match"/> based on the Minimax algorithm</returns>
    private int Minimax(Match match, bool maximizing, int alpha, int beta, int depth)
    {
        if (match.isGameOver())
        {
            return(maximizing? int.MaxValue : int.MinValue);
        }
        if (depth == 1)          // Reach of depth limit
        {
            return(EvaluateState(match, 2));
        }
        List <MoveSequence> nextSequences = GenerateAllSequences(match);        // Generates the possible moves from the received game state

        int bestScore = maximizing? int.MinValue : int.MaxValue;

        foreach (MoveSequence moveSequence in nextSequences)
        {
            Match dummyMatch = match.Clone();                                        // Creates a copy of the match where each move can be simulated
            dummyMatch.board.ApplyMoveSequence(moveSequence);                        // Simulates the move or sequence of moves
            dummyMatch.ChangeTurn();
            int newScore = Minimax(dummyMatch, !maximizing, alpha, beta, depth - 1); // Calls minimax with the new game state
            if (maximizing)
            {
                bestScore = Math.Max(bestScore, newScore);
                alpha     = Math.Max(alpha, newScore);
            }
            else
            {
                bestScore = Math.Min(bestScore, newScore);
                beta      = Math.Min(beta, newScore);
            }
            if (beta <= alpha) // Alpha-beta pruning
            {
                break;
            }
        }
        return(bestScore);
    }
Example #7
0
        public Match UpdateScoreReport(MatchReportDTO matchReportDto)
        {
            //Find the corresponding match
            var match    = _matchRepository.FindById(matchReportDto.matchId);
            var oldMatch = Match.Clone(match);
            var draw     = _drawRepository.FindById(match.DrawId);

            //Format the string and check for errors
            var p1Points       = new List <int>();
            var p2Points       = new List <int>();
            var gameScores     = matchReportDto.score.Split(" ");
            int validGameCount = 0;

            for (int i = 0; i < gameScores.Length; i++)
            {
                try
                {
                    var pointStrings = gameScores[i].Split("/");
                    var p1           = Int32.Parse(pointStrings[0]);
                    var p2           = Int32.Parse(pointStrings[1]);
                    p1Points.Add(p1);
                    p2Points.Add(p2);
                    validGameCount++;
                }
                catch (Exception e)
                {
                    //When formatting goes wrong - break the for loop - this might be when we encounter "__/__"
                    break;
                }
            }

            //Check that number of games is as expected
            var maxGames = draw.Games;
            var minGames = (1 + maxGames) / 2;

            if (validGameCount > maxGames) //Too many games
            {
                throw new TournamentSoftwareException(
                          $"{validGameCount} valid games in score-string {1}, but a maximum of {maxGames} allowed.");
            }
            //Too few games
            if (validGameCount < minGames)
            {
                throw new TournamentSoftwareException(
                          $"{validGameCount} valid games in score-string {matchReportDto.score}," +
                          $" but at least {minGames} were required in draw with up to {draw.Games} games.");
            }

            //Check that points correspond to expected values
            for (int i = 0; i < validGameCount; i++)
            {
                var overMax = p1Points[i] > draw.Points || p2Points[i] > draw.Points;

                if (draw.TieBreaks) //If tie breaks are allowed
                                    //There can be too many points, but only if there is excactly 2 points between scores
                {
                    if (overMax && Math.Abs(p1Points[i] - p2Points[i]) != 2)
                    {
                        throw new TournamentSoftwareException(
                                  $"Score in score-string {matchReportDto.score} does not follow tie break rules." +
                                  $"A max of {draw.Points} is allowed, unless it is a tie break.");
                    }
                }
                else //If tie breaks are not allowed - no score must be greater than max
                {
                    if (overMax)
                    {
                        throw new TournamentSoftwareException(
                                  $"Too high point score in score-string {matchReportDto.score}." +
                                  $"A max of {draw.Points} is allowed, since tie breaks are disallowed.");
                    }
                }
            }


            //Find the winner
            int p1Games = 0, p2Games = 0, p1PointsTotal = 0, p2PointsTotal = 0;

            for (int i = 0; i < validGameCount; i++)
            {
                p1PointsTotal += p1Points[i];
                p2PointsTotal += p2Points[i];
                if (p1Points[i] > p2Points[i])
                {
                    p1Games++;
                }
                else if (p1Points[i] < p2Points[i])
                {
                    p2Games++;
                }
                else
                {
                    throw new TournamentSoftwareException(
                              $"Game with equal score in score-string {matchReportDto.score}");
                }
            }

            if (p1Games > p2Games)
            {
                match.P1Won = true;
            }
            else if (p1Games < p2Games)
            {
                match.P1Won = false;
            }
            else
            {
                //Winner is decided by who won the most points
                match.P1Won = p1PointsTotal > p2PointsTotal;
            }

            //Set variables
            match.P1PointsArray = p1Points.ToArray();
            match.P2PointsArray = p2Points.ToArray();
            match.P1Games       = p1Games;
            match.P2Games       = p2Games;
            match.Status        = Status.FINISHED;

            //Update the match using existing Update method and return
            return(Update(match, oldMatch));
        }