Exemple #1
0
        /// <summary>
        /// Use some heuristics to evaluate how good a board position this is for the current player
        ///
        /// Positive scores indicate good outcomes, negative scores are bad
        /// </summary>
        /// <returns></returns>
        public double Evaluate(TakPiece.PieceColor currentPlayer)
        {
            double score = 0;

            TakPiece.PieceColor otherPlayer = currentPlayer == TakPiece.PieceColor.Black ? TakPiece.PieceColor.White : TakPiece.PieceColor.Black;

            // check for all victory conditions and return extreme values for any of them
            // (note that flats can result in a perfect draw, so we return 0 in that case
            if (Board.HasRoad(currentPlayer))
            {
                score = int.MaxValue;
            }
            else if (Board.HasRoad(otherPlayer))
            {
                score = int.MinValue;
            }
            else if (Board.IsFull() || Black.NumPieces == 0 || White.NumPieces == 0)
            {
                int flats = Board.FlatScore();
                if ((currentPlayer == TakPiece.PieceColor.White && flats > 0) ||
                    (currentPlayer == TakPiece.PieceColor.Black && flats < 0))
                {
                    score = int.MaxValue;
                }
                else if (flats != 0)
                {
                    score = int.MinValue;
                }
                else
                {
                    score = 0;
                }
            }
            else
            {
                // otherwise use a variety of metrics to evaluate the board state
                // TODO decide what these metrics are
                // some ideas:
                // - flat coverage
                // - length of longest path through board graph
                // - number of pieces along same row/column
                // - number of captives/reserves
                // - number of spaces threatened
                // - number of pieces that threaten each space
                // - number of 2x2 squares of our own pieces
                // - number of opposing pieces threatened
                // - number of own pieces threatened

                int flatScore      = Board.FlatScore() * (otherPlayer == TakPiece.PieceColor.White ? -10 : 10);
                int numSquares     = CountSquares(currentPlayer);
                int maxLine        = CountMostOrthogonalInRowOrColumn(currentPlayer);
                int mostFullRowCol = CountMostDistinctRowsOrColumns(currentPlayer);

                score = flatScore + numSquares + maxLine + mostFullRowCol;

                //Console.WriteLine("{0} = {1} {2} {3} {4}", score, deltaCoverage, deltaSquares, deltaOrtho, deltaDistinct);
            }

            return(score);
        }
Exemple #2
0
        /// <summary>
        /// Create a new player with the number of pieces necessary for the size of the board
        /// </summary>
        /// <param name="color"></param>
        /// <param name="boardSize"></param>
        public PlayerState(TakPiece.PieceColor color, int boardSize)
        {
            switch (boardSize)
            {
            case 3:
                NumPieces    = 10;
                NumCapstones = 0;
                break;

            case 4:
                NumPieces    = 15;
                NumCapstones = 0;
                break;

            case 5:
                NumPieces    = 21;
                NumCapstones = 1;
                break;

            case 6:
                NumPieces    = 30;
                NumCapstones = 1;
                break;

            case 7:
                NumPieces    = 40;
                NumCapstones = 2;
                break;

            case 8:
                NumPieces    = 50;
                NumCapstones = 2;
                break;
            }
        }
Exemple #3
0
        /// <summary>
        /// Get the winner, or null if it is a draw
        /// </summary>
        public TakPiece.PieceColor?Winner(TakPiece.PieceColor currentPlayer)
        {
            TakPiece.PieceColor otherPlayer = currentPlayer == TakPiece.PieceColor.White ? TakPiece.PieceColor.Black : TakPiece.PieceColor.White;

            // check road victories first (current player always wins if they made a road)
            if (Board.HasRoad(currentPlayer))
            {
                return(currentPlayer);
            }
            else if (Board.HasRoad(otherPlayer))
            {
                return(otherPlayer);
            }

            // if no roads, check the flat score
            int score = Board.FlatScore();

            if (score > 0)
            {
                return(TakPiece.PieceColor.White);
            }
            else if (score < 0)
            {
                return(TakPiece.PieceColor.Black);
            }
            else
            {
                return(null);
            }
        }
Exemple #4
0
 private TakMove(TakPiece.PieceColor player, int row, int column, MoveType type)
 {
     PieceColor = player;
     Row        = row;
     Column     = column;
     Type       = type;
 }
Exemple #5
0
 /// <summary>
 /// Direct access to each player's pieces by color
 /// </summary>
 /// <param name="player"></param>
 /// <returns></returns>
 public PlayerState this[TakPiece.PieceColor player]
 {
     get
     {
         if (player == TakPiece.PieceColor.White)
         {
             return(White);
         }
         else
         {
             return(Black);
         }
     }
 }
Exemple #6
0
        public bool HasRoad(TakPiece.PieceColor player)
        {
            BoardGraph g = new BoardGraph(this, player);

            for (int i = 0; i < Size; i++)
            {
                for (int j = 0; j < Size; j++)
                {
                    if (g.IsConnected(0, i, Size - 1, j) || // vertical road
                        g.IsConnected(i, 0, j, Size - 1))   // horizontal road
                    {
                        return(true);
                    }
                }
            }

            // we've checked every possibility, so return false
            return(false);
        }
Exemple #7
0
        /// <summary>
        /// Count the number of 2x2 squares of non-wall pieces we own
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        private int CountSquares(TakPiece.PieceColor player)
        {
            int count = 0;

            for (int i = 0; i < Board.Size - 1; i++)
            {
                for (int j = i; j < Board.Size - 1; j++)
                {
                    if ((Board[i, j].Owner == player && Board[i, j].Type != TakPiece.PieceType.Wall) &&
                        (Board[i + 1, j].Owner == player && Board[i + 1, j].Type != TakPiece.PieceType.Wall) &&
                        (Board[i, j + 1].Owner == player && Board[i, j + 1].Type != TakPiece.PieceType.Wall) &&
                        (Board[i + 1, j + 1].Owner == player && Board[i + 1, j + 1].Type != TakPiece.PieceType.Wall))
                    {
                        count++;
                    }
                }
            }

            return(count);
        }
Exemple #8
0
        /// <summary>
        /// Generate the list of all moves that the stack located at the given coordinate can make
        /// </summary>
        /// <param name="gameState"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        private static List <TakMove> GenerateStackMoves(TakPiece.PieceColor player, GameState gameState, int row, int column)
        {
            TakMove            m;
            List <TakMove>     moves    = new List <TakMove>();
            PieceStack         stack    = gameState.Board[row, column];
            List <List <int> > allDrops = new List <List <int> >();

            for (int n = 1; n <= Math.Min(stack.Size, gameState.Board.Size); n++) // for 1 to the carry limit of the board
            {
                allDrops.Clear();
                MakeDrops(n, allDrops, new List <int>());

                foreach (List <int> drops in allDrops)
                {
                    m = new TakMove(player, row, column, TakMove.MoveDirection.Left, drops);
                    if (m.IsLegal(gameState))
                    {
                        moves.Add(m);
                    }

                    m = new TakMove(player, row, column, TakMove.MoveDirection.Right, drops);
                    if (m.IsLegal(gameState))
                    {
                        moves.Add(m);
                    }

                    m = new TakMove(player, row, column, TakMove.MoveDirection.Up, drops);
                    if (m.IsLegal(gameState))
                    {
                        moves.Add(m);
                    }
                    m = new TakMove(player, row, column, TakMove.MoveDirection.Down, drops);
                    if (m.IsLegal(gameState))
                    {
                        moves.Add(m);
                    }
                }
            }

            return(moves);
        }
Exemple #9
0
        /// <summary>
        /// Count the number of distinct rows or columns we have pieces in
        ///
        /// i.e. if we have pieces in rows 0, 1, 4 and columns 2,3,4, and 5 we'll return 4
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        private int CountMostDistinctRowsOrColumns(TakPiece.PieceColor player)
        {
            int most = 0;
            int count;

            for (int i = 0; i < Board.Size; i++)
            {
                count = 0;
                for (int j = 0; j < Board.Size; j++)
                {
                    if (Board[i, j].Owner == player && Board[i, j].Type != TakPiece.PieceType.Wall)
                    {
                        count++;
                        break;
                    }
                }
                if (count > most)
                {
                    most = count;
                }

                count = 0;
                for (int j = 0; j < Board.Size; j++)
                {
                    if (Board[j, i].Owner == player && Board[j, i].Type != TakPiece.PieceType.Wall)
                    {
                        count++;
                        break;
                    }
                }
                if (count > most)
                {
                    most = count;
                }
            }

            return(most);
        }
Exemple #10
0
        public BoardGraph(TakBoard board, TakPiece.PieceColor player)
        {
            Vertices             = new List <Vertex>();
            VerticesByCoordinate = new Dictionary <Point, Vertex>();
            for (int i = 0; i < board.Size; i++)
            {
                for (int j = 0; j < board.Size; j++)
                {
                    if (board[i, j].Owner == player && !board[i, j].Top.IsWall)
                    {
                        Vertex v = new Vertex()
                        {
                            Row = i, Column = j
                        };

                        VerticesByCoordinate.Add(new Point(i, j), v);
                        Vertices.Add(v);
                    }
                }
            }

            for (int i = 0; i < Vertices.Count; i++)
            {
                Vertex p = Vertices[i];
                for (int j = i; j < Vertices.Count; j++)
                {
                    Vertex q = Vertices[j];

                    if ((Math.Abs(q.Row - p.Row) == 1 && q.Column == p.Column) ||
                        (Math.Abs(q.Column - p.Column) == 1 && q.Row == p.Row))
                    {
                        q.Adjacencies.Add(p);
                        p.Adjacencies.Add(q);
                    }
                }
            }
        }
Exemple #11
0
        /// <summary>
        /// Enumerate all legal moves possible for this player, given the state of the game
        ///
        /// Returned moves are unsorted (and are in fact shuffles to avoid any biases)
        /// </summary>
        /// <param name="player"></param>
        /// <param name="boardState"></param>
        /// <returns></returns>
        public static List <TakMove> EnumerateMoves(TakPiece.PieceColor player, GameState gameState)
        {
            TakMove        m;
            List <TakMove> moves = new List <TakMove>();

            TakPiece.PieceColor otherPlayer = player == TakPiece.PieceColor.Black ? TakPiece.PieceColor.White : TakPiece.PieceColor.Black;

            // first off, we can drop pieces on any open space on the board
            // if we're still evaluating moves it must mean we still have at least 1 piece to place
            for (int i = 0; i < gameState.Board.Size; i++)
            {
                for (int j = 0; j < gameState.Board.Size; j++)
                {
                    if (gameState.Board[i, j].Size == 0)
                    {
                        // from turn 1 on we place our own pieces and can place flats, capstones, or walls
                        if (gameState.TurnNumber > 0)
                        {
                            m = new TakMove(player, i, j, TakPiece.PieceType.Flat);
                            moves.Add(m);

                            m = new TakMove(player, i, j, TakPiece.PieceType.Wall);
                            moves.Add(m);

                            if (gameState[player].NumCapstones > 0)
                            {
                                m = new TakMove(player, i, j, TakPiece.PieceType.Capstone);
                                moves.Add(m);
                            }
                        }
                        else
                        {
                            // on turn 0 we can only place an opposing flat
                            m = new TakMove(otherPlayer, i, j, TakPiece.PieceType.Flat);
                            moves.Add(m);
                        }
                    }
                }
            }

            // generate all possible moves for each stack we own
            // this is only allowed from turn 1 onward
            if (gameState.TurnNumber > 0)
            {
                for (int i = 0; i < gameState.Board.Size; i++)
                {
                    for (int j = 0; j < gameState.Board.Size; j++)
                    {
                        if (gameState.Board[i, j].Owner == player)
                        {
                            List <TakMove> stackMoves = GenerateStackMoves(player, gameState, i, j);

                            foreach (TakMove tm in stackMoves)
                            {
                                moves.Add(tm);
                            }
                        }
                    }
                }
            }

            moves.Shuffle();
            return(moves);
        }
Exemple #12
0
 /// <summary>
 /// Create an AI to control the given pieces on the board
 /// </summary>
 /// <param name="ownColor"></param>
 /// <param name="sharedBoard"></param>
 public PlayerAI(TakPiece.PieceColor ownColor, GameState sharedGame)
 {
     MyColor    = ownColor;
     TheirColor = ownColor == TakPiece.PieceColor.White ? TakPiece.PieceColor.Black : TakPiece.PieceColor.White;
     Game       = sharedGame;
 }
Exemple #13
0
 public MoveTree(TakPiece.PieceColor player, GameState state)
 {
     MyColor    = player;
     TheirColor = player == TakPiece.PieceColor.Black ? TakPiece.PieceColor.White : TakPiece.PieceColor.Black;
     Root       = new RootNode(state);
 }
Exemple #14
0
        /// <summary>
        /// Parse a string representing a move
        ///
        /// See README.md for details on notation
        ///
        /// The notation should not contain any spaces
        /// </summary>
        /// <param name="player"></param>
        /// <param name="notation"></param>
        public TakMove(TakPiece.PieceColor player, string notation)
        {
            notation = notation.Trim();

            try
            {
                PieceColor = player;

                if (notation.Contains(">") || notation.Contains("<") || notation.Contains("-") || notation.Contains("+"))
                {
                    // if we contain any of the move symbols, assume we're a move

                    Type = MoveType.Move;

                    int    coordStart = FirstLetterAt(notation);
                    string coord = notation.Substring(coordStart, 2);
                    int    row, col;
                    ParseCoord(coord, out row, out col);
                    Row    = row;
                    Column = col;

                    char dir = notation[coordStart + 2];
                    switch (dir)
                    {
                    case '+':
                        Direction = MoveDirection.Up;
                        break;

                    case '-':
                        Direction = MoveDirection.Down;
                        break;

                    case '<':
                        Direction = MoveDirection.Left;
                        break;

                    case '>':
                        Direction = MoveDirection.Right;
                        break;
                    }

                    Drops = new List <int>();
                    string dropstring = notation.Substring(coordStart + 3);
                    foreach (char ch in dropstring)
                    {
                        Drops.Add(ch - '0');
                    }
                }
                else
                {
                    if (notation.Length == 2)
                    {
                        Piece = TakPiece.PieceType.Flat;

                        int row, col;
                        ParseCoord(notation, out row, out col);
                        Row    = row;
                        Column = col;
                    }
                    else
                    {
                        switch (notation.ToLower()[0])
                        {
                        case 's':
                            Piece = TakPiece.PieceType.Wall;
                            break;

                        case 'c':
                            Piece = TakPiece.PieceType.Capstone;
                            break;
                        }

                        int row, col;
                        ParseCoord(notation.Substring(1, 2), out row, out col);
                        Row    = row;
                        Column = col;
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception("Failed to parse move", e);
            }
        }
Exemple #15
0
 /// <summary>
 /// Create a move where we pick up a stack and drop pieces as we move in a direction
 ///
 /// The sum of all values in drops must equal the number of pieces picked up. So if
 /// we pick up a single piece and move it drops should be [1].
 ///
 /// If we pick up 6 pieces, and drop 1, 1, 2, 1 it should be [1, 1, 2, 1]
 /// </summary>
 /// <param name="player"></param>
 /// <param name="row"></param>
 /// <param name="column"></param>
 /// <param name="direction"></param>
 /// <param name="drops"></param>
 public TakMove(TakPiece.PieceColor player, int row, int column, MoveDirection direction, List <int> drops) : this(player, row, column, MoveType.Move)
 {
     Drops     = drops;
     Direction = direction;
 }
Exemple #16
0
 /// <summary>
 /// Create a placement move where we place a new piece on the location
 /// </summary>
 /// <param name="player"></param>
 /// <param name="row"></param>
 /// <param name="column"></param>
 /// <param name="piece"></param>
 public TakMove(TakPiece.PieceColor player, int row, int column, TakPiece.PieceType piece = TakPiece.PieceType.Flat) : this(player, row, column, MoveType.Place)
 {
     Piece = piece;
 }