крэпс в питоне

Я пытаюсь смоделировать n игр в кости. Код кажется мне понятным, но я никогда не получаю правильного результата. Например, если я введу n = 5, то есть пять игр, сумма выигрышей и проигрышей будет больше 5.

Вот как это должно работать: если начальный бросок равен 2, 3 или 12, игрок проигрывает. Если выпадает 7 или 11, игрок выигрывает. Любой другой начальный бросок заставляет игрока бросить снова. Он продолжает кидать до тех пор, пока не выкинет 7 или значение начального броска. Если он повторно бросает начальное значение до того, как выпадет 7, это выигрыш. Выпадение 7 первым является проигрышем.

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)

person Community    schedule 15.03.2011    source источник
comment
какие результаты вы получаете? сколько игр вы пытаетесь запустить и сколько побед и поражений вы получаете за это количество игр?   -  person Ramy    schedule 15.03.2011
comment
Разве randrange(1,7) не имитирует семигранный кубик?   -  person John    schedule 15.03.2011
comment
@John: Нет, диапазоны в Python полуоткрыты, то есть 7 не включены, и в итоге вы получаете start - stop = 6 вариантов от start до stop - 1.   -  person    schedule 15.03.2011
comment
random.randint(1, 6) может быть более понятным.   -  person nmichaels    schedule 15.03.2011
comment
@delnan: Спасибо за это объяснение.   -  person John    schedule 15.03.2011


Ответы (5)


Проблема с

        if game():
            wins = wins + 1
        if not game():
            losses = losses + 1

Вместо этого должно быть

        if game():
            wins = wins + 1
        else:
            losses = losses + 1

В вашем коде вы моделируете две игры вместо одной (дважды вызывая game()). Это дает четыре возможных исхода вместо двух (выигрыш/проигрыш), что дает противоречивые общие результаты.

person NPE    schedule 15.03.2011

В этом коде

for i in range(n):
    if game():
        wins = wins + 1
    if not game():
        losses = losses + 1

вы вызываете game() дважды, так что тут же играете в две игры. Вам нужен блок else:

for i in range(n):
    if game():
        wins = wins + 1
    else:
        losses = losses + 1

Кстати, вы можете упростить логику с помощью 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 ..

Код буквально соответствует описанию, которое вы дали.

person Jochen Ritzel    schedule 15.03.2011

Не делай этого

    for i in range(n):
        if game():
            wins = wins + 1
        if not game():
            losses = losses + 1

Это вообще плохо работает.

person S.Lott    schedule 15.03.2011

С этим кодом связано множество проблем. Самое главное, вы вызываете game() дважды за цикл. Вам нужно вызвать его один раз, сохранить результат и переключиться на его основе.

person Tyler Eaves    schedule 15.03.2011
comment
Не могли бы вы быть немного более конкретным, каковы многочисленные проблемы? Я исправил проблему с двойным вызовом функции game(), и теперь она работает нормально. - person ; 15.03.2011
comment
К любому вызову eval следует относиться с крайним подозрением. Если вам нужен int, вызовите int(), а не eval. Eval может выполнять произвольный код. Есть также инициализированные переменные, которые не используются. - person Tyler Eaves; 15.03.2011

Переписать ОО:

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()
person Hugh Bothwell    schedule 15.03.2011