# Draw 'Til You Drop

In Dungeons & Dragons 5th edition (as well as most other editions), there exists a magic item called the Deck of Many Things. It is an incredibly powerful item, as the cards all have very strong positive or negative effects. To use the deck, a character declares a number, and then draws up to that number of cards, with the effects applying in sequence. If the character does not draw all of the cards that they declared, and it has been at least 1 hour since the last card has been drawn, the rest of the cards are automatically drawn for them and the effects applied. After each card is drawn, it is returned to the deck, and the deck is shuffled.

The following is a list of the effects of drawing each of the cards1:

• Balance: Your mind suffers a wrenching alteration, causing your alignment to change. Lawful becomes chaotic, good becomes evil, and vice versa. If you are true neutral or unaligned, this card has no effect on you.
• Comet: If you single-handedly defeat the next hostile monster or group of monsters you encounter, you gain experience points enough to gain one level. Otherwise, this card has no effect.
• Donjon: You disappear and become entombed in a state of suspended animation in an extradimensional sphere. Everything you were wearing and carrying stays behind in the space you occupied when you disappeared. You remain imprisoned until you are found and removed from the sphere. You can’t be located by any divination magic, but a wish spell can reveal the location of your prison. You draw no more cards.
• Euryale. The card’s medusa-like visage curses you. You take a -2 penalty on saving throws while cursed in this way. Only a god or the magic of The Fates card can end this curse.
• The Fates: Reality’s fabric unravels and spins anew, allowing you to avoid or erase one event as if it never happened. You can use the card’s magic as soon as you draw the card or at any other time before you die.
• Flames: A powerful devil becomes your enemy. The devil seeks your ruin and plagues your life, savoring your suffering before attempting to slay you. This enmity lasts until either you or the devil dies.
• Fool: You lose 10,000 XP, discard this card, and draw from the deck again, counting both draws as one of your declared draws. If losing that much XP would cause you to lose a level, you instead lose an amount that leaves you with just enough XP to keep your level.
• Gem: Twenty-five pieces of jewelry worth 2,000 gp each or fifty gems worth 1,000 gp each appear at your feet.
• Idiot: Permanently reduce your Intelligence by 1d4 + 1 (to a minimum score of 1). You can draw one additional card beyond your declared draws.
• Jester: You gain 10,000 XP, or you can draw two additional cards beyond your declared draws. Discard this card after drawing it.
• Key: A rare or rarer magic weapon with which you are proficient appears in your hands. The GM chooses the weapon.
• Knight: You gain the service of a 4th-level fighter who appears in a space you choose within 30 feet of you. The fighter is of the same race as you and serves you loyally until death, believing the fates have drawn him or her to you. You control this character.
• Moon: You are granted the ability to cast the wish spell 1d3 times.
• Rogue: A nonplayer character of the GM’s choice becomes hostile toward you. The identity of your new enemy isn’t known until the NPC or someone else reveals it. Nothing less than a wish spell or divine intervention can end the NPC’s hostility toward you.
• Ruin: All forms of wealth that you carry or own, other than magic items, are lost to you. Portable property vanishes. Businesses, buildings, and land you own are lost in a way that alters reality the least. Any documentation that proves you should own something lost to this card also disappears.
• Skull. You summon an avatar of death - a ghostly humanoid skeleton clad in a tattered black robe and carrying a spectral scythe. It appears in a space of the GM’s choice within 10 feet of you and attacks you, warning all others that you must win the battle alone. The avatar fights until you die or it drops to 0 hit points, whereupon it disappears. If anyone tries to help you, the helper summons its own avatar of death. A creature slain by an avatar of death can’t be restored to life.
• Star: Increase one of your ability scores by 2. The score can exceed 20 but can’t exceed 24.
• Sun: You gain 50,000 XP, and a wondrous item (which the GM determines randomly) appears in your hands.
• Talons: Every magic item you wear or carry disintegrates. Artifacts in your possession aren’t destroyed but do vanish.
• Throne: You gain proficiency in the Persuasion skill, and you double your proficiency bonus on checks made with that skill. In addition, you gain rightful ownership of a small keep somewhere in the world. However, the keep is currently in the hands of monsters, which you must clear out before you can claim the keep as yours.
• Vizier: At any time you choose within one year of drawing this card, you can ask a question in meditation and mentally receive a truthful answer to that question. Besides information, the answer helps you solve a puzzling problem or other dilemma. In other words, the knowledge comes with wisdom on how to apply it.
• The Void: This black card spells disaster. Your soul is drawn from your body and contained in an object in a place of the GM’s choice. One or more powerful beings guard the place. While your soul is trapped in this way, your body is incapacitated. A wish spell can’t restore your soul, but the spell reveals the location of the object that holds it. You draw no more cards.

(card descriptions copied from the D&D 5th edition SRD)

Some especially foolish players will draw a large number of cards at once, hoping to get at least one powerful boon to balance out the detrimental cards. As one might expect, this often results in the character's death or inability to continue to draw cards.

## The Challenge

Simulate repeated drawing from a 22-card Deck of Many Things, outputting each card drawn, stopping only when one of the following conditions is met:

• The character dies (via drawing Skull, or drawing 5 cards after drawing Flames or Rogue, without the benefit of The Fates or Moon active2).
• The character is incapable of drawing more cards (via the effects of Donjon, Talons, The Void3, or the character's Intelligence score dropping to 3 or lower via Idiot4).

## Rules

• The character's alignment, level, XP, and possessions other than the deck do not matter.
• The character's Intelligence score starts at 10.
• There is no maximum limit to the character's Intelligence or their stockpiled uses of wish.
• Uses of The Fates do not stack.
• The wish spell has a 1-in-3 chance of causing the character to never be able to use the wish spell again, in addition to its regular effect. If this occurs, the character can no longer use the spell to negate Flames, Rogue, or Skull - the power of The Fates is their only recourse.
• The character always makes the following choices:
• The Fates and Moon are solely used to get the character out of trouble from Skull, Flames, and Rogue. The character will never use them to reverse the effect of Talons or the wish spell being unable to be cast again, and cannot use them to reverse the effects of Donjon and The Void. The character will immediately use one wish spell to negate the effects of Skull, Flames, or Rogue upon drawing one of them, and it will always succeed. The character will always use The Fates before using wish.
• The character always chooses to draw more cards with the effects of Idiot and Jester (appropriately).
• The effect of Star is always used to increase Intelligence by 2, to avoid having to stop drawing cards via the effect of Idiot.
• The NPC ally summoned by Knight is not powerful enough to save the character from their untimely demise.
• Any increases or decreases to Intelligence (via Star or Idiot, respectively) must be reflected in the output (either by noting the change (+2 or -(1d4+1)), or by outputting the current Intelligence score after the effect takes place).
• Any changes to the number of wish uses the character has stockpiled must similarly be reflected in the output, including a wish causing the character to not be able to use wish anymore.
• All random selections are from uniform discrete distributions.
• You may choose any set of 22 distinct outputs to output for the cards drawn - the cards' names do not have to be used.
• You may output changes in Intelligence, wish uses, and wish becoming unusable in any consistent, unambiguous manner of your choosing.
• The character may use wish or the power of The Fates to avoid death if the appropriate card is drawn as the fifth card after drawing Rogue or Flames. Only if wish is unusable or all of the uses have been used, as well as The Fates is not drawn in time or has already been used, will the character die.
• Fool and Jester are discarded after they are drawn. All other cards are immediately returned to the deck, and the deck is then shuffled.
• If there are multiple stacks of Rogue and/or Flame active, only one use of The Fates or wish is necessary to dispel all of them.
• Drawing multiple cards at once via Jester or Fool does not advance the turn counter on Flames and/or Rogue.

## Examples

Each line represents a sequence of draws. Changes to Intelligence and wish uses are shown by the current value in parentheses. A C next to a wish use denotes that wish cannot be used anymore. A F denotes that the power of The Fates was used to avoid death. Additional comments are provided for explanatory purposes, in the form of Python-style comments.

Void # Can't draw with your soul ripped out of your body.
Throne, Euryale, Rogue, Star (12), Donjon # Can't draw while in suspended animation.
Moon (3), Throne, Sun, Flames (2), Fool, Idiot (6), Flames (1 C), The Fates, Skull (F), Skull # Two uses of wish were used on the two Flames draws. The second use rendered the character unable to use wish again. The Fates was used on the first Skull. When the second Skull came up, there was no way for the character to save himself, so he died.
Idiot (5), Star (7), Idiot (3) # Too dumb to draw.
Sun, Star (12), Talons # Talons destroys the deck.
Fates, Throne, Moon (2), Fates, Skull (F), Skull # Fates doesn't stack
Fates, Flames, Euryale, Fates, Skull, Void
Flames, Comet, Euryale, Gem, Knight, Key # 5 draws after Flames, the hero dies
Rogue, Balance, Throne, Gem, Idiot (8), Vizier, Sun # 5 draws plus one extra from Idiot


## Reference Implementation

#!/usr/bin/env python3

import random

deck="""Sun
Moon
Star
Throne
Key
Knight
Void
Flames
Skull
Ruin
Euryale
Rogue
Jester
Vizier
Comet
Fates
Gem
Talons
Idiot
Donjon
Balance
Fool""".split()

random.shuffle(deck)

int_stat = 10
wish_uses = 0
wish_expired = False
fates = False
turn_count = None

while True:
card = deck.pop()
if card == "Fates":
if turn_count is None:
fates = True
print(card)
else:
turn_count = None
fates = False
print("{} (F)".format(card))
elif card == "Moon":
wish_uses += random.randint(1, 3)
if turn_count is None:
print("{} ({})".format(card, wish_uses))
else:
turn_count = None
wish_uses -= 1
print("{} ({}) ({})".format(card, wish_uses+1, wish_uses))
elif card in ["Flames", "Rogue"]:
if turn_count is None:
turn_count = 5
if fates:
fates = False
turn_count = None
print("{} (F)".format(card))
elif wish_uses > 0 and not wish_expired:
wish_uses -= 1
turn_count = None
wish_now_expired = random.choice([False, False, True])
print("{} ({}{})".format(card, wish_uses, " C" if wish_expired else ""))
wish_expired = wish_now_expired
else:
print("{}".format(card))
elif card == "Idiot":
int_stat -= random.randint(2, 5)
print("{} ({})".format(card, int_stat))
if turn_count is not None:
turn_count += 1
if int_stat <= 3:
break
elif card == "Star":
int_stat += 2
print("{} ({})".format(card, int_stat))
elif card == "Skull":
if fates:
fates = False
turn_count = None
print("{} (F)".format(card))
elif wish_uses > 0 and not wish_expired:
wish_uses -= 1
turn_count = None
wish_now_expired = random.choice([False, False, True])
print("{} ({}{})".format(card, wish_uses, " C" if wish_expired else ""))
wish_expired = wish_now_expired
else:
print(card)
break
elif card in ["Donjon", "Void", "Talons"]:
print(card)
break
elif card == "Fool":
print(card)
if turn_count is not None:
turn_count += 1
elif card == "Jester":
print(card)
if turn_count is not None:
turn_count += 2
else:
print(card)
if card not in ["Fool", "Jester"]:
deck.append(card)
random.shuffle(deck)
if turn_count is not None:
turn_count -= 1
if turn_count == 0:
break


[1]: Technically, there are two variants: one with 13 cards, and one with 22 cards. We're only concerned about the full 22-card version here.

[2]: Flame and Rogue don't normally outright kill the character, but the hostile NPC is assumed to have found and killed the foolish character after they have time to draw 5 more cards. The spectre summoned by Skull is extremely difficult to fight, and it's assumed that the character doesn't win. Only divine/magical intervention via The Fates or Moon can save the foolish character from their death by these 3 cards.

[3]: We assume the character's friends are smart enough to not try to rescue the character and allow them to draw more cards.

[4]: An Intelligence score of 3 is roughly equivalent to a wild animal, which wouldn't be able to actively make the choice to draw cards.

• Sandbox – Mego Nov 6 '17 at 4:26
• Might be good to include some more example runs where a) the five turns expire, ideally with some bonus cards drawn in between, b) the fates is drawn twice, with and without making use of it in between. – Martin Ender Nov 8 '17 at 15:29
• Your reference implementation doesn't let the wish expire if it's used the moment Moon is drawn. And it also doesn't check there whether they have expired already. – Martin Ender Nov 8 '17 at 15:33
• One more thing: the original D&D rules mention additional cards for all of Idiot, Fool and Jester. Your rules first state that the player draws additional card for Idiot and Jester but then clarify the rule counter for Fool and Jester, and your reference implementation seems to draw only additional cards for Fool and Jester. Could you clarify/fix this? – Martin Ender Nov 8 '17 at 15:38
• @steenbergh I also read past it at first, but "After each card is drawn, it is returned to the deck, and the deck is shuffled.". Only the Fool and Jester will be removed when drawn, everything else is placed in the deck again and reshuffled every time before a new card is drawn. – Kevin Cruijssen Nov 8 '17 at 18:31

# JavaScript (ES6), 379 bytes

for(D=[...Array(21)].map((a,b)=>b),d={},i=10,w=e=f=t=0,F=_=>f=t=o=0,W=_=>{w--,t=0,o=w+(e?' C':''),e=1>r(2)},r=a=>0|Math.random()*a,$=1;$;){for(;d[c=r(22)];);o='',c?3>c?(t&&(t+=c),d[c]=1):4>c?f?F():0<w&&!e?W():$=0:7>c?$=0:9>c?(!t&&(t=5),f?F():0<w&&!e&&W()):10>c?(w+=1+r(2),t?(t=0,o=[w,--w]):o=w):11>c?(i-=2+r(3),o=i,$=3<i):12>c&&(i+=2,o=i):t?F():f=1,console.log(c,o),t&&(t--,$=t)}

### Ungolfed

let

print = (...x) => console.log(card, ...x),

// Uncomment for more human-friendly output:

### Ungolfed

let

deck = Sun Moon Star Throne Key Knight Void Flames Skull Ruin Euryale Rogue Jester Vizier Comet Fates Gem Talons Idiot Donjon Balance Fool.split ,

intelligence = 10,
wishUses = 0,
wishExpired = false,
fates = false,
turns = null,

useFates = () => {
fates = false
turns = null
print('F')
},
useWish = () => {
wishUses--
turns = null
print(wishUses + (wishExpired ? ' C' : ''))
wishExpired = random(2) < 1
},

print = (...x) => console.log(card + x.map(x =>  (${x})).join), random = n => Math.random() * n | 0, canDraw = true while(canDraw){ card = deck.splice(random(deck.length), 1)[0] switch(card){ case 'Fates': if(turns === null){ fates = true print() }else{ useFates() } break case 'Moon': wishUses += 1 + random(2) if(turns === null){ print(wishUses) }else{ turns = null wishUses-- print(wishUses + 1, wishUses) } break case 'Idiot': intelligence -= 2 + random(3) print(intelligence) if(intelligence <= 3){ canDraw = false } break case 'Star': intelligence += 2 print(intelligence) break case 'Flames': case 'Rogue': // Changed Condition if(turns === null){ turns = 5 } if(fates){ useFates() }else if(wishUses > 0 && !wishExpired){ useWish() }else{ // Added print() } break case 'Skull': if(fates){ useFates() }else if(wishUses > 0 && !wishExpired){ useWish() }else{ print() canDraw = false } break case 'Donjon': case 'Void': case 'Talons': print() canDraw = false break case 'Fool': if(turns !== null){ turns += 1 } break case 'Jester': if(turns !== null){ turns += 2 } break default: print() } if(!['Fool', 'Jester'].includes(card)){ deck.push(card) } if(turns !== null){ turns-- } if(turns === 0){ canDraw = false } } • @Mego honestly, I didn't really get it as well as I should've until seeing this answer, was well done; easy to understand when seeing the full names. If you change it can you keep a version with the full names? – Magic Octopus Urn Nov 6 '17 at 14:01 • @MagicOctopusUrn Certainly, I'll be sure to preserve the current full-name version in the future. – darrylyeo Nov 6 '17 at 16:05 • @Mego it was directed at OP, and was just saying "the version with the actual card names spelled fully made this implementation easy to read. If you shave bytes off, keep this one too, labeled as 'ungolfed'". – Magic Octopus Urn Nov 6 '17 at 16:45 • @MagicOctopusUrn Updated. – darrylyeo Nov 6 '17 at 20:38 # Kotlin, 1173 bytes fun main(args:Array<String>){val d="Sun Moon Star Throne Key Knight Void Flames Skull Ruin Euryale Rogue Jester Vizier Comet Fates Gem Talons Idiot Donjon Balance Fool".split(" ");var c=(Math.random()*22).toInt();var i=10;var u=0;var e=false;var f=false;var t=1;r@while(true){when(c){15->{if(t>=1){f=true;println(c)}else{t = 1;f = false;println("${d[c]} (F)")}}1->{u+=(Math.random()*3).toInt()+1;if(t>=1){println("${d[c]} ($u)")}else{t=1;u-=1;println("${d[c]} (${u + 1}) ($u)")}}in arrayOf(7,11)->{if(t>=1){t=5};if(f){f=false;t=1;println("${d[c]} (F)")}else if(u>0&&!e){u-=1;t=1;val n=(Math.random()*3).toInt();println("${d[c]} ($u$e)");e=n==0}else{println(d[c])}}18->{i-=(Math.random()*4).toInt()+2;println("${d[c]} ($i)");if (t!=0){t+=1};if(i<=3){break@r}}2->{i+=2;println("${d[c]} ($i)")}8->{if(f){f=false;t=1;println("${d[c]} (F)")}else if(u>0&&!e){u-=1;t=1;val n=(Math.random()*3).toInt();println("${d[c]} ($u\$e)");e=n==0}else{println(c);break@r}}in arrayOf(6,17,19)->{println(d[c]);break@r}21->{println(d[c]);if(t!=0){t += 1}}12->{println(d[c]);if(t!=0){t+=2}}else->{println(d[c])}};if((c !in arrayOf(12,21))){c=(Math.random()*23).toInt()};if(t!=0){t-=1}else{break}}}


It's runnable, too. - Try it online!

There's probably lots of bugs... let me know in the comments!

• Infinite loop printing Fool or Jester. – FrownyFrog Nov 9 '17 at 18:47

# Java 8, 481 480 bytes

v->{String r="";for(int i=10,d=22,c=d,F=0,t=0,w=0,W=0,j=Math.random()<.5?1:2;;c=d){c*=Math.random();r+=" "+c;if(c<1){F=1;r+=t>0?"F"+(F=0):"";t=-1;}else if(c<2){w+=Math.random()*3+1-(t>0?1:0);t=-1;}else if(c<4)t=F>0?-1:t<1?6:t;else if(c<5)t=F*w*W<1?1:-1;else if(c>19){t+=t>0?j:0;j=j%2+1;d--;}if(c>1&c<5&w*W>0){w--;W=(int)(Math.random()*3)%2;}i-=c==5?Math.random()*3+2:c==6?-2:0;r+=c>1&c<5&F>0?"F"+(F=0):c>0&c<5?"w"+w+"W"+W:c>4&c<7?"i"+i:"";if(--t==0|(c==5&i<4)|c>6&c<10)return r;}}


Ported the Python3 reference implementation in Java, and then golfed it down. Can definitely be golfed more, but this is just an initial version to make sure I did everything correct.

If anyone spots any mistakes (it wouldn't surprise me if there are any EDIT: Already fixed like seven or eight mistakes since I posted this..), please let me know.

Card outputs:

0: Fates
1: Moon
2: Flames
3: Rogue
4: Skull
5: Idiot
6: Star
7/8/9: Donjon/Void/Talons
20/21: Fool/Jester

10-19: everything else (Sun/Throne/Key/Knight/Ruin/Euryale/Vizier/Comet/Gem/Balance)

Output format for wishes left, wishes used, intelligence left, and flag used:

4w1W0
4       // Card drawn
w1     // New amount of wishes left
W0   // Whether the wishes used flag is active (1) or inactive (0)

5i6
5       // Card drawn
i6     // New intelligence

0F0
0       // Card drawn
F0     // Fates used


Explanation:

v->{                       // Method with empty unused parameter and String return-type
String r="";             //  Result-String, starting empty
for(int i=10,            //  Intelligence
d=22,            //  Amount of cards in the deck, starting at 22
c=d,             //  Current card drawn
F=0,             //  Fates flag
t=0,             //  Turn-counter
w=0,             //  Wishes left
W=0,             //  Wishes used flag
j=Math.random()<.5?1:2;
//  Whether Jester/Fool is drawn first of the two
;                    //  Loop indefinitely
c=d){               //    After every iteration, shuffle the deck (reset c)
c*=Math.random();      //   Draw a random 0-21 card (or less if Fool/Jester is gone)
r+=" "+c;              //   Append the result with a space and this card
if(c<1){               //   If the card was Fates:
F=1;                 //    Set the Fates-flag to active
r+=t>0?              //    If the turn-counter is larger than 0:
"F"+(F=0)        //     Append that Fates was used (and make Fates inactive)
:                 //    Else:
"";              //     Append nothing
t=-1;}               //    Set the turn-counter to -1 (none)
else if(c<2){          //   If the card was Moon instead:
w+=Math.random()*3+1 //    Increase the wishes by 1-3 randomly
-(t>0?            //    Then, if the turn-counter is larger than 0
1              //     Subtract 1 from the amount of wishes
:               //    Else:
0);            //     Leave the wishes the same
t=-1;}               //    Set the turn-counter to -1 (none)
else if(c<4)           //   If the card was Flames or Rogue instead:
t=F>0?               //    If the Fates-flag is active:
-1                //     Set the turn-counter to -1 (none)
:t<1?              //    Else-if the turn-counter is 0 or -1 (none):
6                 //     Set the turn-counter to 6
:                  //    Else:
t;                //     Leave the turn-counter the same
else if(c<5){          //   If the card was Skull instead:
t=F                  //    If the Fates-flag is inactive
*w                 //    or the amount of wishes is smaller than 1
*W<1?              //    or the wishes used flag is inactive
1                 //     Set the turn-counter to 1
:                  //    Else:
-1;               //     Set the turn-counter to -1 (none)
F=0;}                //    Then set the Fates-flag to inactive
else if(c>19){         //   If the card was Fool or Jester instead:
t+=t>0?              //    If the turn-counter was not 0 or -1 (none):
j                //     Increase either by 1 (Fool) or 2 (Jester)
:                 //    Else:
0;               //     Leave the turn-counter the same
j=j%2+1;             //    Fix j (2->1; 1->2)
d--;}                //    And remove the Fool/Jester from the Deck
if(c>1&c<5             //   If the card drawn was Flames, Rogue or Skull,
&w                  //   and the amount of wishes is at least 1,
*W>0){             //   and the wishes used flag is active
w--;                 //    Decrease the amount of wishes by 1
W=(int)(Math.random()*3)%2;}
//    And set the wishes used flag to one of (0,0,1)
i-=c==5?               //   If the card drawn was Idiot:
Math.random()*3+2  //    Decrease the intelligence by 2-5 randomly
:c==6?              //   Else-if the card drawn was Star:
-2                 //    Increase the intelligence by 2
:                   //   Else:
0;                 //    Leave the intelligence the same
r+=c>1&c<5             //   If the card drawn was Flames, Rogue or Skull,
&F>0?               //   and Fates is active
"F"+(F=0)          //    Append that Fates was used (and make Fates inactive)
:c>0&c<5?           //   Else-if the card drawn was Moon, Flames, Rogue or Skull:
"w"+w+"W"+W        //    Append the amount of wishes left and wishes used flag
:c>4&c<7?           //   Else-if the card drawn was Idiot or Star:
"i"+i              //    Append the amount of intelligence left
:                   //   Else:
"";                //    Append nothing
if(--t                 //   Decrease the turn-counter by 1
==0              //   And if the turn-counter is now 0,
|(c==5              //   or the card drawn was Idiot,
&i<4)         //   and the intelligence dropped below 4,
|c>6&c<10)          //   or the card drawn was Donjon, Void or Talons:
return r;         //    Return the result of the game
}                        //  End of loop
}                          // End of method

• Jester; Fates; Ruin; Euryale; Gem; Ruin; Ruin; Rogue(Fates used) Gem; Balance; Throne; Rogue(wishes left: 0; wishes used: 0); Rogue(wishes left: 0; wishes used: 0); Why did it stop? – FrownyFrog Nov 9 '17 at 18:57
• @FrownyFrog Thanks! Should be fixed now. If you spot any other mistakes, let me know. :) – Kevin Cruijssen Nov 9 '17 at 21:53