Python :: Aufgabe #300

2 Lösungen Lösungen öffentlich

Kniffel (Yahtzee, Pasch)

Fortgeschrittener - Python von JKooP - 06.11.2020 um 15:24 Uhr
Schreibe eine Klasse/Modul mit der/dem es möglich ist das Spiel Kniffel in abgespeckter Form abzubilden.
Zur Vereinfachung soll statt 3 nur 1 Mal gewürfelt werden.
Als Ergebnis sollen alle möglichen Gewinnstufen eines Wurfs sowohl des oberen als auch des unteren Blocks mit der erreichten Punktzahl ausgegeben werden.

Beispielwurf: 2-2-2-4-4

Oberer Block:
Zweier: 2+2+2 = 6 (nur Summe der 2er zählen)
Vierer: 4+4 = 8 (nur Summe der 4er zählen)

Unterer Block:
Dreierpasch: 2+2+2 und 4+6 = 16 (Summe aller Augen)
Full House: Dreierpasch + Zweierpasch -> Sonderwertung = 25
Chance: 2+2+2+4+6 = 16 (Summe aller Augen)

Als Erweiterung kann auch das dreimalige Würfeln implementiert werden.
Da die Interaktion mit der Konsole nicht allzu bedienerfreundlich ist, sollte
man vielleicht auf eine grafischen Benutzeroberfläche ausweichen.

Viel Spaß

Lösungen:

vote_ok
von Klaus (1960 Punkte) - 02.12.2020 um 23:26 Uhr
Quellcode ausblenden Python-Code
from random import randint

class Yahtzee:
    def __init__(self):
        self.roll=[]
        self.roll_result={}
        self.block = {}

    def start(self, iteration):
        for index in range(iteration):
            self.roll_dice()
            print(f'\nWurf: {self.roll}')
            self.evaluate_roll()
            self.show_result()

    def roll_dice(self):
        self.roll=[]
        self.roll_result={1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}

        for index in range(5):
            self.roll.append(randint(1, 6))
        for element in self.roll:
            self.roll_result[element] += 1

    def evaluate_roll(self):
        self.block = {
            'Einser': 0,
            'Zweier': 0,
            'Dreier': 0,
            'Vierer': 0,
            'Fünfer': 0,
            'Sechser': 0,
            'Dreierpasch': 0,
            'Viererpasch': 0,
            'Full House': 0,
            'Kleine Straße': 0,
            'Große Straße': 0,
            'Yahtzee': 0,
            'Chance': 0
        }

        if self.__check_dice_rolled():
            self.block['Einser'] = self.roll_result[1] * 1
            self.block['Zweier'] = self.roll_result[2] * 2
            self.block['Dreier'] = self.roll_result[3] * 3
            self.block['Vierer'] = self.roll_result[4] * 4
            self.block['Fünfer'] = self.roll_result[5] * 5
            self.block['Sechser'] = self.roll_result[6] * 6
            if max(self.roll_result.values()) >= 3:
                self.block['Dreierpasch'] = sum(self.roll)
            if max(self.roll_result.values()) >= 4:
                self.block['Viererpasch'] = sum(self.roll)
            if 3 in self.roll_result.values() and 2 in self.roll_result.values():
                self.block['Full House'] = 25
            check_list = sorted(set(self.roll))
            if check_list == [1, 2, 3, 4] or check_list == [2, 3, 4, 5] or check_list == [3, 4, 5, 6]:
                self.block['Kleine Straße'] = 30
            if sorted(self.roll) in [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6]]:
                self.block['Große Straße'] = 40
                self.block['Kleine Straße'] = 30
            if max(self.roll_result.values()) == 5:
                self.block['Yahtzee'] = 50
            self.block['Chance'] = sum(self.roll)
        else:
            print('Sie müssen die Würfel erst werfen, bevor Sie das Ergebnis auswerten können.') 

    def show_result(self):
        if self.__check_result_evaluated():
            for element in self.block:
                if self.block[element] != 0:
                    print(f'{element:15.15}{str(self.block[element]):>2.2} Pkt.')
        else:
            print('Sie müssen erst würfeln bzw. den Wurf auswerten, bevor Sie die Ergebnisse angezeigt bekommen.')

    def __check_dice_rolled(self):
        if not self.roll:
            return False
        else:
            return True

    def __check_result_evaluated(self):
        if not self.block:
            return False
        else:
            return True

if __name__ == "__main__":
    y = Yahtzee()
    y.start(5)
vote_ok
von felixTheC (1200 Punkte) - 07.02.2021 um 19:53 Uhr
Simple Game loop

Quellcode ausblenden Python-Code
import sys

from kniffel_game.kniffel import Kniffel
from kniffel_game.kniffel import NoTurnsLeft


def display_options():
    print('''
    Press [r] for rolling the dices
    Press [1-6] to move a dice into the bucket
        (example: 1, 3) to move dice 1 and 3 into your bucket
    Press [q] to quit
    ''')
    selected_option = input('>>: ').strip().lower()
    if selected_option == 'q':
        print('Good bye.\nSee you next time.')
        sys.exit(0)
    if ',' in selected_option:
        return [int(obj.strip()) for obj in selected_option.split(',')]
    return selected_option


def game_loop():
    print('Welcome to Kniffel')
    while True:
        kniffel = Kniffel()
        while True:
            option = display_options()
            if option == 'n':
                continue
            if option == 'r':
                try:
                    kniffel.roll_dices()
                except NoTurnsLeft:
                    print('Sorry no more turns left')
                    break
                kniffel.display_dices()
                kniffel.display_num_outcomes()
                kniffel.display_down_outcomes()
                print('-' * 30)
                print(f'The best upper block option is {kniffel.best_num_outcome()}')
                print('-' * 30)
                print(f'The best down block option is {kniffel.best_down()}')
                print('-' * 30)
            if isinstance(option, list):
                kniffel.save_dices(tuple(option))
            if isinstance(option, str) and option.isnumeric():
                kniffel.save_dices((int(option), ))
        print('Good Bye.')
        break


if __name__ == '__main__':
    game_loop()




The Kniffel class
Quellcode ausblenden Python-Code
from collections import Counter
import random
from typing import List
from typing import Tuple


class NoTurnsLeft(BaseException):
    pass


class Dice:

    def __init__(self):
        self.eyes = 1

    def __call__(self, *args, **kwargs):
        self.eyes = random.randint(1, 6)
        return self

    def __eq__(self, other):
        if isinstance(other, Dice):
            return self.eyes == other.eyes
        else:
            return self.eyes == other

    def __hash__(self):
        return self.eyes

    def __repr__(self):
        return str(self.eyes)


class Kniffel:

    def __init__(self):
        self.dices: List[Dice] = [Dice() for _ in range(5)]
        self.dice_bucket: List[Dice] = []
        self.turns = 0
        self.roll_dices()
        self.funcs = vars(Kniffel)

    def roll_dices(self) -> None:
        if self.turns > 3:
            raise NoTurnsLeft('No turns left')

        [dice() for dice in self.dices]
        self.turns += 1

    def save_dices(self, dices: Tuple[int, ...]) -> None:
        tmp = {i: dice for i, dice in enumerate(self.dices, 1)}
        for dice in dices:
            if 1 <= dice <= 6:
                self.dice_bucket.append(tmp.pop(dice))
        self.dices = list(tmp.values())

    def _total_eyes(self) -> int:
        all_dices = self.dices + self.dice_bucket
        return sum(dice.eyes for dice in all_dices)

    def _sum_nums(self, num: int) -> int:
        all_dices = self.dices + self.dice_bucket
        return sum(dice.eyes for dice in all_dices if dice.eyes == num)

    def num_one(self) -> int:
        return self._sum_nums(1)

    def num_two(self) -> int:
        return self._sum_nums(2)

    def num_three(self) -> int:
        return self._sum_nums(3)

    def num_four(self) -> int:
        return self._sum_nums(4)

    def num_five(self) -> int:
        return self._sum_nums(5)

    def num_six(self) -> int:
        return self._sum_nums(6)

    def down_three_of_kind(self) -> int:
        """
        3 identical dice
        """
        counter = Counter(self.dices + self.dice_bucket)
        for key, val in counter.items():
            if val == 3:
                return self._total_eyes()
        return 0

    def down_four_of_kind(self) -> int:
        """
        4 identical dice
        """
        counter = Counter(self.dices + self.dice_bucket)
        for key, val in counter.items():
            if val == 4:
                return self._total_eyes()
        return 0

    def down_full_house(self) -> int:
        """
        3 identical and 2 identical dice
        """
        counter = Counter(self.dices + self.dice_bucket)
        is_full_house = len(counter) == 2 and (2 in counter.values() and 3 in counter.values())
        if is_full_house:
            return 25
        else:
            return 0

    def down_tiny_street(self) -> int:
        """
        [1-2-3-4], [2-3-4-5], or [3-4-5-6]
        """
        dice_set = set(self.dices + self.dice_bucket)
        possible_sets = [
            {1, 2, 3, 4},
            {2, 3, 4, 5},
            {3, 4, 5, 6},
        ]
        is_tiny_street = any(len(dice_set - possible_set) == 0 for possible_set in possible_sets)
        if is_tiny_street and len(dice_set) == 4:
            return 30
        else:
            return 0

    def down_big_street(self) -> int:
        """
        [1-2-3-4-5] or [2-3-4-5-6]
        """
        dice_set = set(self.dices + self.dice_bucket)
        possible_sets = [
            {1, 2, 3, 4, 5},
            {2, 3, 4, 5, 6},
        ]
        is_big_street = any(len(dice_set - possible_set) == 0 for possible_set in possible_sets)
        if is_big_street and len(dice_set) == 5:
            return 40
        else:
            return 0

    def down_kniffel(self) -> int:
        """
        return true if 5 of the same dice
        """
        is_kniffel = len(set(self.dices + self.dice_bucket)) == 1
        if is_kniffel:
            return 50
        else:
            return 0

    def down_chance(self) -> int:
        return self._total_eyes()

    def __display_all_outcomes(self, prefix: str) -> None:
        results = {key: val(self) for key, val in self.funcs.items() if key.startswith(prefix)}
        for key, val in results.items():
            if val > 0:
                print(f'{key.replace(prefix, "")}: {val}')

    def __best_result(self, prefix: str) -> Tuple[str, int]:
        highest_val = 0
        name = ''
        results = {key: val(self) for key, val in self.funcs.items() if key.startswith(prefix)}
        for key, val in results.items():
            if val > highest_val:
                highest_val = val
                name = key.replace(prefix, '')
        return name, highest_val

    def best_num_outcome(self) -> Tuple[str, int]:
        return self.__best_result('num_')

    def best_down(self) -> Tuple[str, int]:
        return self.__best_result('down_')

    def display_num_outcomes(self):
        self.__display_all_outcomes('num_')

    def display_down_outcomes(self):
        self.__display_all_outcomes('down_')

    def display_dices(self):
        "-".join([str(dice) for dice in self.dices])
        print(f'Current dices: {"-".join([str(dice) for dice in self.dices])}')
        print(f'Dices in bucket: {"-".join([str(dice) for dice in self.dice_bucket])}')
1988238

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.