Exemplo n.º 1
0
            public HoldemState Transition(
                int nowMillis, bool[] playerIsSeated, bool[] playerIsReady, int[] bankBySeatOwner,
                int actingPlayerBet, bool actingPlayerCommited,
                int[] deck)
            {
                object[] newState = HoldemGame.CalculateTransition(
                    tableState, lastTransitionMillis, bettingRound, actingSeat, dealerSeat,
                    currentBet, minimumRaise, headsUp, wonByFold,

                    // clone so we can test old state
                    (int[])playerState.Clone(),
                    (int[])stacks.Clone(),
                    (int[])roundContribution.Clone(),
                    (int[])potContribution.Clone(),

                    flop0, flop1, flop2, turn, river, holeCards0, holeCards1,
                    // external state
                    nowMillis, bigBlind,
                    winnerTimeoutSecs, readyTimeoutSecs,
                    actionTimeoutSecs, headsUpTimeoutSecs,
                    playerIsSeated, playerIsReady, bankBySeatOwner,
                    actingPlayerBet, actingPlayerCommited,
                    deck);
                HoldemState newS = this;

                if (newState != null)
                {
                    newS = new HoldemState(newState);
                }
                Validate(newS, this, playerIsSeated[actingSeat], actingPlayerBet, actingPlayerCommited);
                return(newS);
            }
Exemplo n.º 2
0
        private ulong hand(string hand)
        {
            var cards = hand.Split(' ');

            return(HoldemGame.EvaluateHand(
                       CARDS[cards[0]], CARDS[cards[1]], CARDS[cards[2]], CARDS[cards[3]], CARDS[cards[4]]));
        }
Exemplo n.º 3
0
            public GameState CalculateTransition(
                int lastTransitionMillis,
                int nowMillis, bool actingPlayerSeated, int actingPlayerBet, bool actingPlayerCommited)
            {
                var newState = HoldemGame.CalculateGameTransition(
                    lastTransitionMillis, bettingRound, actingSeat,
                    currentBet, minimumRaise, headsUp,
                    // copy so we can test against the old one
                    (int[])playerState.Clone(),
                    (int[])stacks.Clone(),
                    (int[])roundContribution.Clone(),
                    (int[])potContribution.Clone(),
                    nowMillis,
                    actionTimeoutSecs, headsUpTimeoutSecs, bigBlind, dealerSeat, actingPlayerSeated,
                    actingPlayerBet, actingPlayerCommited);

                GameState newS = this;

                if (newState != null)
                {
                    newS = new GameState(newState);
                }
                Validate(newS, this, actingPlayerSeated, actingPlayerBet, actingPlayerCommited);
                return(newS);
            }
Exemplo n.º 4
0
 public void DivideSidePot()
 {
     Assert.That(
         HoldemGame.DividePot(
             new int[] { 50, 100, 100, 0, 0, 0, 0, 0, 0, 0 },
             new int[] { 0, 1, 2, -1, -1, -1, -1, -1, -1, -1 }),
         Is.EqualTo(new int[] { 150, 100, 0, 0, 0, 0, 0, 0, 0, 0 }));
 }
Exemplo n.º 5
0
 public void DivideSideSplitPot()
 {
     // side split pot
     Assert.That(
         HoldemGame.DividePot(
             new int[] { 100, 150, 150, 0, 0, 0, 0, 0, 0, 0 },
             new int[] { 0, 0, 1, -1, -1, -1, -1, -1, -1, -1 }),
         Is.EqualTo(new int[] { 150, 250, 0, 0, 0, 0, 0, 0, 0, 0 }));
 }
Exemplo n.º 6
0
        private int[] RankPlayers(
            int[] playerState, int[] holeCards0, int[] holeCards1,
            int flop0, int flop1, int flop2, int turn, int river)
        {
            var values = HoldemGame.GetHandValues(
                playerState, holeCards0, holeCards1, flop0, flop1, flop2, turn, river);

            return(HoldemGame.RankPlayers(values));
        }
Exemplo n.º 7
0
        public void DividePot()
        {
            // simple
            Assert.That(
                HoldemGame.DividePot(
                    new int[] { 100, 100, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new int[] { 0, 1, -1, -1, -1, -1, -1, -1, -1, -1 }),
                Is.EqualTo(new int[] { 200, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));

            // split
            Assert.That(
                HoldemGame.DividePot(
                    new int[] { 100, 100, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new int[] { 0, 0, -1, -1, -1, -1, -1, -1, -1, -1 }),
                Is.EqualTo(new int[] { 100, 100, 0, 0, 0, 0, 0, 0, 0, 0 }));
        }
Exemplo n.º 8
0
            public async Task ExecuteGroupAsync(CommandContext ctx,
                                                [Description("desc-gamble-balance")] int balance = HoldemGame.DefaultBalance)
            {
                if (balance is < 1 or > (int)MaxBid)
                {
                    throw new CommandFailedException(ctx, "cmd-err-gamble-bid", MaxBid);
                }

                if (this.Service.IsEventRunningInChannel(ctx.Channel.Id))
                {
                    if (this.Service.GetEventInChannel(ctx.Channel.Id) is HoldemGame)
                    {
                        await this.JoinAsync(ctx);
                    }
                    else
                    {
                        throw new CommandFailedException(ctx, "cmd-err-evt-dup");
                    }
                    return;
                }

                string currency = ctx.Services.GetRequiredService <GuildConfigService>().GetCachedConfig(ctx.Guild.Id).Currency;
                var    game     = new HoldemGame(ctx.Client.GetInteractivity(), ctx.Channel, balance);

                this.Service.RegisterEventInChannel(game, ctx.Channel.Id);
                try {
                    await ctx.ImpInfoAsync(this.ModuleColor, Emojis.Clock1, "str-casino-holdem-start",
                                           HoldemGame.MaxParticipants, HoldemGame.DefaultBalance, currency
                                           );

                    await this.JoinAsync(ctx);

                    await Task.Delay(TimeSpan.FromSeconds(30));

                    BankAccountService bas = ctx.Services.GetRequiredService <BankAccountService>();
                    if (game.Participants.Count > 1)
                    {
                        await game.RunAsync(this.Localization);

                        if (game.Winner is { })
                        {
                            await ctx.ImpInfoAsync(this.ModuleColor, Emojis.Cards.Suits[0], "fmt-winners", game.Winner.Mention);
                        }
                    }
Exemplo n.º 9
0
        public void HandEvaluator()
        {
            Assert.AreEqual("High Card (A)", HoldemGame.HandClass(hand("2C 3C 4C TD AC")));
            Assert.AreEqual("Pair (2)", HoldemGame.HandClass(hand("2C 2D 4C TD AC")));
            Assert.AreEqual("Two Pairs (3/2)", HoldemGame.HandClass(hand("2C 2D 3C 3D AC")));
            Assert.AreEqual("Three of a Kind (2)", HoldemGame.HandClass(hand("2C 2D 2S 3D AC")));
            Assert.AreEqual("Straight (Wheel)", HoldemGame.HandClass(hand("2C 3S 4S 5D AC")));
            Assert.AreEqual("Straight", HoldemGame.HandClass(hand("3C 4S 5S 6D 7C")));
            Assert.AreEqual("Flush", HoldemGame.HandClass(hand("3S TS 5S 6S 7S")));
            Assert.AreEqual("Full House (10/3)", HoldemGame.HandClass(hand("TS TC TC 3S 3S")));
            Assert.AreEqual("Four of a Kind (10)", HoldemGame.HandClass(hand("TS TC TC TS 4S")));
            Assert.AreEqual("Straight Flush", HoldemGame.HandClass(hand("9S TS JS QS KS")));
            Assert.AreEqual("Royal Flush", HoldemGame.HandClass(hand("TS JS QS KS AS")));

            // high card
            Assert.Greater(
                hand("2C 3C 4C TD AC"),
                hand("2H 3H 4H TH KD"));
            // straight flushes
            Assert.Greater(
                HoldemGame.EvaluateHand(1, 2, 3, 4, 5),
                HoldemGame.EvaluateHand(0, 1, 2, 3, 4));
        }
Exemplo n.º 10
0
    private void Update()
    {
        // XXX apparently udon will run some Update()s before Starts() so
        // HoldemGame's start might not initialize this
        if (game == null)
        {
            return;
        }
        // don't bother if game isn't initialized
        if (game.tableState == TABLE_UNINITIALIZED)
        {
            return;
        }

        var locallySeated = isLocallySeated();
        var seated        = IsSeated();

        uiReady.interactable = locallySeated;
        goReadyToggle.SetActive(locallySeated || !seated);

        if (locallySeated)
        {
            // one ui read
            playerReady = uiReady.isOn;

            uiJoinLeaveButton.interactable = !playerReady;
            if (playerReady)
            {
                uiJoinLeaveText.text = "Ready";
            }
            else
            {
                uiJoinLeaveText.text = "Leave";
            }
        }
        else
        {
            if (seated)
            {
                uiJoinLeaveButton.interactable = false;
                uiJoinLeaveText.text           = $"{OwnerName()}";
            }
            else
            {
                uiJoinLeaveButton.interactable = true;
                uiJoinLeaveText.text           = "Join";
            }
        }

        var playerState = game.playerState[seatIdx];
        var inPlay      = playerState != PLAYER_DEAD;

        uiDealer.enabled = game.tableState == TABLE_PLAYING && game.dealerSeat == seatIdx;

        var  winner   = game.tableState == TABLE_WINNER;
        bool showdown = false;

        if (winner)
        {
            int challengers = 0;
            for (int i = 0; i < 10; ++i)
            {
                if (game.playerState[i] == PLAYER_COMMITED)
                {
                    challengers++;
                }
            }
            if (challengers > 1)
            {
                showdown = true;
            }
        }

        // display at least blank cards if in play
        goHoleCards.SetActive(inPlay);

        var holes = inPlay && (locallySeated || game.headsUp || showdown);

        uiHole0.enabled    = holes;
        uiHole1.enabled    = holes;
        uiBestHand.enabled = holes && game.bettingRound >= FLOP;

        var acting = playerState == PLAYER_ACTING;
        var valid  = game.IsValidBet(bet, seatIdx);

        uiStatusColor.enabled = seated;
        uiStatusColor.color   =
            playerState == PLAYER_DEAD ? Color.black :
            playerState == PLAYER_PENDING ? Color.white :
            playerState == PLAYER_ACTING ? Color.green :
            playerState == PLAYER_COMMITED ? Color.blue : Color.red;

        goBetUi.SetActive(acting);

        uiBet.text = GetBet();

        goChipDisplay.SetActive(seated);
        var stack = game.stacks[seatIdx];

        if (acting && bet > 0)
        {
            var left = stack - bet;
            uiChips.text = $"{left} (total {stack})";
        }
        else
        {
            uiChips.text = $"{stack}";
        }

        uiCallCheck.interactable = locallySeated && acting && valid;
        uiFold.interactable      = locallySeated && acting;

        uiConfirm.interactable = uiPending && (valid || bet == -1);
        var uiConfirmColors = uiConfirm.colors;

        uiConfirmColors.normalColor   = committedEpoch == game.epoch ? Color.yellow : Color.white;
        uiConfirmColors.disabledColor = playerState == PLAYER_COMMITED ? Color.blue : Color.grey;
        uiConfirm.colors = uiConfirmColors;

        var uiFoldColors = uiFold.colors;

        uiFoldColors.normalColor = (bet == -1 && uiPending) ? Color.red : Color.white;
        uiFold.colors            = uiFoldColors;

        var uiCallCheckColors = uiCallCheck.colors;

        uiCallCheckColors.normalColor = bet >= 0 && uiPending ? Color.green : Color.white;
        uiCallCheck.colors            = uiCallCheckColors;

        uiCallCheckText.text =
            bet == 0 ? "Check" :
            bet == game.stacks[seatIdx] ? "All-in" :
            bet == -1 ? "(fold)" :
            !valid ? "(invalid bet)" :
            bet > game.currentBet ?
            (game.currentBet > 0 ?  "Re-Raise" : "Raise") :
            game.currentBet > 0 ? "Call" : "Check";

        uiActTimer.enabled = acting;
        if (acting)
        {
            var now       = Networking.LocalPlayer == null ? (int)(Time.time * 1000) : Networking.GetServerTimeInMilliseconds();
            var timeout   = game.lastTransitionMillis;
            var remaining = game.actionTimeoutSecs - (now - timeout) / 1000;
            uiActTimer.text = $"{remaining / 60}:{remaining % 60} to act";
        }

        // transition check
        if (updateSeenEpoch != game.epoch)
        {
            updateSeenEpoch = game.epoch;
            // edge-triggered
            if (locallySeated)
            {
                if (acting)
                {
                    // start off with a call
                    bet = Mathf.Min(stack, game.currentBet - game.roundContribution[seatIdx]);
                    // require the confirm again
                    uiPending = false;
                }
                else
                {
                    // once it comes around to us again, make sure we aren't
                    // accidentally already commited from the past
                    bet            = 0;
                    committedEpoch = -1;
                }
            }
            if (game.tableState == TABLE_PLAYING)
            {
                uiHole0.text = game.unicard(game.holeCards0[seatIdx]);
                uiHole1.text = game.unicard(game.holeCards1[seatIdx]);
                var bestHand =
                    game.bettingRound == RIVER?game.BestPlayerHandSeat(seatIdx) :
                        game.bettingRound == TURN?game.BestPlayerHandTurnSeat(seatIdx) :
                            game.bettingRound == FLOP?game.BestPlayerHandFlop(seatIdx) : 0;

                if (bestHand > 0UL)
                {
#if !COMPILER_UDONSHARP
                    uiBestHand.text = $"{HoldemGame.HandClass(bestHand)}";
#else
                    uiBestHand.text = $"{game.HandClass(bestHand)}";
#endif
                }
                else
                {
                    uiBestHand.text = "";
                }
            }
        }
    }
Exemplo n.º 11
0
            public async Task ExecuteGroupAsync(CommandContext ctx,
                                                [Description("Amount of money required to enter.")] int amount = 1000)
            {
                if (amount < 5)
                {
                    throw new InvalidCommandUsageException($"Entering balance cannot be lower than 5 {this.Shared.GetGuildConfig(ctx.Guild.Id).Currency ?? "credits"}");
                }

                if (this.Shared.IsEventRunningInChannel(ctx.Channel.Id))
                {
                    if (this.Shared.GetEventInChannel(ctx.Channel.Id) is HoldemGame)
                    {
                        await this.JoinAsync(ctx);
                    }
                    else
                    {
                        throw new CommandFailedException("Another event is already running in the current channel.");
                    }
                    return;
                }

                var game = new HoldemGame(ctx.Client.GetInteractivity(), ctx.Channel, amount);

                this.Shared.RegisterEventInChannel(game, ctx.Channel.Id);
                try {
                    await this.InformAsync(ctx, StaticDiscordEmoji.Clock1, $"The Hold'Em game will start in 30s or when there are 7 participants. Use command {Formatter.InlineCode("casino holdem <entering sum>")} to join the pool. Entering sum is set to {game.MoneyNeeded} {this.Shared.GetGuildConfig(ctx.Guild.Id).Currency ?? "credits"}.");

                    await this.JoinAsync(ctx);

                    await Task.Delay(TimeSpan.FromSeconds(30));

                    if (game.Participants.Count > 1)
                    {
                        await game.RunAsync();

                        if (!(game.Winner is null))
                        {
                            await this.InformAsync(ctx, StaticDiscordEmoji.Trophy, $"Winner: {game.Winner.Mention}");
                        }

                        using (DatabaseContext db = this.Database.CreateContext()) {
                            foreach (HoldemParticipant participant in game.Participants)
                            {
                                await db.ModifyBankAccountAsync(ctx.User.Id, ctx.Guild.Id, v => v + participant.Balance);
                            }
                            await db.SaveChangesAsync();
                        }
                    }
                    else
                    {
                        if (game.IsParticipating(ctx.User))
                        {
                            using (DatabaseContext db = this.Database.CreateContext()) {
                                await db.ModifyBankAccountAsync(ctx.User.Id, ctx.Guild.Id, v => v + game.MoneyNeeded);

                                await db.SaveChangesAsync();
                            }
                        }
                        await this.InformAsync(ctx, StaticDiscordEmoji.AlarmClock, "Not enough users joined the Hold'Em game.");
                    }
                } finally {
                    this.Shared.UnregisterEventInChannel(ctx.Channel.Id);
                }
            }