Trying to stop a random generator from delivering the same output multiple times

I’m working on a program that outputs a certain number of cards from something called a deck of many things (its a D&D thing). The user inputs how many cards they would like to draw before running the program and then the program runs a for loop however many times the user specified to output that number of random cards. The issue that I’m having is that I don’t want the program to be able to output the same card multiple times. For example, if the user draws 5 cards I don’t want them to be able to draw card number 21 twice. Is there any way to accomplish this? I’ve been trying to think of how to do it with the continue aspect of loops. I can share the code if necessary.

that would be very helpful :slight_smile:

there are couple things you can do, depending on your existing code

if you have the deck as an array, you could pop the drawn card
or you could make an array of the drawn cards/random numbers and check the number hasn’t been generated yet

1 Like

I will paste my current code below. It runs without any errors, but I haven’t added any code to stop it from returning the same output yet,

import random
number_of_draws = 5
card = ‘’
#add something so you can’t get same card in one round of drawing (continue?)
for card in range(number_of_draws):
ran = random.randint(1,22)
if ran == 1:
card = ‘Vizier’
print(card)
print(‘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.’)
elif ran == 2:
card = ‘Sun’
print(card)
print(‘You gain 50,000 XP, and a wondrous item (which the DM determines randomly) appears in your hands.’)
elif ran == 3:
card = ‘Moon’
print(card)
print(‘You are granted the ability to cast the wish spell 1d3 times.’)
elif ran == 4:
card = ‘Star’
print(card)
print(“Increase one of your Ability Scores by 2. The score can exceed 20 but can’t exceed 24.”)
elif ran == 5:
card = ‘Comet’
print(card)
print(‘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.’)
elif ran == 6:
card = ‘The Fates’
print(card)
print(“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.”)
elif ran == 7:
card = ‘Throne’
print(card)
print(‘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.’)
elif ran == 8:
card = ‘Key’
print(card)
print(‘A rare or rarer Magic Weapon with which you are proficient appears in your hands. The DM chooses the weapon.’)
elif ran == 9:
card = ‘Knight’
print(card)
print(‘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.’)
elif ran == 10:
card = ‘Gem’
print(card)
print(‘Twenty-five pieces of jewelry worth 2,000 gp each or fifty gems worth 1,000 gp each appear at your feet.’)
elif ran == 11:
card = ‘Talons’
print(card)
print(“Every magic item you wear or carry disintegrates. Artifacts in your possession aren’t destroyed but do Vanish.”)
elif ran == 12:
card = ‘The Void’
print(card)
print(“This black card Spells Disaster. Your soul is drawn from your body and contained in an object in a place of the DM’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.”)
elif ran == 13:
card = ‘Flames’
print(card)
print(‘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.’)
elif ran == 14:
card = ‘Skull’
print(card)
print(“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 DM’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.”)
elif ran == 15:
card = ‘Idiot’
print(card)
print(‘Permanently reduce your Intelligence by 1d4 + 1 (to a minimum score of 1). You can draw one additional card beyond your declared draws.’)
elif ran == 16:
card = ‘Donjon’
print(card)
print(“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.”)
elif ran == 17:
card = ‘Ruin’
print(card)
print(‘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.’)
elif ran == 18:
card = ‘Euryale’
print(card)
print(“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.”)
elif ran == 19:
card = ‘Rogue’
print(card)
print(“A nonplayer character of the DM’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.”)
elif ran == 20:
card = ‘Balance’
print(card)
print(‘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.’)
elif ran == 21:
card = ‘Fool’
print(card)
print(‘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.’)
elif ran == 22:
card = ‘Jester’
print(card)
print(‘You gain 10,000 XP, or you can draw two additional cards beyond your declared draws.’)
print(’’’
‘’’)

Just updated my code to this actually, I think it fixes the problem of generating a variable multiple times. Had to fix an issue with unbalanced probability since it allowed for the generation of negative index values but I think that issue is fixed now. Let me know what you think, I think its much more elegant than the previous code.

import random
cards_and_descriptions = [['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.'], ['Sun', 'You gain 50,000 XP, and a wondrous item (which the DM determines randomly) appears in your hands.'], ['Moon', 'You are granted the ability to cast the wish spell 1d3 times.'], ['Star', "Increase one of your Ability Scores by 2. The score can exceed 20 but can't exceed 24."], ['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.'], ['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."], ['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.'], ['Key', 'A rare or rarer Magic Weapon with which you are proficient appears in your hands. The DM 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.'], ['Gem', 'Twenty-five pieces of jewelry worth 2,000 gp each or fifty gems worth 1,000 gp each appear at your feet.'], ['Talons', "Every magic item you wear or carry disintegrates. Artifacts in your possession aren't destroyed but do Vanish."], ['The Void', "This black card Spells Disaster. Your soul is drawn from your body and contained in an object in a place of the DM'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."], ['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.'], ['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 DM'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."], ['Idiot', 'Permanently reduce your Intelligence by 1d4 + 1 (to a minimum score of 1). You can draw one additional card beyond your declared draws.'], ['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."], ['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.'], ['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."], ['Rogue', "A nonplayer character of the DM'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."], ['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.'], ['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.'], ['Jester', 'You gain 10,000 XP, or you can draw two additional cards beyond your declared draws.']]
# cards_and_descriptions index cheatsheet: Vizier 0, Sun 1, Moon 2, Star 3, Comet 4, Fates 5, Throne 6, Key 7, Knight 8, Gem 9, Talons 10, Void 11, Flame 12, Skull 13, Idiot 14, Donjon 15, Ruin 16, Euryale 17, Rogue 18, Balance 19, Fool 20, Jester 21
card = ''
def card(draws):
for i in range(draws):
ran = random.randint(0,21) - i
if ran < 0:
draws += 1
continue
card = cards_and_descriptions[ran][0]
description = cards_and_descriptions[ran][1]
cards_and_descriptions.pop(ran)
print(card)
print(description)
print('''
''')

card(5)

Actually that code still has some stuff that doesn’t function as it should. I fixed the issue of it returning the same card multiple times but created one of it not always drawing the correct number of cards

your code didn’t have any indention, please format your code:

[How-to] Create a topic that everyone will read

I simplify the process by ensuring no negative numbers can be generated:

ran = random.randint(i,21) - i

Your solution makes it so that with each iteration you lose two possible outcomes instead of one. I thought it over for awhile and came up with a solution. I used ran = random.randint(0, len(cards_and_descriptions) -1) instead but you could also use ran = random.randint(0, 21 - i). Apologies for not formatting the code correctly. Thanks for your help! Code runs great now

1 Like