Beispiel #1
0
        public int SwitchPosition()
        {
            while (!WinChecker.HasWon(TokenType.Red) && !WinChecker.HasWon(TokenType.Black) && !Board.IsFull())
            {
                Console.Clear();
                Renderer.DrawHeader(_currentColumn, _currentType);
                Renderer.DrawBoard();
                var key = Console.ReadKey();
                if (key.Key != ConsoleKey.Enter)
                {
                    _currentColumn = key switch
                    {
                        { KeyChar : var k } when             k >= '1' && k <= '7' => k - '0' - 1,
                        { Key : ConsoleKey.LeftArrow } when  _currentColumn > 0 => _currentColumn - 1,
                        { Key : ConsoleKey.RightArrow } when _currentColumn < 6 => _currentColumn + 1,
                        var _ => _currentColumn,
                    };
                }
                else
                {
                    if (Board.CanAdd(_currentColumn))
                    {
                        Board.Add(_currentColumn, _currentType);
                        _currentType = _currentType == TokenType.Red ? TokenType.Black : TokenType.Red;
                    }
                }
            }

            return(_currentColumn);
        }
Beispiel #2
0
        //places the piece
        public bool PlacePiece(Point location, Colors piece)
        {
            if (isGameOver)
            {
                return(false);
            }

            int column = location.X / squareSize;

            if (column == columns)
            {
                column--;
            }

            int row = ProbeY(column);

            if (row == -1)
            {
                return(false);
            }
            squares[column, row] = piece;

            isGameOver = WinChecker.CheckForWin(squares, boardSize, winLength, ref wonXPos, ref wonYPos);

            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Gets the best move for the AI
        /// </summary>
        /// <param name="field">The field to look in</param>
        /// <param name="fieldSize">The size of the field</param>
        /// <param name="winLength">The length needed to win</param>
        /// <param name="currentPiece">The piece we are currently looking for</param>
        /// <param name="opponentPiece">The piece of the opponent, when looking from the current piece</param>
        /// <param name="depth">How deep we want to look</param>
        /// <param name="isMax">Whether the player we are looking for is the AI or not (true for AI, false for not AI)</param>
        /// <returns>The x-position of the best move</returns>
        protected static int GetBestMove(Pieces[,] field, Size fieldSize, int winLength, Pieces currentPiece, Pieces opponentPiece, int depth, bool isMax)
        {
            // If we are at max depth, we are going to score the field
            if (depth <= 0)
            {
                // If the current move is a winning move, give it the best value (relative to the current player)
                // We also add 100 to the min value, so there is a (small) difference between a losing move for the AI, and "you can't put a piece here" when probing for the y-position
                if (WinChecker.CheckForWin(field, fieldSize, winLength))
                {
                    return(isMax ? (int.MaxValue - searchDepth) : (int.MinValue + searchDepth + 100));
                }
                else
                {
                    int value = GetFieldValue(field, fieldSize, winLength, currentPiece, opponentPiece);
                    return(value);
                }
            }

            int[] moves = new int[fieldSize.Width];
            Pieces[,] testField;

            // Look through each x-position
            for (int x = 0; x < fieldSize.Width; x++)
            {
                // Find the y-position to put the piece at
                int y = ProbeY(field, fieldSize, x);

                // If that position is out of bounds, set it as least desirable for the current player
                if (y <= 1 || y >= fieldSize.Height)
                {
                    moves[x] = isMax ? int.MinValue : int.MaxValue;
                    continue;
                }

                // Copy the field
                testField = CopyField(field, fieldSize);

                // Place a piece at the location found
                testField[x, y] = currentPiece;

                // Check if that move was a win, if it is, we can set it as desirable
                // In order to give a difference in how many moves it takes to get to that win, we lower (or increase for the Min-player) the value by how many layers we are deep
                if (WinChecker.CheckForWin(testField, fieldSize, winLength))
                {
                    moves[x] = isMax ? (int.MaxValue - searchDepth + depth) : (int.MinValue + searchDepth - depth + 100);
                    continue;
                }

                // If it was not a winning move, look deeper
                moves[x] = GetBestMove(testField, fieldSize, winLength, opponentPiece, currentPiece, depth - 1, !isMax);
            }

            // Then, after looking at all the moves, the max player returns the maximum value, and the min player the minimum value
            return(isMax ? moves.Max() : moves.Min());
        }
Beispiel #4
0
        public static void Turn(Player player)
        {
            Game.ClearScreen();
            WriteLine("-------------------------------------------------------------------");
            WriteLine("Player Turn: " + player.GetPlayerNum());
            WriteLine("-------------------------------------------------------------------");

            Game.PrintBoard();
            PlayerPickColumn(player);
            WinChecker.CheckForWin(player);
        }
Beispiel #5
0
        private static void Main()
        {
            new Board();
            var             winChecker  = new WinChecker();
            const TokenType currentType = TokenType.Red;
            var             position    = new Position();

            var currentColumn = position.SwitchPosition();

            Console.Clear();
            Renderer.DrawHeader(currentColumn, currentType);
            Renderer.DrawBoard();
            winChecker.PrintWinConditions();
            Console.ReadKey();
        }
Beispiel #6
0
        /// <summary>
        /// Gets the best move for the AI
        /// </summary>
        /// <param name="field">The field to place a piece on</param>
        /// <param name="fieldSize">The size of the field</param>
        /// <param name="winLength">The length needed to win a game</param>
        /// <param name="currentPiece">The current piece to look for (the AI piece)</param>
        /// <param name="opponentPiece">The piece the opponent uses</param>
        /// <returns>The x-position of the best move</returns>
        protected static int GetBestMove(Pieces[,] field, Size fieldSize, int winLength, Pieces currentPiece, Pieces opponentPiece)
        {
            int[] moves = new int[fieldSize.Width];
            Pieces[,] testField;

            // Go through each x-position
            for (int x = 0; x < fieldSize.Width; x++)
            {
                // Find the y-position the piece will fall to
                int y = ProbeY(field, fieldSize, x);

                // If the piece is out-of-bounds, we can't place a piece here
                if (y <= -1 || y >= fieldSize.Height)
                {
                    moves[x] = int.MinValue;
                    continue;
                }

                // Makes a copy of the field
                testField = CopyField(field, fieldSize);

                // Places the current piece at the place
                testField[x, y] = currentPiece;

                // If that placement is a winning move, that means it is a move we really want to make, and that we won't have to look further after this move
                if (WinChecker.CheckForWin(testField, fieldSize, winLength))
                {
                    moves[x] = int.MaxValue;
                    continue;
                }

                // If it is not a winning move, look at all the possible moves after this and see how well they hold up
                moves[x] = GetBestMove(testField, fieldSize, winLength, opponentPiece, currentPiece, searchDepth - 1, false);
            }

            // Here, we look for the best index/indeces
            List <int> bestIndeces = new List <int>();
            int        bestValue   = int.MinValue;

            for (int i = 0; i < fieldSize.Width; i++)
            {
                if (moves[i] > bestValue)
                {
                    bestIndeces.Clear();
                    bestIndeces.Add(i);
                    bestValue = moves[i];
                }
                else if (moves[i] == bestValue)
                {
                    bestIndeces.Add(i);
                }
            }

            int bestIndex = 0;

            // After we have a list of indeces (which will be at least 1), we either get the best move if there is 1 move, or a random one of the best moves if there are more
            if (bestIndeces.Count == 1)
            {
                bestIndex = bestIndeces[0];
            }
            else if (bestIndeces.Count >= 2)
            {
                bestIndex = bestIndeces[random.Next(0, bestIndeces.Count)];
            }

            // There is a random chance the AI will make a random move
            // We do this at the end so that the AI will always seem to think, even when it will make a random move
            // We make a random move to give the opponent a more fair chance, otherwhise you would have to "trick" the AI in order to win
            if (random.Next(0, 100) <= randomMoveChance)
            {
                List <int> availableColumns = new List <int>();
                for (int x = 0; x < fieldSize.Width; x++)
                {
                    if (ProbeY(field, fieldSize, x) != -1)
                    {
                        availableColumns.Add(x);
                    }
                }

                bestIndex = availableColumns[random.Next(0, availableColumns.Count)];
            }

            return(bestIndex);
        }