2
\$\begingroup\$

I'm trying to implement Reiner Knizia’s Decathlon, a set of 10 solo dice games played with 8 dices named after Decathlon events in Olympics.

The first event is called "100 Metres". The player divides 8 dices into two sets of 4, then pick a set and throw. He may keep the dice (freeze) or rethrow. After he is satisfied with the result, he does the same with the other set. He has a total of 5 rethrows. The score is the total of the dice after he freezes all dice.

My approach: There are 10 events, so it is going to be a lot of repetitive code. I made a Event class, and each Event will have a self.state dict object keeping tracking of dice rolls and number of rethrows. Each event will also have a self.print_game_state object.

Here is the code. Any idea to write this code smarter?

common.py

import random


class DiceRoller:

    def __new__(cls, num_dice=1):
        return [random.randint(1, 6) for _ in range(num_dice)]


class Event:
    def __init__(self):
        if not hasattr(self, 'state'):
            self.state = dict()

    def print_game_state(self):
        for key, value in self.state.items():
            print(f'{key}: {value}')
        print(f'Score: {self.score()}')
        if self.game_finished():
            print('Game Finished')

e100metres.py

from common import DiceRoller, Event


class E100Metres(Event):
    '''100 metres event.'''

    def __init__(self):
        super().__init__()
        self.state.update({
            'frozen_sets': 0,
            'remaining_rerolls': 5,
            'frozen_dices': [],
            'current_rolls': DiceRoller(4)
        })
        self.print_game_state()

    def game_finished(self):
        return self.state['frozen_sets'] >= 2

    def no_more_rerolls(self):
        return self.state['remaining_rerolls'] <= 0

    def reroll(self):
        if self.game_finished():
            raise Exception('Game already finished')
        if self.no_more_rerolls():
            raise Exception('No more rerolls')
        self.state['remaining_rerolls'] -= 1
        self.state['current_rolls'] = DiceRoller(4)
        self.print_game_state()

    def freeze(self):
        if self.game_finished():
            raise Exception('Game already finished')
        self.state['frozen_dices'] += self.state['current_rolls']
        self.state['frozen_sets'] += 1
        if self.game_finished():
            self.state['current_rolls'] = list()
        else:
            self.state['current_rolls'] = DiceRoller(4)
        self.print_game_state()

    def score(self):
        return sum(self.state['frozen_dices'])
\$\endgroup\$
  • \$\begingroup\$ Please verify your code. The braces don't match. \$\endgroup\$ – 200_success Oct 13 '18 at 12:02
  • \$\begingroup\$ Is there some code missing? I can't see how you use E100Metres, and for example nothing ever changes frozen_sets from its initial value of 0. \$\endgroup\$ – Peter Taylor Oct 13 '18 at 16:59
  • \$\begingroup\$ Code fixed. To play I'll initiate an E100Metres object, then call the functions freeze or reroll directly. \$\endgroup\$ – user2341726 Oct 13 '18 at 20:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.