0
votes

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)
5
what results are you getting? how many games are you trying to run and how many wins and losses are you getting for that number of games? - Ramy
Doesn't randrange(1,7) simulate a seven-sided die? - John
@John: No, ranges in Python are half-open, i.e. the 7 isn't included and you end up with start - stop = 6 options from start to stop - 1. - user395760
random.randint(1, 6) might be more clear. - nmichaels
@delnan: Thanks for that explanation. - John

5 Answers

5
votes

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.

3
votes

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.

1
votes

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.

0
votes

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.

0
votes

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()