コード例 #1
0
ファイル: Board.cs プロジェクト: AustinJGreen/MarbleBoardGame
        /// <summary>
        /// Thinks about the current position given the dice roll and calculates the best move
        /// </summary>
        /// <param name="algorithm">Evaluation algorithm to use</param>
        /// <param name="roll">Roll</param>
        /// <param name="team">Team to think for</param>
        /// <param name="depth">Depth to think</param>
        public Move ThinkBest(Algorithm algorithm, DiceRoll roll, sbyte team, int ms)
        {
            MoveCollection collection = GetMoves(roll, team);

            if (collection.Count == 0)
            {
                return(null);
            }
            else if (collection.Count == 1)
            {
                return(collection[0]);
            }
            else if (ms < 0)
            {
                return(collection[random.Next(collection.Count)]);
            }

            PositionNode[] nodes = new PositionNode[collection.Count];
            for (int i = 0; i < collection.Count; i++)
            {
                Position node = new Position(this.quadrants);
                PerformMove(node, collection[i]);

                nodes[i] = new PositionNode(node, collection[i], roll);
            }

            algorithm.Player = team;
            Vector4[] evaluations = new Vector4[nodes.Length];
            for (int j = 0; j < nodes.Length; j++)
            {
                PositionNode currentRootMoveNode = nodes[j];
                algorithm.Root = currentRootMoveNode;

                Vector4 moveEval = algorithm.Go(ms / collection.Count);
                evaluations[j] = moveEval;
            }

            int    highIndex = 0;
            double high      = evaluations[0].GetMagnitude(team);

            for (int i = 1; i < evaluations.Length; i++)
            {
                double curMag = evaluations[i].GetMagnitude(team);
                if (curMag > high)
                {
                    high      = curMag;
                    highIndex = i;
                }
            }

            return(collection[highIndex]);
        }
コード例 #2
0
ファイル: Board.cs プロジェクト: AustinJGreen/MarbleBoardGame
        /// <summary>
        /// Checks if the move is a possible move for a human (called by Engine)
        /// </summary>
        /// <param name="move">Move move</param>
        public bool IsPossibleMove(DiceRoll roll, Move move, out Move orderCorrect)
        {
            MoveCollection collection = GetMoves(roll, move.Team);

            for (int j = 0; j < collection.Count; j++)
            {
                if (collection[j].Equals(move))
                {
                    orderCorrect = collection[j];
                    return(true);
                }
            }

            orderCorrect = null;
            return(false);
        }
コード例 #3
0
ファイル: Board.cs プロジェクト: AustinJGreen/MarbleBoardGame
        public MoveCollection ThinkAll(Algorithm algorithm, DiceRoll roll, sbyte team, int ms, out Vector4[] scores)
        {
            MoveCollection collection = GetMoves(roll, team);

            if (collection.Count == 0)
            {
                scores = null;
                return(null);
            }
            else if (collection.Count == 1)
            {
                scores = new Vector4[1] {
                    algorithm.Eval(this.GetPosition(), roll.IsDoubles() ? team : Board.NO_PLAYER)
                };
                return(collection);
            }
            if (ms < 0)
            {
                throw new ArgumentException();
            }

            PositionNode[] nodes = new PositionNode[collection.Count];
            for (int i = 0; i < collection.Count; i++)
            {
                Position node = new Position(this.quadrants);
                PerformMove(node, collection[i]);

                nodes[i] = new PositionNode(node, collection[i], roll);
            }

            algorithm.Player = team;
            Vector4[] evaluations = new Vector4[nodes.Length];
            for (int j = 0; j < nodes.Length; j++)
            {
                PositionNode currentRootMoveNode = nodes[j];
                algorithm.Root = currentRootMoveNode;

                Vector4 moveEval = algorithm.Go(ms / collection.Count);
                evaluations[j] = moveEval;
            }

            SortDecreasing(evaluations, collection, team);
            scores = evaluations;
            return(collection);
        }
コード例 #4
0
ファイル: Board.cs プロジェクト: AustinJGreen/MarbleBoardGame
        /// <summary>
        /// Checks if the piece move is part of a valid move
        /// </summary>
        /// <param name="roll">Current roll</param>
        /// <param name="move">Move to check</param>
        /// <param name="team">Team</param>
        public bool IsPossibleTreeMove(DiceRoll roll, PieceMove move, sbyte team)
        {
            MoveCollection collection = GetMoves(roll, team);

            for (int j = 0; j < collection.Count; j++)
            {
                PieceMove[] moves = collection[j].PieceMoves;
                for (int i = 0; i < moves.Length; i++)
                {
                    if (moves[i].Equals(move))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
コード例 #5
0
        /// <summary>
        /// Starts thinking
        /// </summary>
        public void Think(DiceRoll roll, Board board)
        {
            int       timeThink = Difficulty.TimeThink;
            Algorithm algorithm = GetAlgorithm();

            if (timeThink < 0)
            {
                base.SetMove(board.ThinkBest(algorithm, roll, Team, timeThink));
                return;
            }

            int blunderValue = Board.Next(100);

            if (blunderValue < Difficulty.BlunderPercent)
            {
                //Worst move
                Vector4[]      scores;
                MoveCollection moves = board.ThinkAll(algorithm, roll, Team, ComputerPlayer.Difficulties[ComputerPlayer.Difficulties.Length - 1].TimeThink, out scores);
                LastEvaluation = GetVariations(moves, scores);

                if (moves != null)
                {
                    base.SetMove(moves[moves.Count - 1]);
                    return;
                }
            }
            else
            {
                //Best move
                Vector4[]      scores;
                MoveCollection moves = board.ThinkAll(algorithm, roll, Team, Difficulty.TimeThink, out scores);
                LastEvaluation = GetVariations(moves, scores);

                if (moves != null)
                {
                    base.SetMove(moves[0]);
                    return;
                }
            }

            base.SetMove(null);
        }
コード例 #6
0
        public override void StartThink(Board board, DiceRoll roll)
        {
            base.StartThink(board, roll);
            //Continue logic

            if (thinkThread != null)
            {
                if (thinkThread.ThreadState == ThreadState.Running)
                {
                    thinkThread.Abort();
                    thinkThread = new Thread(() => Think(roll, board));
                }
            }

            thinkThread              = new Thread(() => Think(roll, board));
            thinkThread.Name         = "MarbleBoard_AI";
            thinkThread.IsBackground = true;
            DateTime start = DateTime.Now;

            thinkThread.Start();
        }
コード例 #7
0
        private double Iterate(Position pos, sbyte us, sbyte evaluating_team, int time)
        {
            Stopwatch sw = Stopwatch.StartNew();

            double wins   = 0;
            double losses = 0;

            Board board = new Board();

            sbyte team = NextTeam(us);

            int   doublesCount = 0;
            sbyte lastTeam     = 0;

            int turns = 0;

            do
            {
                //Reset board
                board.SetPosition(pos);

                //Pick random nodes and play out game
                while (!board.IsGameOver())
                {
                    lastTeam = team;

                    DiceRoll roll = board.GetRandomRoll();

                    MoveCollection moves = board.GetMoves(roll, team);

                    if (moves.Count != 0)
                    {
                        Move m = moves[Board.Next(moves.Count)];
                        if (m != null)
                        {
                            board.PerformMove(m);
                        }
                    }

                    if (roll.IsDoubles())
                    {
                        doublesCount++;
                        if (doublesCount >= 3)
                        {
                            board.RemoveFrontMarble(team);
                            doublesCount = 0;
                            team         = board.NextPlayer(team);
                            turns++;
                        }
                    }
                    else
                    {
                        doublesCount = 0;
                        team         = board.NextPlayer(team);
                        turns++;
                    }
                }

                if (lastTeam == evaluating_team)
                {
                    wins++;
                }
                else
                {
                    losses++;
                }
            }while (sw.ElapsedMilliseconds < time);

            return(wins / losses);
        }
コード例 #8
0
ファイル: Board.cs プロジェクト: AustinJGreen/MarbleBoardGame
        /// <summary>
        /// Gets all the possible moves for a team given a dice roll
        /// </summary>
        /// <param name="roll">Dice roll</param>
        /// <param name="team">Marble team</param>
        public MoveCollection GetMoves(Position position, DiceRoll roll, sbyte team)
        {
            if (team < 0 || team > TEAM_COUNT)
            {
                return(null);
            }

            sbyte winner = -1;

            if (position.IsWon(out winner))
            {
                return(null);
            }

            MoveCollection moves = new MoveCollection(this, position);

            Square[] marbleSquares = GetMarbles(position, team);

            bool hasMarbleOnSpawn = position.Get(new Square(team, 0)) == team;
            int  activePieces     = GetActivePiecesCount(marbleSquares);

            //Loop until a marble in our base is found
            for (int i = 0; i < marbleSquares.Length; i++)
            {
                //If marble is at start square
                if (marbleSquares[i] == null)
                {
                    //If no team marble is on spawn square
                    if (!hasMarbleOnSpawn)
                    {
                        int[] takeOut = roll.CanTakeOutWith();
                        if (takeOut.Length > 0)
                        {
                            for (int j = 0; j < takeOut.Length; j++)
                            {
                                Square target = new Square(team, takeOut[j]);
                                if (position.Get(target) != team)
                                {
                                    moves.Add(new Move(new PieceMove(null, target), team));
                                }
                            }
                        }
                    }

                    //Add a special case for taking out a piece and using the other die value on another marble
                    if (activePieces > 0)
                    {
                        int[]     combinations = roll.GetDoublesTakeOutCombinations();
                        PieceMove takeOutCombo = new PieceMove(null, new Square(team, 0));
                        for (int p = 0; p < activePieces; p++)
                        {
                            for (int pc = 0; pc < combinations.Length; pc++)
                            {
                                PieceMove correspondant = new PieceMove(marbleSquares[p], marbleSquares[p].Add(combinations[pc], team));

                                if (hasMarbleOnSpawn && !correspondant.From.Equals(takeOutCombo.To))
                                {
                                    continue;
                                }

                                moves.Add(new Move(new PieceMove[] { correspondant, takeOutCombo }, team));
                            }
                        }
                    }

                    break;
                }
            }

            List <int[]> pieceCombinations = GetPieceCombinations(activePieces);

            for (int c = 0; c < pieceCombinations.Count; c++)
            {
                int     pieces      = pieceCombinations[c].Length;
                int[][] pieceValues = roll.GetValues(pieces);
                for (int k = 0; k < pieceValues.Length; k++)
                {
                    PieceMove[] pieceMoves = new PieceMove[pieces];

                    for (int j = 0; j < pieces; j++)
                    {
                        Square marblePiece = marbleSquares[pieceCombinations[c][j]];
                        pieceMoves[j] = new PieceMove(marblePiece, marblePiece.Add(pieceValues[k][j], team));

                        if (j > 0)
                        {
                            if (pieceMoves[j].From.Equals(pieceMoves[j - 1].To))
                            {
                                //Swap the move order
                                PieceMove current = pieceMoves[j];
                                pieceMoves[j]     = pieceMoves[j - 1];
                                pieceMoves[j - 1] = current;
                            }
                        }
                    }

                    Move move = new Move(pieceMoves, team);
                    moves.Add(move);
                }
            }

            return(moves);
        }
コード例 #9
0
ファイル: Board.cs プロジェクト: AustinJGreen/MarbleBoardGame
 /// <summary>
 /// Gets all the possible moves for a team given a dice roll
 /// </summary>
 /// <param name="roll">Dice roll</param>
 /// <param name="team">Marble team</param>
 public MoveCollection GetMoves(DiceRoll roll, sbyte team)
 {
     return(GetMoves(GetPosition(), roll, team));
 }
コード例 #10
0
        /// <summary>
        /// Updates the view of the board
        /// </summary>
        /// <param name="gameTime">Current GameTime</param>
        public void Update(GameTime gameTime)
        {
            //Update logic
            KeyboardState kState = Keyboard.GetState();
            MouseState    mState = MouseHandle.GetState();

            //Updates squares
            UpdateSquares();

            if (Playing)
            {
                //Update current animation
                if (currentAnimation != null)
                {
                    currentAnimation.Update(gameTime);
                }

                if (kState.IsKeyDown(Keys.Q) && rollOver)
                {
                    for (int i = 0; i < currentMove.Count; i++)
                    {
                        if (currentMove[i].IsTakingOutMarble)
                        {
                            PutBackMarble(currentPlayer.Team);
                        }
                    }

                    RemoveMove();
                }

                if (!currentPlayer.IsThinking && CanRoll())
                {
                    if (!currentPlayer.IsHuman)
                    {
                        rollOver = false;
                        RollDice(gameTime);
                    }
                    else if (!isDiceRolling && kState.IsKeyDown(Keys.R)) //Check for user starting a roll
                    {
                        rollOver = false;
                        RollDice(gameTime);
                    }
                }

                //Check if dice are done rolling
                if (die1 != -1 && die2 != -1 && !rollOver)
                {
                    currentRoll = new DiceRoll(die1, die2);
                    OnRollFinished();
                }

                //Check if dice have rolled for too long
                if (rollStartTime.HasValue)
                {
                    TimeSpan timeElapsed   = gameTime.TotalGameTime.Subtract(rollStartTime.Value);
                    double   timeElapsedMs = timeElapsed.TotalMilliseconds;
                    if (timeElapsedMs >= 10000)
                    {
                        StopDice();
                        UpdateDie(die1Body, ref die1, true);
                        UpdateDie(die2Body, ref die2, true);

                        if (die1 != -1 && die2 != -1)
                        {
                            currentRoll = new DiceRoll(die1, die2);
                            OnRollFinished();
                        }
                    }
                }

                //If the player is a human and hasnt rolled yet, disallow any movement of marbles
                if (!CanRoll())
                {
                    //Update drag
                    UpdateDrag(mState);

                    ////Handle user submitting move
                    if (rollOver && kState.IsKeyDown(Keys.Enter) && currentPlayer.IsHuman)
                    {
                        if (!HasMove)
                        {
                            //Pressed enter without making a move
                            MoveCollection collection = board.GetMoves(currentRoll, currentPlayer.Team);

                            if (collection.Count == 0)
                            {
                                //End the player step
                                ProcessRoll();
                                SetReadyForRoll();
                                //
                            }
                        }
                        else
                        {
                            if (currentRoll == null)
                            {
                                RemoveMove();
                            }
                            else
                            {
                                Move move = GetMove(currentPlayer.Team);
                                if (board.IsPossibleMove(currentRoll, move, out move))
                                {
                                    currentPlayer.SetMove(move);
                                }
                                else
                                {
                                    for (int i = 0; i < currentMove.Count; i++)
                                    {
                                        if (currentMove[i].IsTakingOutMarble)
                                        {
                                            PutBackMarble(currentPlayer.Team);
                                        }
                                    }

                                    RemoveMove();
                                }
                            }
                        }
                    }
                }

                if (currentPlayer.HasMove)
                {
                    OnMoveFound(currentPlayer.GetMove());
                }

                //Update dice
                UpdateDie(die1Body, ref die1, IsNearlyZero(die1Body.LinearVelocity));
                UpdateDie(die2Body, ref die2, IsNearlyZero(die2Body.LinearVelocity));

                if (!Resizing)
                {
                    world.Step(1 / 30f, false);
                    //world.Step((float)gameTime.TotalGameTime.TotalSeconds, false, (float)gameTime.ElapsedGameTime.TotalSeconds, 1);
                }
            }
        }
コード例 #11
0
 /// <summary>
 /// Creates a new position node
 /// </summary>
 /// <param name="value">Position value</param>
 /// <param name="roll">Dice roll</param>
 public PositionNode(Position value, Move move, DiceRoll roll) : this()
 {
     Value = value;
     Move  = move;
     Roll  = roll;
 }
コード例 #12
0
        public static sbyte SimulateGame()
        {
            Board     board     = new Board();
            Algorithm mpMix     = new MPMix(board, 1, 0.5);
            Algorithm maxN      = new MaxN(board);
            Algorithm paranoid  = new Paranoid(board);
            Algorithm offensive = new Offensive(board);
            Algorithm mcts      = new MCTS(board);

            int   doublesCount = 0;
            sbyte lastTeam     = 0;
            sbyte team         = 0;
            int   turns        = 0;

            while (!board.IsGameOver())
            {
                Console.Title = turns.ToString();
                lastTeam      = team;

                DiceRoll roll = board.GetRandomRoll();
                Move     m    = null;
                switch (team)
                {
                case 0:
                    m = board.ThinkBest(mcts, roll, team, 0);
                    break;

                case 1:
                    m = board.ThinkBest(maxN, roll, team, 0);
                    break;

                case 2:
                    m = board.ThinkBest(mcts, roll, team, 0);
                    break;

                case 3:
                    m = board.ThinkBest(mcts, roll, team, 0);
                    break;
                }
                if (m != null)
                {
                    board.PerformMove(m);
                }

                if (roll.IsDoubles())
                {
                    doublesCount++;
                    if (doublesCount >= 3)
                    {
                        board.RemoveFrontMarble(team);
                        doublesCount = 0;
                        team         = board.NextPlayer(team);
                        turns++;
                    }
                }
                else
                {
                    doublesCount = 0;
                    team         = board.NextPlayer(team);
                    turns++;
                }
            }

            Console.WriteLine("{0} won ({1} turns)", GetName(lastTeam), turns);
            return(lastTeam);
        }
コード例 #13
0
        /// <summary>
        /// Evaluates a teams overall score in units of scored marbles (5 = won)
        /// </summary>
        /// <param name="position">Position to evaluate for a team</param>
        /// <param name="team"></param>
        /// <returns></returns>
        public double EvaluateTeam(Position position, sbyte team, bool rolledDoubles)
        {
            //Score in units of scores (5 = won)
            double score = 0.0;

            const double marbleValue = 0.1;

            //Sorted list of marbles
            Square[] marbles           = GetMarbles(position, team);
            int      activeMarbles     = ActiveMarbles(marbles);
            int      activePathMarbles = ActivePathMarbles(marbles);

            int[]    activeEnemyMarbleCount = null;
            Square[] enemies = GetEnemyMarbles(position, team, out activeEnemyMarbleCount);

            //Evaluation scorelist
            //O-Check for impossible position with roll for 1 to win
            //O-Evaluate distance to goal)
            //O-Evaluate danger (probability of being taken) (Add special case for being on enemy spawn squares?)
            //O-Evaluate scored marbles (Add bonus for being aligned back in a row)

            //-Check for impossible position with roll for 1 to win
            if (activeMarbles == Board.TEAM_SIZE)
            {
                if (MustRollDoubles3x(position, team))
                {
                    return(DiceRoll.P_ROLLING_DOUBLES_3X);
                }
            }

            //-Evaluate distance to goal
            //-Pentalize marbles on own goal (for taking out)
            Square endGoal  = GetEndGoal(position, team);
            double endIndex = endGoal.GetBoardIndex(team);

            double distanceScore = 0.0;

            for (int i = 0; i < marbles.Length; i++)
            {
                if (marbles[i] != null)
                {
                    if (marbles[i].IsInPath())
                    {
                        if (marbles[i].GetBoardIndex(team) == 1)
                        {
                            score -= marbleValue;
                        }

                        double dis = (endIndex - marbles[i].DistanceTo(endGoal, team));
                        distanceScore += dis;
                    }
                }
            }

            //Add score for activity
            score += activeMarbles * marbleValue;

            //Add the distance traveled
            if (activeMarbles > 0)
            {
                score += (distanceScore - 1) / (double)(endIndex * activeMarbles);
            }

            //-Evaluate danger (probability of being taken) (Add special case for being on enemy spawn squares?)
            double dangerScore = 0.0f;

            if (!rolledDoubles)
            {
                //Add special case for being on enemy spawn squares
                for (int m = 0; m < marbles.Length; m++)
                {
                    if (marbles[m] != null)
                    {
                        double weight = 2 * ((endIndex - marbles[m].DistanceTo(endGoal, team)) / endIndex);
                        for (sbyte eT = 0; eT < Board.TEAM_COUNT; eT++)
                        {
                            if (eT != team)
                            {
                                int marbleCount = activeEnemyMarbleCount[eT];
                                if (marbleCount > 0)
                                {
                                    Square enemySpawn = new Square(eT, 0);
                                    if (marbles[m].Equals(enemySpawn))
                                    {
                                        dangerScore += weight * DiceRoll.P_GETTING_OUT;
                                    }
                                }
                            }
                        }
                    }
                }

                for (int x = 0; x < enemies.Length; x++)
                {
                    if (enemies[x] != null)
                    {
                        if (enemies[x].IsInPath())
                        {
                            for (int t = 0; t < marbles.Length; t++)
                            {
                                if (marbles[t] != null)
                                {
                                    if (marbles[t].IsInPath())
                                    {
                                        double weight = (endIndex - marbles[t].DistanceTo(endGoal, team)) / endIndex;

                                        int distance = marbles[t].DistanceTo(enemies[x], team);
                                        if (distance > 0)
                                        {
                                            if (distance <= 6)
                                            {
                                                int marbleTeam         = position.Get(enemies[x]);
                                                int activeEnemyMarbles = activeEnemyMarbleCount[marbleTeam]; //Active in path
                                                if (activeEnemyMarbles >= 2)
                                                {
                                                    dangerScore += weight * DiceRoll.P_ANY_NUM;
                                                }
                                                else if (activeEnemyMarbles >= 1)
                                                {
                                                    dangerScore += weight * (DiceRoll.P_ANY_NUM * DiceRoll.P_GETTING_OUT);
                                                }
                                                else
                                                {
                                                    double probability = DiceRoll.GetProbabilityQuick(distance);
                                                    dangerScore += weight * probability;
                                                }
                                            }
                                            else if (distance < 36) //If greater than, the probability is 0, so no danger
                                            {
                                                double probability = DiceRoll.GetProbabilityQuick(distance);
                                                dangerScore += weight * probability;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                //Subtract danger score
                score -= dangerScore;
            }

            double eDistanceScore = 0.0;
            double eDividendTotal = 0.0;
            int    eCount         = 0;

            //O-Evaluate other marbles
            for (sbyte sEM = 0; sEM < enemies.Length; sEM++)
            {
                if (enemies[sEM] != null)
                {
                    if (enemies[sEM].IsInPath())
                    {
                        sbyte  eTeam    = (sbyte)position.Get(enemies[sEM]);
                        Square eEndGoal = GetEndGoal(position, eTeam);

                        double eDividend = eEndGoal.GetBoardIndex(eTeam);
                        eDistanceScore += (eDividend - enemies[sEM].DistanceTo(eEndGoal, eTeam));

                        eDividendTotal += eDividend;
                        eCount++;
                    }
                }
            }

            if (eCount > 0)
            {
                //We don't want a full negative impact from enemy moves (between 1/2-3/4 scale factor)
                score -= 0.55 * (eDistanceScore / eDividendTotal);
            }

            //-Evaluate scored marbles (Add bonus for being aligned back in a row)
            bool inARow = true;

            int    marblesScored      = 0;
            double marblesScoredScore = 0; //Marbles as far back as possible = 1 score

            Square[] homeSquares = GetHomeSquares(team);
            for (int i = homeSquares.Length - 1; i >= 0; i--)
            {
                int marble = position.Get(homeSquares[i]);
                if (marble == team)
                {
                    if (inARow)
                    {
                        marblesScoredScore++;
                    }
                    else
                    {
                        marblesScoredScore += 0.5 + (0.5 / (double)(homeSquares.Length - i));
                    }

                    marblesScored++;
                }
                else
                {
                    //Gap, stop giving points
                    inARow = false;
                }
            }


            score += marblesScoredScore;

            return(score);
        }