// Calls minimax for each possible move and returns best move
        public static int FindBestMove(Connect4Game connect4, Connect4Board startBoard, int maxDepth)
        {
            MiniMaxVanilla.maxDepth = maxDepth;
            MiniMaxVanilla.connect4 = connect4;
            int player = MAXIMIZING;

            List <MoveScore> results = new List <MoveScore>();

            Console.WriteLine("Move scores {move, score}: ");
            foreach (int move in connect4.GetPossibleMoves(startBoard))
            {
                Connect4Board nextBoard   = connect4.SimulateMove(startBoard, player, move);
                int           searchScore = MiniMaxSearch(nextBoard, player * -1, 1);
                Console.Write("{" + move + ", " + searchScore + "} ,  ");

                results.Add(new MoveScore()
                {
                    move = move, score = searchScore
                });
            }
            int decidedMove = DecideMove(results);

            Console.WriteLine("Move chosen: " + decidedMove);
            return(decidedMove);
        }
Exemple #2
0
        static int FindMove(Connect4Board board)
        {
            int iterativeDepth = 0;
            int bestMove = 0, tempBestMove = 0;

            while (true)
            {
                iterativeDepth++;
                Console.WriteLine("Depth: " + (iterativeDepth));
                tempBestMove = MiniMaxAlphaBetaHeuristic.FindBestMove(connect4, new Con4Board(board), iterativeDepth);
                if (timesUp)
                {
                    timesUp       = false;
                    averageDepth += iterativeDepth - 1;
                    averageDepthCounts++;
                    Console.WriteLine("Depth " + iterativeDepth + " aborted!");
                    return(bestMove);
                }

                bestMove = tempBestMove;

                if (gameOutcomeFinal)   // 100% win/lose in sight, don't search deeper. Or if only 1 viable option
                {
                    gameOutcomeFinal = false;
                    t.Abort();
                    return(bestMove);
                }
            }
            //return MiniMaxAlphaBetaHeuristic.FindBestMove(connect4, new Con4Board(board), depth);
        }
 public void ColumnFullReturnsTrueIfFull()
 {
     var board = new Connect4Board(2, 2);
     board.Columns[0][0].PlayerIndex = 1;
     board.Columns[0][1].PlayerIndex = 1;
     Assert.IsTrue(board.ColumnFull(1));
 }
        // Returns best score found for current player
        private static int MiniMaxSearch(Connect4Board currentBoard, int player, int depth)
        {
            BoardState boardState = connect4.EvaluateBoard(currentBoard);

            // End game if max depth reached or game is over
            if (depth == maxDepth || boardState != BoardState.ongoing)
            {
                return(Evaluate.EvaluateBoardSimple(boardState, depth));
            }

            int searchScore = player == MAXIMIZING ? int.MinValue : int.MaxValue;

            foreach (int move in connect4.GetPossibleMoves(currentBoard))
            {
                Connect4Board nextBoard = connect4.SimulateMove(currentBoard, player, move);

                if (player == MAXIMIZING)
                {
                    searchScore = Math.Max(searchScore, MiniMaxSearch(nextBoard, MINIMIZING, depth + 1));
                }
                else
                {
                    searchScore = Math.Min(searchScore, MiniMaxSearch(nextBoard, MAXIMIZING, depth + 1));
                }
            }
            return(searchScore);
        }
Exemple #5
0
        protected override async Task <InnerMoveResult> HandleAsync(Connect4MoveData moveData, int playerId)
        {
            var serializedBoard = await boardLoader.LoadByMatchIdAsync(moveData.MatchId);

            var board = new Connect4Board();

            board.DeserializeContent(serializedBoard);

            var item = playerId == 0 ? Item.Red : Item.Yellow;

            board.PlaceItem(item, moveData.Column);
            serializedBoard.BoardData = board.SerializeContent().BoardData;
            var result = new InnerMoveResult
            {
                MoveResult = new Connect4MoveResult
                {
                    Board = board.Board
                }
            };

            if (board.CheckWinner() == item)
            {
                result.Status = Status.Win;
                return(result);
            }

            if (board.Full)
            {
                result.Status = Status.Draw;
                return(result);
            }

            result.Status = Status.Success;
            return(result);
        }
Exemple #6
0
 private void Connect4BoardOnMouseMove(object sender, MouseEventArgs e)
 {
     if (Game.GameStatus != GameStatusType.BlackWin && Game.GameStatus != GameStatusType.RedWin)
     {
         CurrentHover = GetAvailableInRow(e.Location.X);
     }
     Connect4Board.Refresh();
 }
 public void AddCounterAddsToCorrectRowAndColumnPopulatedBoard()
 {
     var board = new Connect4Board(5, 2);
     board.Columns[0][0].PlayerIndex = 1;
     board.Columns[0][1].PlayerIndex = 2;
     board.AddCounter(1, 1);
     Assert.AreEqual(1, board.Columns[0][2].PlayerIndex);
 }
 public override int GetColumnSelected(Func<string> QueryPlayer, Action<object> WriteLinetoDisplay, Connect4Board board)
 {
     WriteLinetoDisplay("The computer is thinking");
     Thread.Sleep(2000);
     int column = rand.Next(1, board.ColumnCount+1);
     while (board.ColumnFull(column))
         column = rand.Next(1, board.ColumnCount+1);
     return column;
 }
 public void CreateBuildsCorrectArrays()
 {
     var board = new Connect4Board(5, 2);
     Assert.AreEqual(2, board.ColumnCount);
     Assert.AreEqual(5, board.RowCount);
     Assert.AreEqual(2,board.Columns.Length);
     Assert.AreEqual(5, board.Columns[0].Length);
     Assert.AreEqual(5, board.Columns[1].Length);
 }
Exemple #10
0
    // Use this for initialization
    void Start()
    {
        _board    = new Connect4Board(COLUMNS, COLUMN_SIZE);
        mouseCell = new Vector3Int(-1, COLUMN_SIZE, 0);

        exitBtn.onClick.AddListener(OnExitBtnClick);
        resetBtn.onClick.AddListener(OnResetBtnClick);

        difficultyDropdown.onValueChanged.AddListener(OnDifficultyChange);
    }
 public void AddMultipleCounters()
 {
     var board = new Connect4Board(5, 2);
     board.AddCounter(1, 1);
     board.AddCounter(2, 1);
     board.AddCounter(3, 2);
     Assert.AreEqual(1, board.Columns[0][0].PlayerIndex);
     Assert.AreEqual(2, board.Columns[0][1].PlayerIndex);
     Assert.AreEqual(3, board.Columns[1][0].PlayerIndex);
 }
        private static void DrawMove(Connect4Board board, int selectedColumn, int cursorLeft, int cursorTop, Player humanPlayer)
        {
            var boardState = board.Clone().State;

            Console.CursorVisible = false;
            var emptyPositions = boardState.Columns[selectedColumn].Count(player => player == Player.None);

            Console.SetCursorPosition(cursorLeft, cursorTop + emptyPositions);
            Console.Write(Connect4Board.FromPlayerToString(humanPlayer));
        }
Exemple #13
0
        public override Connect4MoveResult Convert(SerializedConnect4Board serializedBoard)
        {
            var board = new Connect4Board();

            board.DeserializeContent(serializedBoard);

            return(new Connect4MoveResult
            {
                Board = board.Board
            });
        }
Exemple #14
0
 public Con4Board(Connect4Board board)
 {
     grid = new int[WIDTH, HEIGHT];
     for (int x = 0; x < WIDTH; x++)
     {
         for (int y = 0; y < HEIGHT; y++)
         {
             grid[x, y] = board.GetCell(x, y);
         }
     }
 }
Exemple #15
0
        private void RestartButton_Click(object sender, EventArgs e)
        {
            Game.RestartGame();
            Connect4Board.Refresh();
            var AIColour = UserPlayer == PlayerColor.Red ? PlayerColor.Black : PlayerColor.Red;

            AI = new MCTSAI(false, AIColour);
            if (AIColour == PlayerColor.Red)
            {
                AI.MakeMove(Game);
            }
        }
Exemple #16
0
    // Use this for initialization
    void Start()
    {
        players = FindObjectsOfType <Player>();
        if (players.Length == 0)
        {
            players    = new Player[1];
            players[0] = Instantiate(dummyPlayer);
        }
        players[activePlayerIndex].isActive = true;

        board = FindObjectOfType <Connect4Board>();
    }
    protected override void Start()
    {
        base.Start();

        for (int i = 0; i < actions.Length; i++)
        {
            actions[i].action = i;
        }

        policyValueNet = new Connect4PolicyValueNet();
        mctsPlayer     = new MCTSPlayer(policyValueNet);
        board          = new Connect4Board();
    }
 public override int GetColumnSelected(Func<string> QueryPlayer, Action<object> WriteLineToDisplay, Connect4Board board)
 {
     var columnSelected =  QueryPlayer();
     int column = 0;
     while (!Int32.TryParse(columnSelected, out column) ||
         column < 1||
         column > board.ColumnCount ||
         board.ColumnFull(column))
     {
         WriteLineToDisplay(String.Format("Please enter a number between 1 and {0} where column is not full.", board.ColumnCount));
         columnSelected = QueryPlayer();
     }
     return column;
 }
Exemple #19
0
        // Returns best score found for current player
        private static int MiniMaxSearch(Connect4Board currentBoard, int player, int depth, int a, int b) {

            BoardState boardState = connect4.EvaluateBoard(currentBoard);
            // End game if max depth reached or game is over
            if (depth == maxDepth || boardState != BoardState.ongoing)
                return Evaluate.EvaluateBoardSimple(boardState, depth);

            int searchScore = player == MAXIMIZING ? int.MinValue : int.MaxValue;

            foreach (int move in connect4.GetPossibleMoves(currentBoard).OrderBy(x => rand.Next()).ToList()) {
                Connect4Board nextBoard = connect4.SimulateMove(currentBoard, player, move);

                if (player == MAXIMIZING) {
                    searchScore = Math.Max(searchScore, MiniMaxSearch(nextBoard, MINIMIZING, depth + 1, a, b));
                    a = Math.Max(a, searchScore);
                    if (a >= b) 
                        break;
                    
                    /*
                    if (searchScore >= b) // Minimizing parent will not choose this path, beta cutoff
                        break;
                    a = Math.Max(a, searchScore);
                    */

                } else {
                    searchScore = Math.Min(searchScore, MiniMaxSearch(nextBoard, MAXIMIZING, depth + 1, a, b));
                    b = Math.Min(b, searchScore);
                    if (b <= a)
                        break;
                    /*
                    if (searchScore <= a) // Maximizing parent will not choose this path, alpha cutoff
                        break;
                    b = Math.Min(b, searchScore);
                    */

                }
            }
            return searchScore;

        }
        private static void PrintBoard(Connect4Board board, Player humanPlayer)
        {
            Console.Clear();
            var cursorTop = Console.WindowHeight - 9;

            Console.SetCursorPosition(0, cursorTop);

            Console.Write("CONNECT 4\n");
            Console.Write("\n");
            Console.Write("Players:\n");
            Console.Write("\n");
            Console.Write($"* You: {Connect4Board.FromPlayerToString(humanPlayer)}\n");
            Console.Write($"* Computer: {Connect4Board.FromPlayerToString(humanPlayer.ToOppositePlayer())}\n");
            Console.Write("\n");
            Console.Write("How to play:\n");
            Console.Write("\n");
            Console.Write("* Select a column and click enter to drop your chip.\n");
            Console.Write("* Type Q to exit.\n");
            Console.Write("\n\n");
            Console.Write(board);
            Console.Write("\n");
        }
Exemple #21
0
        private void Connect4Board_Click(object sender, MouseEventArgs e)
        {
            var available = GetAvailableInRow(e.Location.X);

            if (available != null && Game.GameStatus != GameStatusType.BlackWin && Game.GameStatus != GameStatusType.RedWin)
            {
                Game.PutInColumn(available.Item2, UserPlayer);
                Connect4Board.Refresh();
                if (Game.GameStatus != GameStatusType.Started && Game.GameStatus != GameStatusType.Initialised)
                {
                    MessageBox.Show("Koniec gry. Wygrały " + (Game.GameStatus == GameStatusType.BlackWin ? "czerwone" : "zolte") + ".");
                }
                else
                {
                    AI.MakeMove(Game);
                    Connect4Board.Refresh();
                    if (Game.GameStatus != GameStatusType.Started && Game.GameStatus != GameStatusType.Initialised)
                    {
                        MessageBox.Show("Koniec gry. Wygrały " + (Game.GameStatus == GameStatusType.BlackWin ? "czerwone" : "zolte") + ".");
                    }
                }
            }
        }
Exemple #22
0
        // Calls minimax for each possible move and returns best move
        public static int FindBestMove(Connect4Game connect4, Connect4Board startBoard, int maxDepth) {
            MiniMaxAlphaBeta.maxDepth = maxDepth;
            MiniMaxAlphaBeta.connect4 = connect4;
            int player = MAXIMIZING;
            int a = int.MinValue;
            int b = int.MaxValue;

            List<MoveScore> results = new List<MoveScore>();

            Console.WriteLine("\nMove scores {move, score, a}: ");
            foreach (int move in connect4.GetPossibleMoves(startBoard).OrderBy(x => rand.Next()).ToList()) {
                Connect4Board nextBoard = connect4.SimulateMove(startBoard, player, move);
                int searchScore = MiniMaxSearch(nextBoard, MINIMIZING, 1, a, b);
                // UPDATE ALPHA
                a = Math.Max(a, searchScore);
                Console.Write("{" + move + ", " + searchScore + ", " + a + "} ,  ");
                results.Add(new MoveScore() { move = move, score = searchScore });
            }
            int decidedMove = DecideMove(results);
            Console.WriteLine("Move chosen: " + decidedMove);
            return decidedMove;

        }
 public abstract int GetColumnSelected(Func<string> QueryPlayer, Action<object> WriteLineToDisplay, Connect4Board board);
 public void ColumnFullReturnsFalseIfNotFull()
 {
     var board = new Connect4Board(2, 2);
     Assert.IsFalse(board.ColumnFull(1));
 }
 public void CreateBuildsEmptyBoard()
 {
     var board = new Connect4Board(5, 2);
     //check board is empty
     Assert.IsTrue(board.Columns.All(x => x.All(y => y.PlayerIndex ==0)));
 }
        private static async Task PlayConnect4(TwoPlayerZeroSumGameMovesEngine gameEngine, bool humanIsFirstPlayer = true)
        {
            var humanPlayer = humanIsFirstPlayer ? Player.First : Player.Second;
            var board       = new Connect4Board(gameEngine);

            PrintBoard(board, humanPlayer);

            if (!humanIsFirstPlayer)
            {
                Console.CursorVisible = false;
                Console.SetCursorPosition(0, Console.WindowHeight);
                Console.Write("Calculating first move...");

                var firstMoveResult = await gameEngine.CalculateBestMove <Connect4Board, Connect4MoveInfo, Connect4BoardState>(board, Player.First).ConfigureAwait(false);

                var firstMove = firstMoveResult.BestMove;
                gameEngine.TryMakeMove <Connect4Board, Connect4MoveInfo, Connect4BoardState>(board, firstMove, false);

                PrintBoard(board, humanPlayer);
            }

            var selectedColumn = 0;

            var gameResult = GameResult.StillGame;

            while (gameResult == GameResult.StillGame)
            {
                var cursorLeft = 2 + (2 * selectedColumn);
                var cursorTop  = Console.WindowHeight - 9;
                Console.SetCursorPosition(cursorLeft, cursorTop);
                Console.CursorVisible = true;

                var keyInfo = Console.ReadKey();
                Console.SetCursorPosition(cursorLeft, cursorTop);

                switch (keyInfo.Key)
                {
                case ConsoleKey.LeftArrow:
                    selectedColumn = selectedColumn > 0 ? selectedColumn - 1 : selectedColumn;
                    break;

                case ConsoleKey.RightArrow:
                    selectedColumn = selectedColumn < (board.Clone().State.Columns.Length - 1)
                            ? selectedColumn + 1
                            : selectedColumn;
                    break;

                case ConsoleKey.Enter:
                    DrawMove(board, selectedColumn, cursorLeft, cursorTop, humanPlayer);
                    Console.SetCursorPosition(0, Console.WindowHeight);
                    Console.Write("Calculating move...");
                    var humanMove = new Connect4MoveInfo(humanPlayer, selectedColumn);
                    await gameEngine.MakeMoveAgainstMachine <Connect4Board, Connect4MoveInfo, Connect4BoardState>(board, humanMove).ConfigureAwait(false);

                    gameResult = board.GetGameResult(humanMove.Player);
                    PrintBoard(board, humanPlayer);
                    break;

                case ConsoleKey.Q:
                    PrintBoard(board, humanPlayer);
                    return;

                default:
                    PrintBoard(board, humanPlayer);
                    break;
                }

                Console.SetCursorPosition(cursorLeft, cursorTop);
                Console.CursorVisible = true;
            }

            PrintGameResult(gameResult);
            await PlayConnect4(gameEngine, !humanIsFirstPlayer);
        }
Exemple #27
0
 public void Init()
 {
     board = new Connect4Board(Width, Height);
 }
Exemple #28
0
        public Albot.BoardState EvaluateBoard()   // SHOULD BE LOCAL IMPLEMENTATION
        {
            Connect4Board board = new Connect4Board(grid);

            return(Program.connect4.EvaluateBoard(board));
        }
Exemple #29
0
        private static int DecideMove(Connect4Board board)
        {
            Con4Board con4Board = new Con4Board(board);

            return(MCTS.FindMove(con4Board, 9000));
        }
Exemple #30
0
    Move MaxPlay(Connect4Board board, int depth, int alpha = int.MinValue, int beta = int.MaxValue)
    {
        if (depth == 0 || board.Done)
        {
            return new Move {
                       Column = -1, Score = board.EvalScore()
            }
        }
        ;

        var maxMove = new Move {
            Column = -1, Score = int.MinValue
        };
        var possibleColumns = board.GetAvailableColumns();

        for (var i = 0; i < possibleColumns.Count; i++)
        {
            var col      = possibleColumns[i];
            var newBoard = board.GetNewState(BoardTile.CPU, col);

            var nextMove = MinPlay(newBoard, depth - 1, alpha, beta);

            if (maxMove.Column == -1 || nextMove.Score > maxMove.Score)
            {
                maxMove.Column = col;
                maxMove.Score  = nextMove.Score;
                alpha          = nextMove.Score;
            }

            if (alpha >= beta)
            {
                return(maxMove);
            }
        }

        return(maxMove);
    }

    Move MinPlay(Connect4Board board, int depth, int alpha = int.MinValue, int beta = int.MaxValue)
    {
        if (depth == 0 || board.Done)
        {
            return new Move {
                       Column = -1, Score = board.EvalScore()
            }
        }
        ;

        var minMove = new Move {
            Column = -1, Score = int.MaxValue
        };
        var possibleColumns = board.GetAvailableColumns();

        for (var i = 0; i < possibleColumns.Count; i++)
        {
            var col      = possibleColumns[i];
            var newBoard = board.GetNewState(BoardTile.Player, col);

            var nextMove = MaxPlay(newBoard, depth - 1, alpha, beta);

            if (minMove.Column == -1 || nextMove.Score < minMove.Score)
            {
                minMove.Column = col;
                minMove.Score  = nextMove.Score;
                beta           = nextMove.Score;
            }

            if (alpha >= beta)
            {
                return(minMove);
            }
        }

        return(minMove);
    }
}