Creating the war(card) game using OOP in Python - python

I am trying to create the war card game where 2 players draw a card each on the table, and the player whose card has max value gets both the cards, if the card values are equal(called war condition) each player draws 5 cards, and the value of the last card among these 5 cards are compared and works similarly as above. A player wins when either the other player runs out of cards or if in war condition the other player has less than 5 cards.
My questions:
When I am running the game logic sometimes it runs but sometimes it gets stuck in an infinite loop. Why?
I can notice that when the total number of cards for both players at all times should be 52, but here it is decreasing. Why? (I can see that the cards are getting lost every time the game goes into war condition, but I am not able to understand why that is happening, since I am adding all the 10 cards to the player whose card has a greater value.)
I have tried another method where I assume that players are always at war and then approach it, which works. But I want to understand why, if I break it into steps which I am trying to do here, is it not working?
Code:
import random
suits = ['Hearts','Clubs','Spades','Diamonds']
ranks = ['Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten','Jack','Queen','King','Ace']
values = {'Two': 2, 'Three': 3, 'Four': 4, 'Five': 5, 'Six' : 6 , 'Seven' :7, 'Eight': 8,'Nine':9,
'Ten':10,'Jack':11, 'Queen': 12,'King': 13,'Ace':14 }
classes:
class Card():
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
self.value = values[rank]
#string method
def __str__(self):
return self.rank + ' of ' + self.suit
class Deck():
def __init__(self):
self.all_cards = [] #list of objects
for suit in suits:
for rank in ranks:
#create card object
created_card = Card(suit,rank)
self.all_cards.append(created_card)
def shuffle(self): #method to shuffle the card
random.shuffle(self.all_cards)
def deal_one(self):
return self.all_cards.pop() #we want the last card from deck
class Player():
def __init__(self,name):
self.name = name
self.all_cards = []
def remove_one(self):
return self.all_cards.pop(0) #to remove card from beginning of the list
def add_cards(self,new_cards):
if type(new_cards) == type([]):
self.all_cards.extend(new_cards)
else:
self.all_cards.append(new_cards)
def __str__(self):
return f'Player {self.name} has {len(self.all_cards)} cards.'
And below is the final game logic:
#create 2 new instances of the player class
player1_name = input('Enter the name of Player1: ')
player2_name = input('Enter the name of Player2: ')
player1 = Player(player1_name)
player2 = Player(player2_name)
newdeck = Deck()
newdeck.shuffle()
#splitting the deck among the two players - alternate card from deck goes to each player respectively
for i in range(0,len(newdeck.all_cards)-1,2):
player1.add_cards(newdeck.all_cards[i])
player2.add_cards(newdeck.all_cards[i+1])
#for x in range(26):
# player1.add_cards(newdeck.deal_one())
#player2.add_cards(newdeck.deal_one())
print(player1)
print(player2)
game_status = True
round_num = 0
while game_status == True:
round_num +=1
print(f"Round {round_num}")
if len(player1.all_cards) == 0:
print('Player 1 out of cards'+ player2.name + 'Wins!')
game_status = False
break
if len(player2.all_cards) == 0:
print('Player 2 out of cards' + player1.name + 'Wins!')
game_status = False
break
else:
player_cards = []
player1_card = player1.remove_one()
player2_card = player2.remove_one()
player_cards.append(player1_card)
player_cards.append(player2_card)
print('player1_card_value: ',player1_card.value)
print('')
print('player2_card_value: ',player2_card.value)
print('')
print(player1)
print('')
print(player2)
at_war = True
if player1_card.value == player2_card.value:
while at_war == True:
player1_list = []
player2_list = []
card_list = []
if len(player1.all_cards) < 5:
print('Player 2 won')
game_status = False
at_war = False
break
elif len(player2.all_cards) <5:
print('Player 1 won')
game_status = False
at_war = False
break
if len(player1.all_cards) >= 5 and len(player2.all_cards) >= 5:
for i in range(5):
player1_list.append(player1.remove_one())
player2_list.append(player2.remove_one())
card_list.extend(player1_list)
card_list.extend(player2_list)
print("CARD LIST LEN", len(card_list))
if player1_list[0].value > player2_list[0].value:
player1.add_cards(card_list)
at_war = False
break
elif player1_list[0].value < player2_list[0].value:
player2.add_cards(card_list)
#player2.add_cards(player1_list)
at_war = False
break
else:
at_war = True
elif player1_card.value > player2_card.value:
player1.add_cards(player_cards)
#player1.add_cards(player2_cards)
#print('p1>p2', player1)
elif player2_card.value > player1_card.value:
player2.add_cards(player_cards)
print(player1)
print(player2)
if len(player1.all_cards) == 0:
print('Player 2 won')
elif len(player2.all_cards) == 0:
print('Player 1 won')
Output: When it was stuck in an infinite loop:(You can see the total number of cards is now 34 instead of 52.)

Related

Created an endless loop, but can't tell why it is endless

So I am creating a card game in python using classes. I got it all set up to the point where it should work. But when I ran it it just simply never stops running. I am not really sure how to make this code minimal and reproduceable, because I do not know where the issue is at.
Here is the code i have written.
It has to be in the play_uno() class object.
""" UNO Simulator """
import random
class card():
def __init__(self, value, color, wild):
'''
An UNO deck consists of 108 cards, of which there are 76 Number cards,
24 Action cards and 8 Wild cards. UNO cards have four color "suits",
which are red, yellow, blue and green.
'''
self.card_nums = ['0','1','2','3','4','5','6','7','8','9']
self.card_colors = ['red','blue','green','yellow']
self.spec_cards = ['draw2','reverse','skip']
self.wild_cards = ['wild','wild_draw_4']
if wild == False:
self.value = self.card_nums[value]
self.color = self.card_colors[color]
elif wild == 'special':
self.value = self.spec_cards[value]
self.color = self.card_colors[color]
elif wild == True:
self.value = self.wild_cards[value]
self.color = None
class generate_deck():
def __init__(self):
self.number_cards = self.get_num_cards()
self.special_cards = self.get_special_cards()
self.wild_cards = self.get_wild_cards()
self.cards = self.number_cards + self.special_cards + self.wild_cards
random.shuffle(self.cards)
def get_num_cards(self):
# only one zero per color
with_zeroes = [card(i,j,False) for i in range(10) for j in range(4)]
no_zeroes = [card(i,j,False) for i in range(1,10) for j in range(4)]
return no_zeroes + with_zeroes
def get_wild_cards(self):
wild_draw4s = [card(i,None,True) for i in range(2) for x in range(2)]
wilds = [card(i,None,True) for i in range(2) for x in range(2)]
return wilds + wild_draw4s
def get_special_cards(self):
return [card(i,j,'special') for i in range(3) for j in range(4) for x in range(2)]
class player():
def __init__(self, name):
self.wins = 0
self.name = name
self.cheater = False
self.cards = ''
self.turn = 0
self.uno = 0
class play_uno():
def __init__(self, num_players = 3, num_cheaters = 0, cards_per_player = 5):
# get started
self.rules = 'default'
self.status = 'ongoing'
self.deck = generate_deck().cards
self.played_cards = []
self.dro = 0
self.direction = 0
self.top_card = self.deck.pop() # random card as first card to play on
self.tot_turns = 0
# generate players, make cheaters later
self.players = [player('player' + str(i)) for i in range(num_players + num_cheaters)]
# give each player 7 cards to start
for _player_ in self.players:
_player_.cards = [self.draw_card() for i in range(cards_per_player)]
# start playing turns in order
# do not know how to reverse yet
"""
Right now it is endless for some reason.
"""
while self.status == 'ongoing':
for _player in self.players:
self.turn(_player)
def draw_card(self):
# draws random card from deck instead of card on top
if len(self.deck) == 0:
self.re_shuffle()
self.dro += 1
return self.deck.pop()
def re_shuffle(self):
self.deck = self.played_cards
random.shuffle(self.deck)
self.played_cards = []
return self.deck, self.played_cards
def play_card(self, player_cards, _card):
self.top_card = _card
return player_cards.remove(_card), self.played_cards.append(_card), self.top_card
def game_over(self, winner):
winner.wins += 1
self.game_status = 'over'
def turn(self, _player):
played = False
# check if someone played wild card last turn
if self.top_card.value in card(1,2,None).wild_cards:
self.top_card.color = random.choice(card.card_colors)
if self.top_card.value == 'wild_draw_4':
_player.cards += [self.draw_card() for i in range(4)]
self.tot_turns += 1
return _player
# check for special cards
elif self.top_card.value in card(1,2,None).spec_cards:
if self.top_card.value == 'draw2':
_player.cards += [self.draw_card() for i in range(4)]
self.tot_turns += 1
return _player
# for now we are treating reverse cards like skips
elif self.top_card.value == 'reverse' or self.top_card.value == 'skip':
played = True
self.tot_turns += 1
return _player
# If its a normal card, or regular wild
if played == False:
for _card in _player.cards:
if _card.color == self.top_card.color:
self.play_card(_player.cards, _card)
played = True
break
elif _card.value == self.top_card.value:
self.play_card(_player.cards, _card)
played = True
break
# if the player cannot play at all
# rn they just move on if they have to draw,
# cant play the card they just drew.
if played == False:
_player.cards += [self.draw_card()]
played = True
self.tot_turns += 1
# check if the player won or not
if len(_player.cards) == 0:
self.game_over(_player)
elif len(_player.cards) == 1:
_player.uno += 1
return _player.cards
In the function turn in the play_uno class you are checking for certain wild/special cards. If the value is reverse, for example, the function hits a return _player line which ends the execution of the function and the player is unable to play another card.
Move the return statements to the end of the function if you want to ensure the rest of the code is run.
I did not run the code, but I think you should test a player's number of cards before drawing again. Like this:
if len(_player.cards) == 0:
self.game_over(_player)
elif len(_player.cards) == 1:
_player.uno += 1
if played == False:
_player.cards += [self.draw_card()]
played = True
self.tot_turns += 1
Or are the rules of this game different? I sincerely don't remember them anymore.
The while loop at the end of play_uno's __init__ checks for status, which never changes.
The loop calls turn on each of players every iteration. You must change status somewhere or you must put an if ...: break in the while loop (e.g. if not _player.cards).
EDIT: It appears that you meant self.status instead of self.game_status, in game_over. Try changing game_status to status there.

Making card game, how do I give the face cards value

Im making a card game for a project for my high school class. I'm making black jack but with changed rules and new features. I am using the random plugin to randomize the numbers. I am not using suits but am using face cards. How do I make it so if a user gets a face card like 'King' the program knows the value of the face card and able to calculate the total.
For example if one user gets a 3 card and a King card their total will be 13 as King = 10. How will I make the face cards have values and put it into a list with the normal cards
Here is my code so far, I know how to deal more cards later, just want to know how to add face cards and their value to shuffle. Thanks
while len(dealer_cards) != 2:
dealer_cards.append(random.randint(2, 10))
if len(dealer_cards) == 2:
print("The Dealer has:", dealer_cards)
# Players cards
while len(player_cards) != 2:
player_cards.append(random.randint(2, 10))
if len(player_cards) == 2:
print("You have:", player_cards)
One way is to define the card as an object (dictionary)
Note that this is just a way to build your logic: This doesn't take into effect other rules (like how many total cards and if the same card gets dealt out twice. You need more rules and house-keeping for that
card = {
"face": "K", # This indicates what is printed on the face
"value": 10, # This indicates the value (used internally)
"suite": "spade", # will be one of ["spade", "jack", "clubs", "hearts"]
}
define a function to get a random card:
def getRandomCard():
# list of possible cards with their values
cards = [("1", 1), ("2", 2).. ("J", <value>), ("Q", <value>), ("K", <value>), ("A", <value>)]
randIdx = <Get random number>
randomCard, randomCardValue = cards[randIdx % len(cards)] #
suits = ["spade", "jack", "clubs", "hearts"]
randomSuite = <similarly pick a random suite>
return {
"face": randomCard,
"value": randomCardValue,
"suite": randomSuite
}
Now rest of your code deals with the card object.
you get the idea..
I quickly wrote this bare bones blackjack game. It doesn't have betting, splitting, or even the logic to say if who wins but it does the basic game play. I hope you can look at this example of Object Oriented programming and maybe learn something.
import random
class Card:
suits = {0:"Spades",
1:"Heaarts",
2:"Clubs",
3:"Dimods"}
names = {1:"Ace",
2:"Duce",
3:"Three",
4:"Four",
5:"Five",
6:"Six",
7:"Seven",
8:"Eight",
9:"Nine",
10:"Ten",
11:"Jack",
12:"Queen",
0:"King"}
def __init__(self,id):
self.id = id
self.name = id%13
self.suit = int((id-1)/13)
def announce(self):
return Card.names[self.name]+" of "+Card.suits[self.suit]
def value(self):
if self.name > 10:
return 10
if self.name == 1:
return 0
else:
return self.name
class Deck:
def __init__(self):
self.cards=[int(k) for k in range(1,53)]
def restock(self):
self.cards = range(1,53)
def deal(self):
cardIndex = random.choice(range(len(self.cards)))
cardId = self.cards[cardIndex]
del self.cards[cardIndex]
return Card(cardId)
def evaluate(hand):
total = 0
aces = 0
for c in hand:
v = c.value()
if v:
total+= v
else:
aces+=1
while aces > 0:
aces-=1
if total<11-aces:
total+=11
else:
total+=1
return 0 if total>21 else total
class Player:
deck = Deck()
def __init__(self):
self.hand = []
def getCard(self):
self.hand.append(self.deck.deal())
def discard(self):
self.hand = []
def play(self):
print("Player has:")
print(self.hand[0].announce())
print(self.hand[1].announce())
hitOrStand="hit"
v = evaluate(self.hand)
while hitOrStand != "stand" and v:
hitOrStand = input("hit or stand:")
if hitOrStand not in ["hit","stand"]:
print("please enter `hit` or `stand`.")
continue
if hitOrStand == "hit":
self.getCard()
print(self.hand[-1].announce())
v = evaluate(self.hand)
print(v if v else "bust")
class Dealer(Player):
def hits(self):
v = evaluate(self.hand)
return True if v<17 and v else False
def play(self):
print("Dealer has:")
print(self.hand[0].announce())
print(self.hand[1].announce())
while self.hits():
print("And gets:")
self.getCard()
print(self.hand[-1].announce())
v = evaluate(self.hand)
v = evaluate(self.hand)
print(v if v else "bust")
def restock(self):
Player.deck.restock()
class Game:
def __init__(self):
self.player = Player()
self.dealer = Dealer()
def playRound(self):
self.player.getCard()
self.dealer.getCard()
self.player.getCard()
self.dealer.getCard()
self.player.play()
self.dealer.play()
self.player.discard()
self.dealer.discard()
self.dealer.restock()
g = Game()
g.playRound()

List index out of range in class

All code
import random
import time
class Enemy():
def __init__(self):
self.health = 100
self.power = random.randint(10,20)
def hit(self, player):
player.health -= self.power
class player():
def __init__(self):
self.health = 300
self.power = 50
def hit(self, Enemy):
Enemy.health -= self.power
player1 = player()
enemies = []
for i in range(5): # create 5 enemy
enemies.append(Enemy())
print("Play - Help - Quit")
action1 = input("Type 'hit' for enemies\n>>>> ")
while action1 != 'q':
print("---------------")
for i in range(len(enemies)):
print("#{}.enemy heatlh-->{}".format(i, enemies[i].health))
print("----------------")
random_enemy = random.randint(1, 5)
action = input(">>>> ")
if action == 'hit':
which = int(input("Which enemy? there are {} enemies\n>>>>".format(len(enemies))))
if enemies[which].health == 0:
enemies[which].health = 0
print("\nThis is a death enemy")
else:
player1.hit(enemies[which])
damage_enemy = random.randint(1,5)
if enemies[random_enemy].health == 0:
continue
else:
if damage_enemy == 1 or damage_enemy == 3 or damage_enemy == 4:
if enemies[which].health == 0 or enemies[which].health <= 0:
enemies[which].health = 0
print("{}. enemy death HP: {} ".format(which, enemies[which].health))
else:
enemies[random_enemy].hit(player1)
print("{}. enemy hit you {} damage, your HP: {} ".format(random_enemy,enemies[random_enemy].power,player1.health))
elif enemies[which].health != 0 or enemies[which].health >= 0:
print("{}. enemy HP: {} ".format(which, enemies[which].health))
elif action == 'q':
break
I get this error at random time, my list size is 5, enemies die and their healths are 0. They stay there, but for some reason sometimes I get this error.
#0.enemy heatlh-->100
#1.enemy heatlh-->100
#2.enemy heatlh-->0
#3.enemy heatlh-->0
#4.enemy heatlh-->100
if enemies[random_enemy].health == 0:
continue
The random.randint(1, 5) can return 5. Your list has 5 elements, but the indices are from 0 to 4.
P.S. Also, the minimum value that you get is 1. Not 0.

How do I swap which function runs at the beginning of my while loop?

I have just starting learning Python and I am writing a rudimentary Blackjack game. I have got the basic stuff working but I want to add a little bit of finesse here and there. I am looking for a way in which my introduction function at the beginning of my while loop is substituted for my new_round function.
My idea was that I could have a round counter running at the top which would dictate which function would run through and if/elif statement.
Suffice it to say, it doesn't work. Firstly, I would like to know why it doesn't and secondly would like a way to do it!
import random
suits = ('Hearts', 'Diamonds', 'Spades', 'Clubs')
ranks = ('Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace')
values = {'Two':2, 'Three':3, 'Four':4, 'Five':5, 'Six':6, 'Seven':7, 'Eight':8, 'Nine':9, 'Ten':10, 'Jack':10, 'Queen':10, 'King':10, 'Ace':11}
player_name = ''
playing = True
class Card:
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
def __str__(self):
return f'{self.rank} of {self.suit}'
class Deck:
def __init__(self):
self.deck = []
for suit in suits:
for rank in ranks:
self.deck.append(Card(suit,rank))
def __str__(self):
deck_comp = ''
for card in self.deck:
deck_comp += '\n '+card.__str__()
return 'The deck has:' + deck_comp
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
single_card = self.deck.pop()
return single_card
class Hand:
def __init__(self):
self.cards = []
self.value = 0
self.aces = 0
def add_card(self,card):
self.cards.append(card)
self.value += values[card.rank]
if card.rank == 'Ace':
self.aces += 1
def adjust_for_ace(self):
#if value of players hand is over 21 and includes an ace then the player will automatically have the ace value reduced to 1
#also track ace counter will revert to 0
while self.value > 21 and self.aces > 0:
self.value -= 10
self.aces -= 1
class Chips:
def __init__(self,total):
self.total = total
self.bet = 0
def win_bet(self):
self.total += self.bet
def lose_bet(self):
self.total -= self.bet
def take_bet(chips):
while True:
try:
player_chips.bet = int(input('How many chips would you like to bet?: '))
except ValueError:
print('\nSorry, the number of chips must be a number!')
else:
if player_chips.bet > player_chips.total:
print(f"\nSorry guy, your bet can't exceed {player_chips.total} chips.")
else:
print(f"\nYour bet of {player_chips.bet} chips has been accepted - good luck!")
break
def introduction():
global player_name
print("\nWelcome to BlackJack! Get as close to 21 as you can without busting.\n\nThe Dealer will hit up to 17, Face cards count as 10 and Aces are 1/11.")
player_name=input("The first round is about to begin, what is your name friend?: ")
def next_round():
global player_name
print("Hey ho, let's go another round!")
def chip_count():
global player_name
print(f"{player_name}, your current chip count stands at {player_chips.total}")
def play_again():
global player_name
global playing
while True:
replay = input(f"{player_name}, would you like to play another round?: ").upper()
if replay[0] == 'Y':
return True
elif replay[0] == 'N':
print(f"\nThanks for playing - you leave the table with {player_chips.total} chips.")
break
else:
print("Sorry, I don't understand what you are saying, do you want to play the next round, or not? Y or N!: ")
continue
def total():
global player_name
while True:
try:
total = int(input(f'Hello {player_name}, how many chips will you be using this game?: '))
except ValueError:
print('\nSorry, the number of chips must be a number!')
else:
return total
print(f"\nWelcome to the table - you currently have {total} chips to play with.")
def hit(deck,hand):
#run the add card function within the Hand Class with the card argument being generated by the deal function within the Deck Class.
hand.add_card(deck.deal())
hand.adjust_for_ace()
def hit_or_stand(deck,hand):
global player_name
global playing
while True:
response = input(f"{player_name}, Would you like to hit or stand?: ")
if response[0].upper() == 'H':
hit(deck,hand)
elif response[0].upper() == 'S':
print(f"{player_name} stands. It is the Dealer's turn")
playing = False
else:
print("\nI can't understand what you are saying - are you hitting or standing?!")
continue
break
def show_some(player,dealer):
print("\nDealer's Hand:")
print("<card hidden>")
print(dealer.cards[1])
print("\nPlayer's Hand: ",*player.cards, sep='\n')
print("Value of your cards: ",player.value)
def show_all(player,dealer):
print("\nDealer's Hand: ",*dealer.cards, sep='\n')
print("Dealer's Hand = ",dealer.value)
print("\nPlayer's Hand: ",*player.cards, sep='\n')
print("Player's Hand = ",player.value)
def player_busts(player,dealer,chips):
global player_name
print(f"{player_name} busts!")
chips.lose_bet()
def player_wins(player,dealer,chips):
global player_name
print(f"{player_name} wins the round!")
chips.win_bet()
def dealer_busts(player,dealer,chips):
print("Dealer busts!")
chips.win_bet()
def dealer_wins(player,dealer,chips):
print("Dealer wins!")
chips.lose_bet()
def push(player,dealer,chips):
print("You have tied with the Dealer! It's a push, your chips have been refunded.")
############################################################################################################################################################
while True:
counter = 0
if counter > 0:
next_round()
elif counter == 0:
introduction()
#Create & shuffle the deck, deal 2 cards to each player.
deck = Deck()
deck.shuffle()
player_hand = Hand()
player_hand.add_card(deck.deal())
player_hand.add_card(deck.deal())
dealer_hand = Hand()
dealer_hand.add_card(deck.deal())
dealer_hand.add_card(deck.deal())
#Set up Player's chips
player_chips = Chips(total())
#Prompt the Player for their bet
take_bet(player_chips)
#Show cards (keep one dealer card hidden)
show_some(player_hand,dealer_hand)
while playing == True:
#Prompt for player hit or stand
hit_or_stand(deck,player_hand)
#show cards (keep one dealer card hidden)
show_some(player_hand,dealer_hand)
#if player's hand exceeds 21, player busts - break loop
if player_hand.value > 21:
player_busts(player_hand,dealer_hand,player_chips)
break
#if player hasn't bust, play dealer's hand until dealer reaches 17 or busts.
if player_hand.value <= 21:
while dealer_hand.value < 17:
hit(deck,dealer_hand)
#show all cards
show_all(player_hand,dealer_hand)
#run different winning scenarios
if dealer_hand.value > 21:
dealer_busts(player_hand,dealer_hand,player_chips)
elif dealer_hand.value > player_hand.value:
dealer_wins(player_hand,dealer_hand,player_chips)
elif dealer_hand.value < player_hand.value:
player_wins(player_hand,dealer_hand,player_chips)
else:
push(player_hand,dealer_hand,player_chips)
#inform player of their current chip count.
chip_count()
counter += 1
#play another round?
if play_again() == True:
continue
else:
break
You are resetting counter to 0 at the start of every loop.
You probably meant to set it to 0 before the loop started, then have it increase every loop.
Instead of:
while True:
counter = 0
if counter > 0:
try:
counter = 0
while True:
if counter > 0:
The issue in your code is that each time you loop through your While True: loop, you are setting the variable counter back to zero.... So even though you increment counter at the end of your loop, it is then immediately set back to zero as the loop restarts.
A different way to accomplish what you are looking for would be to run your introduction() function just before your While True: loop, and then edit the final lines of your code to call the next_round() function, as such:
if play_again() == True:
next_round()
continue

craps in python

I'm trying to simulate n games of craps. The code seems to make sense to me but I never get the right result. For example, if I put in n = 5 i.e. fives games the wins and losses sum to something greater than 5.
Here's how it's supposed to work: if initial roll is 2, 3, or 12, the player loses. If the roll is 7 or 11, the player wins. Any other initial roll causes the player to roll again. He keeps rolling until either he rolls a 7 or the value of the initial roll. If he re-rolls the initial value before rolling a 7, it's a win. Rolling a 7 first is a loss.
from random import randrange
def roll():
dice = randrange(1,7) + randrange (1,7)
return dice
def sim_games(n):
wins = losses = 0
for i in range(n):
if game():
wins = wins + 1
if not game():
losses = losses + 1
return wins, losses
#simulate one game
def game():
dice = roll()
if dice == 2 or dice == 3 or dice == 12:
return False
elif dice == 7 or dice == 11:
return True
else:
dice1 = roll()
while dice1 != 7 or dice1 != dice:
if dice1 == 7:
return False
elif dice1 == dice:
return True
else:
dice1 = roll()
def main():
n = eval(input("How many games of craps would you like to play? "))
w, l = sim_games(n)
print("wins:", w,"losses:", l)
The problem is with
if game():
wins = wins + 1
if not game():
losses = losses + 1
Instead, it should be
if game():
wins = wins + 1
else:
losses = losses + 1
In your code, you are simulating two games instead of one (by calling game() twice). This gives four possible outcomes instead of two (win/loss), giving inconsistent overall results.
In this code
for i in range(n):
if game():
wins = wins + 1
if not game():
losses = losses + 1
you call game() twice, so you play two games right there. What you want is a else block:
for i in range(n):
if game():
wins = wins + 1
else:
losses = losses + 1
Btw, you can simplify the logic with in:
def game():
dice = roll()
if dice in (2,3,12):
return False
if dice in (7,11):
return True
# keep rolling
while True:
new_roll = roll()
# re-rolled the initial value => win
if new_roll==dice:
return True
# rolled a 7 => loss
if new_roll == 7:
return False
# neither won or lost, the while loop continues ..
The code is quite literally the description you gave.
Don't do this
for i in range(n):
if game():
wins = wins + 1
if not game():
losses = losses + 1
It doesn't work out well at all.
There are numerous problems with this code. Most importantly, you're calling game() twice per loop. You need to call it once and store the result, and switch based on that.
An OO rewrite:
import random
try:
rng = xrange # Python 2.x
inp = raw_input
except NameError:
rng = range # Python 3.x
inp = input
def makeNSidedDie(n):
_ri = random.randint
return lambda: _ri(1,n)
class Craps(object):
def __init__(self):
super(Craps,self).__init__()
self.die = makeNSidedDie(6)
self.firstRes = (0, 0, self.lose, self.lose, 0, 0, 0, self.win, 0, 0, 0, self.win, self.lose)
self.reset()
def reset(self):
self.wins = 0
self.losses = 0
def win(self):
self.wins += 1
return True
def lose(self):
self.losses += 1
return False
def roll(self):
return self.die() + self.die()
def play(self):
first = self.roll()
res = self.firstRes[first]
if res:
return res()
else:
while True:
second = self.roll()
if second==7:
return self.lose()
elif second==first:
return self.win()
def times(self, n):
wins = sum(self.play() for i in rng(n))
return wins, n-wins
def main():
c = Craps()
while True:
n = int(inp("How many rounds of craps would you like to play? (0 to quit) "))
if n:
print("Won {0}, lost {1}".format(*(c.times(n))))
else:
break
print("Total: {0} wins, {1} losses".format(c.wins, c.losses))
if __name__=="__main__":
main()

Categories