private IEnumerator DrawCards()
    {
        var heldCards = CardObjects.Where(co => co.Held).Select(co => co.RankText.text + co.SuitText.text);

        if (!IsSolved)
        {
            ModuleLog("Attempting to {0}...", heldCards.Count() > 0 ? ("hold " + heldCards.Join(" ")) : "discard everything");
        }

        int strategyIndex = Enumerable.Range(0, 5).Where(i => CardObjects[i].Held).Sum(i => 1 << i);

        if (!IsSolved && !AcceptablePlays.Contains(strategyIndex))
        {
            ModuleLog("Strike! This isn't an optimal play. Resetting streak to 0.");
            Streak = 0;
            ProgressLightManager.SetValue(0);
            StartCoroutine(BlinkProgressLightsRed());
            BombModule.HandleStrike();
        }
        else
        {
            if (!IsSolved)
            {
                Streak++;
                ProgressLightManager.SetValue(Streak);
                ModuleLog("Yes, that's an optimal play! Current streak: {0}", Streak);
            }

            GameMessageText.Text = "";

            State = KtaneVideoPoker.State.SecondDeal;

            GameInfoButton.Disable();
            SpeedButton.Disable();
            DealButton.Disable();

            for (int i = 0; i < 5; i++)
            {
                if (!CardObjects[i].Held)
                {
                    CardObjects[i].Card = null;
                }
            }

            yield return(new WaitForSeconds(2 * SpeedButton.GetDelay()));

            for (int i = 0; i < 5; i++)
            {
                if (CardObjects[i].Card == null)
                {
                    Audio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.TypewriterKey, transform);
                    CardObjects[i].Card = AvailableCards.Pop();
                    yield return(new WaitForSeconds(SpeedButton.GetDelay()));
                }
            }

            if (!IsSolved)
            {
                ModuleLog("Final hand: {0}", CardObjects.Select(co => co.RankText.text + co.SuitText.text).Join(" "));
            }

            // Evaluate the hand
            var hand    = new KtaneVideoPoker.Core.Hand(CardObjects.Select(co => co.Card).Where(c => c.HasValue).Select(c => c.Value));
            var variant = VariantInfo.VariantIfUsingMaxBet(BetAmount == 5);

            var finalHandType = variant.Evaluate(hand);
            int payout        = variant.PayoutForResult(finalHandType) * BetAmount;

            if (finalHandType == KtaneVideoPoker.Core.HandResult.Nothing)
            {
                if (!IsSolved)
                {
                    ModuleLog("Oh well, this hand doesn't pay. Better luck next time!");
                }
                GameMessageText.Text = "PLAY 5 CREDITS";

                StartCoroutine(Payout(0));
            }
            else
            {
                if (!IsSolved)
                {
                    ModuleLog("Hand type {0} with bet {1} pays {2}", finalHandType.ToFriendlyString(), BetAmount, payout);
                }
                GameMessageText.Text = finalHandType.ToFriendlyString();

                if (payout >= JackpotThreshold)
                {
                    JackpotValue     = payout;
                    JackpotCoroutine = StartCoroutine(Jackpot());
                    yield break;
                }
                else
                {
                    StartCoroutine(Payout(payout));
                }
            }
        }
    }
    private IEnumerator BeginDeal()
    {
        // TODO: Disable buttons

        Credits             -= BetAmount;
        CreditsText.Text     = String.Format("CREDIT {0}", Credits);
        BetText.Text         = String.Format("BET {0}", BetAmount);
        GameMessageText.Text = "GOOD LUCK";
        State = KtaneVideoPoker.State.FirstDeal;

        for (int i = 0; i < 5; i++)
        {
            CardObjects[i].Card = null;
            CardObjects[i].Held = false;
        }

        GameInfoButton.Disable();
        SpeedButton.Disable();
        BetOneButton.Disable();
        BetMaxButton.Disable();
        DealButton.Disable();

        yield return(new WaitForSeconds(2 * SpeedButton.GetDelay()));

        int deckSize = KtaneVideoPoker.Core.Util.StandardDeckSize + VariantInfo.VariantIfUsingMaxBet(BetAmount == 5).JokerCount;

        AvailableCards = new Stack <KtaneVideoPoker.Core.Card>(Enumerable.Range(0, deckSize).Select(KtaneVideoPoker.Core.Card.CreateWithId).ToList().Shuffle());

        for (int i = 0; i < 5; i++)
        {
            Audio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.TypewriterKey, transform);
            CardObjects[i].Card = AvailableCards.Pop();
            yield return(new WaitForSeconds(SpeedButton.GetDelay()));
        }

        // Log cards
        if (!IsSolved)
        {
            ModuleLog("Dealt cards: {0}", CardObjects.Select(co => co.CardAsLogString()).Join(" "));
        }

        var hand           = new KtaneVideoPoker.Core.Hand(CardObjects.Select(co => co.Card).Where(c => c.HasValue).Select(c => c.Value));
        var strategyResult = VariantInfo.StrategyMaxBet.Evaluate(hand);

        if (BetAmount == 5)
        {
            AcceptablePlays = new HashSet <int>(strategyResult.Strategies);

            if (!IsSolved)
            {
                if (strategyResult.RuleIndex >= 0)
                {
                    ModuleLog("Use rule {0}", strategyResult.RuleIndex + 1);
                    ModuleLog("Applicable special rules: {0}", strategyResult.ExtraRules.Length > 0 ? strategyResult.ExtraRules.Join(", ") : "none");
                }
                else
                {
                    ModuleLog("Applicable exceptions: {0}", strategyResult.ExtraRules.Length > 0 ? strategyResult.ExtraRules.Join(", ") : "none");
                    ModuleLog("No valid rules found");
                }

                ModuleLog("Acceptable plays:");
                foreach (int strategy in strategyResult.Strategies)
                {
                    if (strategy == 0)
                    {
                        ModuleLog("• Discard everything");
                    }
                    else
                    {
                        ModuleLog("• Hold {0}", CardObjects.Where((co, i) => (strategy & (1 << i)) != 0).Select(co => co.RankText.text + co.SuitText.text).Join(" "));
                    }
                }
            }
        }


        State = KtaneVideoPoker.State.ChooseHolds;

        var intermediateHandType = VariantInfo.VariantIfUsingMaxBet(BetAmount == 5).Evaluate(hand);

        if (intermediateHandType == KtaneVideoPoker.Core.HandResult.Nothing)
        {
            GameMessageText.Text = "";
        }
        else
        {
            Audio.PlaySoundAtTransform("gliss1", transform);
            GameMessageText.Text = intermediateHandType.ToFriendlyString();
        }

        GameInfoButton.Text.text = "Game Info";
        GameInfoButton.Enable();

        SpeedButton.Enable();

        DealButton.Text.text = "Draw";
        DealButton.Enable();
    }