/// <summary>
        /// Get directions where there's a playable move
        /// </summary>
        /// <param name="position">Position to check</param>
        /// <returns>List of directions</returns>
        public List <IntPosition> GetNeighborsDirections(IntPosition position)
        {
            List <IntPosition> directionsList = new List <IntPosition>();
            Player             currentPlayer  = playerTurn;
            Player             oppositePlayer = GetOppositePlayer(currentPlayer);

            for (int rowDelta = -1; rowDelta <= 1; rowDelta++)
            {
                for (int columnDelta = -1; columnDelta <= 1; columnDelta++)
                {
                    IntPosition nextPosition = new IntPosition(position.Column + columnDelta, position.Row + rowDelta);

                    if (IsPositionValid(nextPosition))
                    {
                        int slotContentId = gameBoard[nextPosition.Column, nextPosition.Row];

                        if ((position.Row != nextPosition.Row || position.Column != nextPosition.Column) &&
                            slotContentId == (int)oppositePlayer &&
                            IsPositionValid(nextPosition))
                        {
                            directionsList.Add(new IntPosition(columnDelta, rowDelta));
                        }
                    }
                }
            }

            return(directionsList);
        }
        /// <summary>
        /// Get a list of positions where a pawn has to be flipped, given the position where a new pawn is to be placed.
        /// This is basically the effect of a new move on the board.
        /// NB: the list does not contain the new pawn.
        /// </summary>
        /// <param name="pawnPosition">Pawn position</param>
        /// <returns>List of positions where to flip pawns</returns>
        public List <IntPosition> GetPawnsToFlip(IntPosition pawnPosition)
        {
            List <IntPosition> pawnsToFlip    = new List <IntPosition>();
            List <IntPosition> directionsList = GetNeighborsDirections(pawnPosition);

            foreach (IntPosition direction in directionsList)
            {
                List <IntPosition> currentPath = new List <IntPosition>();

                Player currentPlayer  = playerTurn;
                Player oppositePlayer = GetOppositePlayer(currentPlayer);

                IntPosition currentPosition = pawnPosition;
                currentPosition += direction;
                while (IsPositionValid(currentPosition) && gameBoard[currentPosition.Column, currentPosition.Row] == (int)oppositePlayer)
                {
                    currentPath.Add(currentPosition);
                    currentPosition += direction;
                }

                if (IsPositionValid(currentPosition) && gameBoard[currentPosition.Column, currentPosition.Row] == (int)currentPlayer)
                {
                    pawnsToFlip.AddRange(currentPath);
                }
            }

            return(pawnsToFlip);
        }
Exemple #3
0
        /// <summary>
        /// Implementation of negamax algorithm with alpha beta pruning. A node is represented by a game board.
        /// </summary>
        /// <param name="nodeBoard">A particular game state</param>
        /// <param name="depth">The maximum tree depth</param>
        /// <param name="parentValue">The parent node value</param>
        /// <param name="maximizingPlayer">Whether node is a maximizimer or minimizer. True if maximizer. </param>
        /// <returns>A tuple containing the value as it's first item and the position corresponding to the best
        /// predicted play as it's second item. </returns>
        private Tuple <int, IntPosition> AlphaBeta(BoardIA nodeBoard, int depth, int parentValue, bool maximizingPlayer)
        {
            if (depth == 0 || nodeBoard.IsTerminal())
            {
                var heuristicValue = nodeBoard.GetHeuristicValue();
                return(new Tuple <int, IntPosition>(heuristicValue, new IntPosition(-1, -1)));
            }
            else
            {
                int         bestValue = maximizingPlayer ? -int.MaxValue : int.MaxValue;
                IntPosition bestMove  = new IntPosition(-1, -1);

                var childPositions = nodeBoard.GetAllPossibleMoves();
                foreach (var child in childPositions)
                {
                    var childValue = AlphaBeta(PosToBoard(child, nodeBoard), depth - 1, bestValue, !maximizingPlayer);
                    int minOrMax   = maximizingPlayer ? 1 : -1;
                    if (childValue.Item1 * minOrMax > bestValue * minOrMax)
                    {
                        bestValue = childValue.Item1;
                        bestMove  = child;
                        if (bestValue * minOrMax > parentValue * minOrMax)
                        {
                            break;
                        }
                    }
                }
                return(new Tuple <int, IntPosition>(bestValue, bestMove));
            }
        }
        /// <summary>
        /// Initialize all the data of the game
        /// </summary>
        /// <param name="gridSize">Size of the board</param>
        /// <param name="initialPawnsPosition">Initial position of the pawns (top left corner)</param>
        public void InitAll(IntPosition gridSize, IntPosition initialPawnsPosition)
        {
            playerTurn = Player.Black;

            InitPlayersData();
            InitGameBoard(gridSize, initialPawnsPosition);
            InitTimer();
            moveHistory = new List <Tuple <List <IntPosition>, Player> >();
        }
Exemple #5
0
        /// <summary>
        /// Check whether the given position is legal.
        /// </summary>
        /// <param name="column">Column number of the position to check</param>
        /// <param name="line">Line number of the position to check</param>
        /// <param name="isWhite">True if player turn is white</param>
        /// <returns>True if move is legal</returns>
        public bool IsPlayable(int column, int line, bool isWhite)
        {
            Player currentPlayer = PlayerTurn;

            PlayerTurn = isWhite ? Player.White : Player.Black;
            IntPosition        positionToCheck = new IntPosition(column, line);
            List <IntPosition> playableSlots   = GetAllPossibleMoves();

            PlayerTurn = currentPlayer;
            return(playableSlots.Contains(positionToCheck));
        }
Exemple #6
0
        /// <summary>
        /// Check if a move is stable
        /// </summary>
        /// <param name="position">Position to check stability</param>
        /// <returns>True : stable, False : not stable</returns>
        private bool IsMoveStable(IntPosition position, bool isWhite)
        {
            int[,] gameBoardSave = CopyArray(GameBoard);
            List <IntPosition> result = new List <IntPosition>();
            int playerId = isWhite ? (int)Player.White : (int)Player.Black;

            GameBoard[position.Column, position.Row] = playerId;
            List <IntPosition> pawnsToFlip = GetPawnsToFlip(position);

            foreach (IntPosition pawnPos in pawnsToFlip)
            {
                GameBoard[pawnPos.Column, pawnPos.Row] = (int)(GetOppositePlayer((Player)playerId));
            }

            // Tests valid moves for the opposite players
            SwitchPlayer();

            for (int rowDelta = -1; rowDelta <= 1; rowDelta++)
            {
                for (int columnDelta = -1; columnDelta <= 1; columnDelta++)
                {
                    if (!(columnDelta == 0 && rowDelta == 0))
                    {
                        try
                        {
                            IntPosition nextPosition = new IntPosition(position.Column + columnDelta, position.Row + rowDelta);

                            while (IsPositionValid(nextPosition) && GameBoard[nextPosition.Column, nextPosition.Row] == playerId)
                            {
                                nextPosition = new IntPosition(nextPosition.Column + columnDelta, nextPosition.Row + rowDelta);
                            }

                            if (IsPositionValid(nextPosition) && GameBoard[nextPosition.Column, nextPosition.Row] == (int)GetOppositePlayer((Player)playerId))
                            {
                                if (IsPossibleMove(nextPosition, new IntPosition(-columnDelta, -rowDelta), result))
                                {
                                    GameBoard = gameBoardSave;
                                    SwitchPlayer();
                                    return(false);
                                }
                            }
                        }
                        catch (Exception exc)
                        {
                            Console.WriteLine(exc.Message);
                        }
                    }
                }
            }

            SwitchPlayer();
            GameBoard = gameBoardSave;
            return(true);
        }
Exemple #7
0
        /// <summary>
        /// Play a move and alter the board accordingly. Returns true if the move was legal.
        /// </summary>
        /// <param name="column">The column corresponding to the position of the move</param>
        /// <param name="line">The line corresponding to the position of the move</param>
        /// <param name="isWhite">True if the current player turn is white</param>
        /// <returns>True if move was legal.</returns>
        public bool PlayMove(int column, int line, bool isWhite)
        {
            PlayerTurn = isWhite ? Player.White : Player.Black;
            bool IsMoveValid = IsPlayable(column, line, isWhite);

            if (IsMoveValid)
            {
                IntPosition        slotPosition = new IntPosition(column, line);
                List <IntPosition> pawnsToFlip  = GetPawnsToFlip(slotPosition);
                pawnsToFlip.Add(slotPosition);
                UpdateSlots(pawnsToFlip);
            }
            return(IsMoveValid);
        }
        /// <summary>
        /// Gets the most recent move stored and plays it backwards.
        /// </summary>
        /// <returns>
        /// A tuple containing the coordinates of the affected slots, which
        /// player the move belongs to and the coordinates of the pawn that
        /// was added to the board (which now has to be removed).
        /// </returns>
        public Tuple <List <IntPosition>, Player, IntPosition> UndoMove()
        {
            var lastMove = moveHistory.Last();
            List <IntPosition> slotsToUndo      = lastMove.Item1;
            Player             moveAuthor       = lastMove.Item2;
            IntPosition        lastPawnPosition = slotsToUndo.Last();

            slotsToUndo.RemoveAt(slotsToUndo.Count - 1);
            foreach (var position in slotsToUndo)
            {
                GameBoard[position.Column, position.Row] = (int)GetOppositePlayer(moveAuthor);
            }
            GameBoard[lastPawnPosition.Column, lastPawnPosition.Row] = (int)SlotContent.Nothing;
            moveHistory.RemoveAt(moveHistory.Count - 1);
            return(Tuple.Create(slotsToUndo, moveAuthor, lastPawnPosition));
        }
        /// <summary>
        /// Init. the game board
        /// </summary>
        /// <param name="gridSize">Size of the board</param>
        /// <param name="initialPawnsPosition">Initial position of the pawns (top left corner)</param>
        public void InitGameBoard(IntPosition gridSize, IntPosition initialPawnsPosition)
        {
            gameBoard = new int[gridSize.Column, gridSize.Row];

            for (int row = 0; row < Rows; row++)
            {
                for (int column = 0; column < Columns; column++)
                {
                    gameBoard[column, row] = (int)SlotContent.Nothing;
                }
            }

            gameBoard[initialPawnsPosition.Column, initialPawnsPosition.Row]         = (int)SlotContent.White;
            gameBoard[initialPawnsPosition.Column + 1, initialPawnsPosition.Row]     = (int)SlotContent.Black;
            gameBoard[initialPawnsPosition.Column, initialPawnsPosition.Row + 1]     = (int)SlotContent.Black;
            gameBoard[initialPawnsPosition.Column + 1, initialPawnsPosition.Row + 1] = (int)SlotContent.White;
        }
Exemple #10
0
        /// <summary>
        /// Creates an AIBoard class given the position of a move to play
        /// and the board where the move has to be played.
        /// </summary>
        /// <param name="position">The position of the pawn to play on the board</param>
        /// <param name="sourceBoard">The board where the move takes place</param>
        /// <returns>A new AIBoard with the updated game state</returns>
        private BoardIA PosToBoard(IntPosition position, BoardIA sourceBoard)
        {
            int[,] gameState = new int[9, 7];
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 7; j++)
                {
                    gameState[i, j] = sourceBoard.GameBoard[i, j];
                }
            }

            BoardIA newBoard = new BoardIA
            {
                GameBoard  = gameState,
                PlayerTurn = sourceBoard.PlayerTurn
            };

            newBoard.PlayMove(position.Column, position.Row, sourceBoard.PlayerTurn == Player.White);
            newBoard.SwitchPlayer();
            return(newBoard);
        }
        /// <summary>
        /// Walk the game board to get all possible moves for the current player.
        /// </summary>
        /// <returns>
        /// A list containing the position of each playable slot.
        /// </returns>
        public List <IntPosition> GetAllPossibleMoves()
        {
            List <IntPosition> possibleMovesList = new List <IntPosition>();

            for (int rowIndex = 0; rowIndex < Rows; rowIndex++)
            {
                for (int columnIndex = 0; columnIndex < Columns; columnIndex++)
                {
                    IntPosition currentSlot   = new IntPosition(columnIndex, rowIndex);
                    int         slotContentId = gameBoard[currentSlot.Column, currentSlot.Row];
                    if (slotContentId == (int)playerTurn)
                    {
                        List <IntPosition> currentSlotPossibleMovesList = GetNeighborsDirections(currentSlot);
                        List <IntPosition> movements = new List <IntPosition>();
                        foreach (IntPosition direction in currentSlotPossibleMovesList)
                        {
                            if (IsPossibleMove(currentSlot, direction, movements))
                            {
                                IntPosition possibleMove = movements[movements.Count - 1];
                                possibleMovesList.Add(possibleMove);
                            }
                            movements.Clear();
                        }
                    }
                }
            }

            if (possibleMovesList.Count == 0)
            {
                SkipCurrentPlayerTurn();
            }
            else
            {
                CurrentPlayerData.HasSkippedLastTurn = false;
            }

            return(possibleMovesList);
        }
        /// <summary>
        /// Check if there's a valid move in the given direction, if true, the "positions" list is filled with all the positions of the valid move
        /// </summary>
        /// <param name="pawnPosition">Position to check</param>
        /// <param name="direction">Direction to check</param>
        /// <param name="positions">Empty list given by the user, filled with severals position if there's a valid move</param>
        /// <returns></returns>
        public bool IsPossibleMove(IntPosition pawnPosition, IntPosition direction, List <IntPosition> positions)
        {
            IntPosition currentPosition = pawnPosition;
            bool        result          = false;

            Player currentPlayer  = playerTurn;
            Player oppositePlayer = GetOppositePlayer(currentPlayer);

            positions.Add(pawnPosition);

            currentPosition += direction;
            while (IsPositionValid(currentPosition) && gameBoard[currentPosition.Column, currentPosition.Row] == (int)oppositePlayer)
            {
                positions.Add(currentPosition);
                currentPosition += direction;
            }

            if (result = IsPositionValid(currentPosition) && (gameBoard[currentPosition.Column, currentPosition.Row] == (int)SlotContent.Nothing))
            {
                positions.Add(currentPosition);
            }

            return(result);
        }
 /// <summary>
 /// Overloaded constructor: can define the size of the board and the initial position of the pawns (top left corner)
 /// </summary>
 /// <param name="gridSize">Size of the board</param>
 /// <param name="initialPawnsPosition">Initial position of the pawns (top left corner)</param>
 public OthelloLogic(IntPosition gridSize, IntPosition initialPawnsPosition)
 {
     InitAll(gridSize, initialPawnsPosition);
 }
 /// <summary>
 /// Check if the position is inside the board
 /// </summary>
 /// <param name="position">Position to check</param>
 /// <returns>True if the position is inside board, false otherwise</returns>
 public bool IsPositionValid(IntPosition position)
 {
     return(position.Row >= 0 && position.Row < Rows && position.Column >= 0 && position.Column < Columns);
 }