예제 #1
0
        // 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);
        }
예제 #2
0
        public void TestMethodCanWinDiagonallyDown()
        {
            // AAA

            // arrange
            Connect4Game game = new Connect4Game();

            // act
            game.dropPieceInColumn(3);
            game.dropPieceInColumn(2);
            game.dropPieceInColumn(2);
            game.dropPieceInColumn(2);
            game.dropPieceInColumn(1);
            game.dropPieceInColumn(1);
            game.dropPieceInColumn(1);
            game.dropPieceInColumn(0);
            game.dropPieceInColumn(0);
            game.dropPieceInColumn(0);
            game.dropPieceInColumn(0);

            bool actualIsGameOver = game.isGameOver();

            // assert
            Assert.IsTrue(actualIsGameOver);
        }
        public void ProcessNextPlayerCallsCorrectMethods()
        {
            var player1 = MockRepository.GenerateMock<Connect4Player>();
            var player2 = MockRepository.GenerateMock<Connect4Player>();
            var game = new Connect4Game(6, 7, player1, player2);
            var writer = MockRepository.GenerateMock<WithWriteMethod>();
            game.WriteLineToDisplay = writer.WriteLineToDisplay;
            //expect a write to screen
            writer.Expect(x => x.WriteLineToDisplay(Arg<object>.Is.Anything));
            //expect a query ofplayer one
            player1.Expect(x => x.GetColumnSelected(Arg<Func<string>>.Is.Anything,
                                                    Arg<Action<object>>.Is.Anything,
                                                    Arg<Connect4Board>.Is.Anything)).Return(1);
            //expect no query pf player 2
            player2.Expect(x => x.GetColumnSelected(Arg<Func<string>>.Is.Anything,
                                                    Arg<Action<object>>.Is.Anything,
                                                    Arg<Connect4Board>.Is.Anything))
                                                    .Repeat.Never().Return(1);

            game.ProcessNextPlayer();

            writer.VerifyAllExpectations();
            player1.VerifyAllExpectations();
            player2.VerifyAllExpectations();
        }
 public void CanCreateGame()
 {
     IPlayer player1 = MockRepository.GenerateMock<Connect4Player>();
     IPlayer player2 = MockRepository.GenerateMock<Connect4Player>();
     var game = new Connect4Game(rows: 7, columns: 6, player1: player1, player2: player2);
     Assert.IsNotNull(game);
     Assert.IsInstanceOfType(game, typeof(IGame));
     Assert.IsInstanceOfType(game, typeof(Connect4Game));
 }
예제 #5
0
        public void TestMethodNewGameIsNotOver()
        {
            // AAA

            // arrange
            Connect4Game game = new Connect4Game();

            // act
            bool isGameOver = game.isGameOver();

            // assert
            Assert.IsFalse(isGameOver);
        }
예제 #6
0
        public void TestMethodGetCurrentPlayer()
        {
            // AAA

            // arrange
            Connect4Game game = new Connect4Game();
            Piece        expectedCurrentPlayer = Piece.Red;

            // act
            Piece actualCurrentPlayer = game.getCurrentPlayer();

            // assert
            Assert.AreEqual(expectedCurrentPlayer, actualCurrentPlayer);
        }
예제 #7
0
        public void TestMethodGetPieceAt()
        {
            // AAA

            // arrange
            Connect4Game game = new Connect4Game();
            Piece        expectedPieceColor = Piece.Red;

            // act
            game.dropPieceInColumn(0);
            Piece actualPieceColor = game.getPieceAt(5, 0);

            // assert
            Assert.AreEqual(expectedPieceColor, actualPieceColor);
        }
예제 #8
0
        public void TestMethodDropPieceAndCurrentPlayerChanges()
        {
            // AAA

            // arrange
            Connect4Game game = new Connect4Game();
            Piece        expectedCurrentPlayer = Piece.Green;

            // act
            game.dropPieceInColumn(0);
            Piece actualCurrentPlayer = game.getCurrentPlayer();

            // assert
            Assert.AreEqual(expectedCurrentPlayer, actualCurrentPlayer);
        }
예제 #9
0
        public void TestMethodCanWinVertically()
        {
            // AAA

            // arrange
            Connect4Game game = new Connect4Game();

            // act
            for (int columnIndex = 0; columnIndex < 8; columnIndex++)
            {
                game.dropPieceInColumn(columnIndex % 2);
            }
            bool actualIsGameOver = game.isGameOver();

            // assert
            Assert.IsTrue(actualIsGameOver);
        }
예제 #10
0
        public async Task Connect4PreGameSetup(GameUser p2, int bet, Connect4Game currentLobby)
        {
            var player1 = GameService.GetGameUser(Context.User.Id, Context.Guild.Id);
            var player2 = GameService.GetGameUser(p2.UserId, Context.Guild.Id);

            var lines = new int[6, 7];

            var embed = new EmbedBuilder();

            // Here we build the initial game board with all empty squares
            for (var r = 0; r < 6; r++)
            {
                if (r == 0)
                {
                    for (var c = 0; c < 7; c++)
                    {
                        embed.Description += $":{numlist[c]}:";
                    }

                    embed.Description += "\n";
                }

                for (var c = 0; c < 7; c++)
                {
                    embed.Description += $"{none}";
                }

                embed.Description += "\n";
            }

            embed.Description += "Usage:\n" +
                                 "`connect4 [column]`\n" +
                                 $":large_blue_circle: - {Context.User.Mention} <-\n" +
                                 $":red_circle: - {Context.Guild.GetUser(player2.UserId)?.Mention}";
            embed.Footer = new EmbedFooterBuilder
            {
                Text = $"it is {Context.User.Username}'s turn"
            };

            var gamemessage = await ReplyAsync("", false, embed.Build());

            await Connect4PlayingTask(lines, gamemessage, player1, player2, bet, embed, currentLobby);
        }
예제 #11
0
            public async Task ExecuteGroupAsync(CommandContext ctx,
                                                [Description("desc-game-movetime")] TimeSpan?moveTime = null)
            {
                if (moveTime?.TotalSeconds is < 2 or > 120)
                {
                    throw new InvalidCommandUsageException(ctx, "cmd-err-game-movetime", 2, 120);
                }

                if (this.Service.IsEventRunningInChannel(ctx.Channel.Id))
                {
                    throw new CommandFailedException(ctx, "cmd-err-evt-dup");
                }

                DiscordUser?opponent = await ctx.WaitForGameOpponentAsync();

                if (opponent is null)
                {
                    throw new CommandFailedException(ctx, "cmd-err-game-op-none", ctx.User.Mention);
                }

                var game = new Connect4Game(ctx.Client.GetInteractivity(), ctx.Channel, ctx.User, opponent, moveTime);

                this.Service.RegisterEventInChannel(game, ctx.Channel.Id);
                try {
                    await game.RunAsync(this.Localization);

                    if (game.Winner is { })
                    {
                        if (game.IsTimeoutReached)
                        {
                            await ctx.ImpInfoAsync(this.ModuleColor, Emojis.Trophy, "str-game-timeout", game.Winner.Mention);
                        }
                        else
                        {
                            await ctx.ImpInfoAsync(this.ModuleColor, Emojis.Trophy, "fmt-winners", game.Winner.Mention);
                        }

                        GameStatsService gss = ctx.Services.GetRequiredService <GameStatsService>();
                        await gss.UpdateStatsAsync(game.Winner.Id, s => s.Connect4Won++);

                        await gss.UpdateStatsAsync(game.Winner == ctx.User?opponent.Id : ctx.User.Id, s => s.Connect4Lost++);
                    }
예제 #12
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;

        }
예제 #13
0
 public Connect4GameController(ILogger <Connect4GameController> logger, Connect4Game game)
 {
     _game   = game;
     _logger = logger;
 }
예제 #14
0
        public async Task Connect4PlayingTask(int[, ] lines, IUserMessage gamemessage, GameUser player1, GameUser player2, int bet, EmbedBuilder embed, Connect4Game currentlobby)
        {
            // LastX and LastY are used to check for horizontal and vertical wins
            var lastx       = 0;
            var lasty       = 0;
            var playinggame = true;

            // We always begin the game with whoever ran the initial command.
            var currentplayer = 1;
            var winmethod     = "";

            // MSGTime is used to ensure that only a single minute passes in between turns, if it goes past a minute between turns then we count it as a player forfeiting.
            var msgtime   = DateTime.UtcNow + TimeSpan.FromMinutes(1);
            var errormsgs = "";

            while (playinggame)
            {
                var errormsgs1 = errormsgs;
                if (!string.IsNullOrEmpty(errormsgs1))
                {
                    await gamemessage.ModifyAsync(x => x.Content = errormsgs1);
                }
                else
                {
                    await gamemessage.ModifyAsync(x => x.Content = " ");
                }

                errormsgs = "";

                // Using InteractiveBase we wait until a message is sent in the current game
                var next = await NextMessageAsync(async (x, y) => x.Channel.Id == y.Channel.Id, TimeSpan.FromMinutes(1));

                // If the player doesn't show up mark them as forfeiting and award a win to the other player.
                if (next == null || msgtime < DateTime.UtcNow)
                {
                    await ReplyAsync(
                        $"{(currentplayer == 1 ? Context.Guild.GetUser(player1.UserId)?.Mention : Context.Guild.GetUser(player2.UserId)?.Mention)} Did not reply fast enough. Auto forfeiting");

                    var w = currentplayer == 1 ? player2.UserId : player1.UserId;
                    var l = currentplayer == 1 ? player1.UserId : player2.UserId;
                    await Connect4WinAsync(w, l, bet, "Player Forfeited.");

                    return;
                }

                // filter out non game messages by ignoring ones
                if (!next.Content.ToLower().StartsWith("connect4"))
                {
                    continue;
                }

                // Ensure that we only accept messages from players that are in the game
                if (next.Author.Id != player1.UserId && next.Author.Id != player2.UserId)
                {
                    // await ReplyAsync("You are not part of this game.");
                    errormsgs = $"{next.Author.Mention} You are not part of this game.";
                    await next.DeleteAsync();

                    continue;
                }

                // Ensure that the current message is from a player AND it is also their turn.
                if ((next.Author.Id == player1.UserId && currentplayer == 1) ||
                    (next.Author.Id == player2.UserId && currentplayer == 2))
                {
                    // filter out invalid line submissions
                    var parameters = next.Content.Split(" ");

                    // Make sure that the message is in the correct format of connect4 [line]
                    if (parameters.Length != 2 || !int.TryParse(parameters[1], out var Column))
                    {
                        errormsgs =
                            $"{(currentplayer == 2 ? Context.Guild.GetUser(player1.UserId)?.Mention : Context.Guild.GetUser(player2.UserId)?.Mention)} \n" +
                            $"Invalid Line input, here is an example input:\n" +
                            "`connect4 3` - this will place a counter in line 3.\n" +
                            "NOTE: Do not use the bot's prefix, just write `connect4 [line]`";
                        await next.DeleteAsync();

                        continue;
                    }

                    // as there are only 7 columns to pick from, filter out values outside of this range.
                    if (Column < 0 || Column > 6)
                    {
                        // error invalid line.
                        errormsgs =
                            $"{(currentplayer == 2 ? Context.Guild.GetUser(player1.UserId)?.Mention : Context.Guild.GetUser(player2.UserId)?.Mention)}\n" +
                            $"Invalid input, line number must be from 0-6 message in the format:\n" +
                            "`connect4 [line]`";
                        await next.DeleteAsync();

                        continue;
                    }

                    var success = false;

                    // moving from the top of the board downwards
                    for (var row = 5; row >= 0; row--)
                    {
                        if (lines[row, Column] != 0)
                        {
                            continue;
                        }

                        lines[row, Column] = currentplayer;
                        lastx   = Column;
                        lasty   = row;
                        success = true;
                        break;
                    }

                    // Ensure that we only move to the next player's turn IF the current player actually makes a move in an available column.
                    if (!success)
                    {
                        errormsgs =
                            $"{(currentplayer == 2 ? Context.Guild.GetUser(player1.UserId)?.Mention : Context.Guild.GetUser(player2.UserId)?.Mention)}\n" +
                            $"Error, please specify a line that isn't full";
                        await next.DeleteAsync();

                        continue;
                    }

                    // Update the embed message
                    embed.Description = "";
                    for (var r = 0; r < 6; r++)
                    {
                        if (r == 0)
                        {
                            for (var c = 0; c < 7; c++)
                            {
                                embed.Description += $":{numlist[c]}:";
                            }

                            embed.Description += "\n";
                        }

                        for (var c = 0; c < 7; c++)
                        {
                            if (lines[r, c] == 0)
                            {
                                embed.Description += $"{none}";
                            }
                            else if (lines[r, c] == 1)
                            {
                                embed.Description += $"{blue}";
                            }
                            else if (lines[r, c] == 2)
                            {
                                embed.Description += $"{red}";
                            }
                        }

                        embed.Description += "\n";
                    }

                    embed.Description += "Usage:\n" +
                                         "`connect4 [column]`\n" +
                                         $":large_blue_circle: - {Context.User.Mention} {(currentplayer == 1 ? "" : "<-")}\n" +
                                         $":red_circle: - {Context.Guild.GetUser(player2.UserId)?.Mention} {(currentplayer == 2 ? "" : "<-")}";
                    embed.Footer = new EmbedFooterBuilder
                    {
                        Text =
                            $"it is {(currentplayer == 2 ? Context.Guild.GetUser(player1.UserId)?.Username : Context.Guild.GetUser(player2.UserId)?.Username)}'s turn"
                    };
                    await gamemessage.ModifyAsync(x => x.Embed = embed.Build());

                    // Check If it is a win here.
                    var connectioncount = 0;

                    // Checking Horizontally (Rows)
                    for (var i = 0; i <= 6; i++)
                    {
                        if (lines[lasty, i] == currentplayer)
                        {
                            connectioncount++;
                        }
                        else
                        {
                            connectioncount = 0;
                        }

                        if (connectioncount < 4)
                        {
                            continue;
                        }

                        // await ReplyAsync($"Player {currentplayer} Wins! Horizontal");
                        playinggame = false;
                        winmethod   = "Horizontal";
                        break;
                    }

                    // Checking Vertically (Columns)
                    connectioncount = 0;
                    for (var i = 0; i <= 5; i++)
                    {
                        if (lines[i, lastx] == currentplayer)
                        {
                            connectioncount++;
                        }
                        else
                        {
                            connectioncount = 0;
                        }

                        if (connectioncount >= 4)
                        {
                            // await ReplyAsync($"Player {currentplayer} Wins! Vertical");
                            playinggame = false;
                            winmethod   = "Vertical";
                            break;
                        }
                    }

                    /*     C    O    L    U    M    N    S
                     * R [0,0][0,1][0,2][0,3][0,4][0,5][0,6]
                     * O [1,0][1,1][1,2][1,3][1,4][1,5][1,6]
                     * W [2,0][2,1][2,2][2,3][2,4][2,5][2,6]
                     * S [3,0][3,1][3,2][3,3][3,4][3,5][3,6]
                     *   [4,0][4,1][4,2][4,3][4,4][4,5][4,6]
                     *   [5,0][5,1][5,2][5,3][5,4][5,5][5,6]
                     */

                    // Checking Diagonally
                    int colinit, rowinit;

                    // Top Left => Bottom Right (from top row diagonals)
                    for (rowinit = 0; rowinit <= 5; rowinit++)
                    {
                        connectioncount = 0;
                        int row, col;
                        for (row = rowinit, col = 0; col <= 6 && row <= 5; col++, row++)
                        {
                            if (lines[row, col] == currentplayer)
                            {
                                connectioncount++;
                                if (connectioncount < 4)
                                {
                                    continue;
                                }

                                playinggame = false;
                                winmethod   = "Diagonal";
                                break;
                            }

                            connectioncount = 0;
                        }
                    }

                    // Top Left => Bottom Right (from columns)
                    for (colinit = 0; colinit <= 6; colinit++)
                    {
                        connectioncount = 0;
                        int row, col;
                        for (row = 0, col = colinit; col <= 6 && row <= 5; col++, row++)
                        {
                            if (lines[row, col] == currentplayer)
                            {
                                connectioncount++;
                                if (connectioncount < 4)
                                {
                                    continue;
                                }

                                playinggame = false;
                                winmethod   = "Diagonal";
                                break;
                            }

                            connectioncount = 0;
                        }
                    }

                    // Checking other Diagonal.
                    // Top Right => Bottom Left
                    for (rowinit = 0; rowinit <= 5; rowinit++)
                    {
                        connectioncount = 0;
                        int row, col;
                        for (row = rowinit, col = 6; col >= 0 && row <= 5; col--, row++)
                        {
                            if (lines[row, col] == currentplayer)
                            {
                                connectioncount++;
                                if (connectioncount < 4)
                                {
                                    continue;
                                }

                                playinggame = false;
                                winmethod   = "Diagonal";
                                break;
                            }

                            connectioncount = 0;
                        }
                    }

                    for (colinit = 6; colinit >= 0; colinit--)
                    {
                        connectioncount = 0;
                        int row, col;
                        for (row = 0, col = colinit; col >= 0 && row <= 5; col--, row++)
                        {
                            if (lines[row, col] == currentplayer)
                            {
                                connectioncount++;
                                if (connectioncount < 4)
                                {
                                    continue;
                                }

                                playinggame = false;
                                winmethod   = "Diagonal";
                                break;
                            }

                            connectioncount = 0;
                        }
                    }

                    // If we have a win, do don't switch the current player.
                    if (!playinggame)
                    {
                        continue;
                    }

                    currentplayer = currentplayer == 1 ? 2 : 1;

                    // To reduce the amount of messages after the game, delete the connect4 message.
                    await next.DeleteAsync();

                    msgtime = DateTime.UtcNow + TimeSpan.FromMinutes(1);

                    if (!embed.Description.Contains($"{none}"))
                    {
                        // This means all spaces are filled on the board
                        // ie. a tie.
                        await ReplyAsync(
                            "The Game is a draw. User Balances have not been modified. Good Game!");

                        currentlobby.GameRunning = false;
                        return;
                    }
                }
                else
                {
                    errormsgs =
                        $"{(currentplayer == 2 ? Context.Guild.GetUser(player1.UserId)?.Mention : Context.Guild.GetUser(player2.UserId)?.Mention)}\n" +
                        "Unknown Player/Not your turn.";
                    await next.DeleteAsync();
                }
            }

            await Connect4GetResultsAsync(currentplayer, player1, player2, bet, winmethod);
        }
예제 #15
0
            public async Task Connect4(params string[] args)
            {
                var(options, _) = OptionsParser.Default.ParseFrom(new Connect4Game.Options(), args);
                if (!await CheckBetOptional(options.Bet))
                {
                    return;
                }

                var          newGame = new Connect4Game(Context.User.Id, Context.User.ToString(), options, _cs);
                Connect4Game game;

                if ((game = _service.Connect4Games.GetOrAdd(Context.Channel.Id, newGame)) != newGame)
                {
                    if (game.CurrentPhase != Connect4Game.Phase.Joining)
                    {
                        return;
                    }

                    newGame.Dispose();
                    //means game already exists, try to join
                    var joined = await game.Join(Context.User.Id, Context.User.ToString(), options.Bet).ConfigureAwait(false);

                    return;
                }

                if (options.Bet > 0)
                {
                    if (!await _cs.RemoveAsync(Context.User.Id, "Connect4-bet", options.Bet, true))
                    {
                        await ReplyErrorLocalized("not_enough", _bc.BotConfig.CurrencySign).ConfigureAwait(false);

                        _service.Connect4Games.TryRemove(Context.Channel.Id, out _);
                        game.Dispose();
                        return;
                    }
                }

                game.OnGameStateUpdated  += Game_OnGameStateUpdated;
                game.OnGameFailedToStart += Game_OnGameFailedToStart;
                game.OnGameEnded         += Game_OnGameEnded;
                _client.MessageReceived  += _client_MessageReceived;

                game.Initialize();
                if (options.Bet == 0)
                {
                    await ReplyConfirmLocalized("connect4_created").ConfigureAwait(false);
                }
                else
                {
                    await ReplyConfirmLocalized("connect4_created_bet", options.Bet + _bc.BotConfig.CurrencySign).ConfigureAwait(false);
                }

                Task _client_MessageReceived(SocketMessage arg)
                {
                    if (Context.Channel.Id != arg.Channel.Id)
                    {
                        return(Task.CompletedTask);
                    }

                    var _ = Task.Run(async() =>
                    {
                        bool success = false;
                        if (int.TryParse(arg.Content, out var col))
                        {
                            success = await game.Input(arg.Author.Id, arg.Author.ToString(), col).ConfigureAwait(false);
                        }

                        if (success)
                        {
                            try { await arg.DeleteAsync().ConfigureAwait(false); } catch { }
                        }
                        else
                        {
                            if (game.CurrentPhase == Connect4Game.Phase.Joining ||
                                game.CurrentPhase == Connect4Game.Phase.Ended)
                            {
                                return;
                            }
                            RepostCounter++;
                            if (RepostCounter == 0)
                            {
                                try { msg = await Context.Channel.SendMessageAsync("", embed: (Embed)msg.Embeds.First()); } catch { }
                            }
                        }
                    });

                    return(Task.CompletedTask);
                }

                Task Game_OnGameFailedToStart(Connect4Game arg)
                {
                    if (_service.Connect4Games.TryRemove(Context.Channel.Id, out var toDispose))
                    {
                        _client.MessageReceived -= _client_MessageReceived;
                        toDispose.Dispose();
                    }
                    return(ErrorLocalized("connect4_failed_to_start"));
                }

                Task Game_OnGameEnded(Connect4Game arg, Connect4Game.Result result)
                {
                    if (_service.Connect4Games.TryRemove(Context.Channel.Id, out var toDispose))
                    {
                        _client.MessageReceived -= _client_MessageReceived;
                        toDispose.Dispose();
                    }

                    string title;

                    if (result == Connect4Game.Result.CurrentPlayerWon)
                    {
                        title = GetText("connect4_won", Format.Bold(arg.CurrentPlayer.Username), Format.Bold(arg.OtherPlayer.Username));
                    }
                    else if (result == Connect4Game.Result.OtherPlayerWon)
                    {
                        title = GetText("connect4_won", Format.Bold(arg.OtherPlayer.Username), Format.Bold(arg.CurrentPlayer.Username));
                    }
                    else
                    {
                        title = GetText("connect4_draw");
                    }

                    return(msg.ModifyAsync(x => x.Embed = new EmbedBuilder()
                                                          .WithTitle(title)
                                                          .WithDescription(GetGameStateText(game))
                                                          .WithOkColor()
                                                          .Build()));
                }
            }
        // Calls minimax for each possible move and returns best move
        public static int FindBestMove(Connect4Game connect4, Con4Board startBoard, int maxDepth)
        {
            MiniMaxAlphaBetaHeuristic.maxDepth = maxDepth;
            MiniMaxAlphaBetaHeuristic.connect4 = connect4;
            int player = MAXIMIZING;
            int a      = int.MinValue;
            int b      = int.MaxValue;

            List <MoveBoardNode> moveBoardNodes = new List <MoveBoardNode>();

            foreach (int move in startBoard.GetPossibleMoves())
            {
                Con4Board  nextBoard = startBoard.SimulateMove(player, move);
                Evaluation nextEval  = CalculateBoardScore(nextBoard, 1);
                BoardNode  boardNode = new BoardNode {
                    board = nextBoard, eval = nextEval
                };
                moveBoardNodes.Add(new MoveBoardNode {
                    move = move, boardNode = boardNode
                });
            }

            moveBoardNodes = moveBoardNodes.OrderByDescending(x => x.boardNode.eval.score).ToList(); // player is maximizing

            Console.WriteLine("\tMove scores {move, score}: ");
            Console.Write("\t");
            List <MoveScore> results = new List <MoveScore>();

            foreach (MoveBoardNode moveBoardNode in moveBoardNodes)
            {
                int searchScore = MiniMaxSearch(moveBoardNode.boardNode, MINIMIZING, 1, a, b);
                a = Math.Max(a, searchScore);
                if (a >= b)
                {
                    break;
                }

                Console.Write("{" + moveBoardNode.move + ", " + searchScore + "} ,  ");

                results.Add(new MoveScore()
                {
                    move = moveBoardNode.move, score = searchScore
                });
            }
            int maxScore = results.Max(x => x.score);

            if (Math.Abs(maxScore) > 900) // Either confident in win or in loss, don't search deeper
            {
                MainClass.gameOutcomeFinal = true;
            }
            if (results.Count(x => x.score > -900) == 1) // Only 1 viable option, just do it!
            {
                MainClass.gameOutcomeFinal = true;
            }
            int bestMove = results.Find(x => x.score == maxScore).move;

            //int decidedMove = DecideMove(results);
            Console.WriteLine("\tBest move: " + bestMove);
            Console.WriteLine("\tSimulations: " + Con4Board.simulations);
            Con4Board.simulations = 0;
            return(bestMove);
        }
 public void CannotCreateGame_WrongPlayerType2()
 {
     IPlayer player2 = MockRepository.GenerateMock<IPlayer>();
     IPlayer player1 = MockRepository.GenerateMock<Connect4Player>();
     var game = new Connect4Game(rows: 7, columns: 6, player1: player1, player2: player2);
 }
 public void CannotCreateCreateGame_BoardTooManyRows()
 {
     IPlayer player1 = MockRepository.GenerateMock<Connect4Player>();
     IPlayer player2 = MockRepository.GenerateMock<Connect4Player>();
     var game = new Connect4Game(rows: 10, columns: 6, player1: player1, player2: player2);
 }
예제 #19
0
 public Connect4Form() : base()
 {
     InitializeComponent();
     game = new Connect4Game();
 }
예제 #20
0
        public async Task Connect4AcceptTask(int bet, Connect4Game currentlobby)
        {
            var      accepted        = false;
            var      timeoutattempts = 0;
            var      messagewashout  = 0;
            GameUser p2 = null;

            // Here we wait until another player accepts the game
            while (!accepted)
            {
                var next = await NextMessageAsync(async (x, y) => x.Channel.Id == y.Channel.Id, TimeSpan.FromSeconds(10));

                if (next?.Author.Id == Context.User.Id)
                {
                    // Ignore author messages for the game until another player accepts
                }
                else if (string.Equals(next?.Content, "connect4 accept", StringComparison.InvariantCultureIgnoreCase))
                {
                    p2 = GameService.GetGameUser(next.Author.Id, Context.Guild.Id);
                    if (p2.Points < bet)
                    {
                        await ReplyAsync(
                            $"{next.Author.Mention} - You do not have enough points to play this game, you need a minimum of {bet}. Your balance is {p2.Points} points");
                    }
                    else
                    {
                        accepted = true;
                        p2       = GameService.GetGameUser(next.Author.Id, Context.Guild.Id);
                    }
                }

                // Overload for is a message is not sent within the timeout
                if (next == null)
                {
                    // if more than 6 timeouts (1 minute of no messages) occur without a user accepting, we quit the game
                    timeoutattempts++;
                    if (timeoutattempts < 6)
                    {
                        continue;
                    }

                    await ReplyAsync("Connect4: Timed out!");

                    currentlobby.GameRunning = false;
                    return;
                }

                // In case people are talking over the game, we also make the game quit after 25 messages are sent so it is not waiting indefinitely for a player to accept.
                messagewashout++;
                if (messagewashout <= 25)
                {
                    continue;
                }

                await ReplyAsync("Connect4: Timed out!");

                currentlobby.GameRunning = false;
                return;
            }

            await Connect4PreGameSetup(p2, bet, currentlobby);
        }