Kniffel Python?
Hat irgendwer eine Idee wie man "Kniffel Gewinnkarte" mit Python nachmachen kann für 3 Spieler denn ich habe keine Idee wie ich das machen soll?
Gibt es generell Ideen wie man ein Projekt machen kann wenn man nicht weiß wie man das umsetzen soll?
2 Antworten
Man könnte das Spiel durch Python steuern lassen:
Zuerst werden bspw. die Namen eingetragen. (Spieler 1,2 und 3). Dann entscheidet Python wer anfängt. Die geworfenen Würfel werden direkt nacheinander eingegeben z.B. 43265. Die Zahlen werden nach Größe sortiert: 23456. Python gibt dann eine Übersicht aus und die Möglichkeiten den Wurf einzuordnen. Der Spieler entscheidet dann worauf der Wurf geschrieben wird.
Zu verschiedenen Zeitpunkten (oder ständig sichtbar) wird der Stand als Tabelle ausgegeben. In den Zeilen die Würfe, Summen und Boni (wie auf einer Gewinnkarte) und in den spalten die Spieler.
Nach dem Spiel gibt es eine zweite Tabelle. Reduziert auf die Gesamtpunkte, Spiele und Spieler.
Python gibt immer Informationen leicht lesbar aus und gibt an, welcher Spieler als nächstes dran ist.
Ich finde, das ist ein cooles großes und unkompliziertes Projekt. Hätte ich auch Lust drauf :)
Ich würde eine Funktion verwenden um die Zahlen einzulesen. Etwa so:
def input_wurf():
while True: #solange wiederholen bis abgebrochen wird durch return/break
wurf = input("Gib deinen Wurf ein: ")
wurf = list(wurf) #wandelt in eine liste um
wurf.sort() #sortiert die liste von klein nach groß
wurf = list(map(int, wurf)) #wandelt alle ziffern in integer um
print("So sieht die Liste aus:",wurf)
laenge = len(wurf) #zählt die ziffern
kleinste = wurf[0] #die erste ziffer
groesste = wurf[-1] #die letzte ziffer
if laenge==5 and kleinste>=1 and groesste<=6: #wenn alles passt
return wurf
else:
print("Da stimmt was nicht! Bitte nochmal:")
Um zu erkennen wo man seinen Wurf einordnen kann, gibt es verschiedene Möglichkeiten.
Hier ist mein Beispiel:
def print_möglichkeiten(wurf):
count_keys = {
"dreier Pasch": lambda x: max(x)>=3,
"vierer Pasch": lambda x: max(x)>=4,
"Full House": lambda x: x.count(2)!=0 and x.count(3)!=0,
"kleine Straße": lambda x: x.count(1)>=4,
"große Straße": lambda x: x.count(1)==5,
"Kniffel": lambda x: 5 in x
}
augen_vorkommnisse = [wurf.count(i+1) for i in range(6)] #zählt jede augenzahl
print("\nHier sind die Möglichkeiten:")
for ck in count_keys:
if count_keys[ck](augen_vorkommnisse):
print(ck)
print_möglichkeiten(input_wurf())
Diese Funktion gibt die jenigen Kategorien aus, in denen der Wurf Punkte ergibt (unabhängig vom oberen Block).
Da ich mich jetzt etwas mit dem Spiel beschäftigt habe, würde ich alle "Kategorien" (z.b. 3er, 4er, 3er-Pasch, Kniffel,...) zur Auswahl anbieten und die passenden (von print_möglichkeiten) hervorheben.
Die Funktion mit den Lambdas ist echt gut. Hätte nicht gedacht, dass man das so weit kürzen kann.
Die Lambdas für die kleine und große Straße musst du allerdings noch etwas nachbessern. Z.B. [1,2,3,4,4] wird nicht als kleine Straße erkannt und bei [1,2,3,5,6] wird kleine und große Straße angeboten, obwohl es keins von beiden ist.
Oh danke fürs Testen!
count_keys = {
"dreier Pasch": lambda x: max(x)>=3,
"vierer Pasch": lambda x: max(x)>=4,
"Full House": lambda x: x.count(2)!=0 and x.count(3)!=0,
"kleine Straße": lambda x: "1111" in "".join(map(str,x)),
"große Straße": lambda x: "11111" in "".join(map(str,x)),
"Kniffel": lambda x: 5 in x
}
ein String daraus zum machen ist sicherlich nicht die beste Lösung.
Ich hab gerade mal getestet den wurf aus input_wurf als String zu lassen, das wird aber schnell unverständlich.
Jetzt hast du aber nur eins von beiden Problemen behoben. Die [1,2,3,4,4] wird trotzdem nicht als kleine Straße erkannt, weil die 4 halt doppelt drin ist. 😛
:D nur her mit den Fehlern
def print_möglichkeiten(wurf):
count_keys = {
"dreier Pasch": lambda x: max(x)>=3,
"vierer Pasch": lambda x: max(x)>=4,
"Full House": lambda x: x.count(2)!=0 and x.count(3)!=0,
"kleine Straße": lambda x: "1111" in "".join(["1" if i!=0 else "0" for i in x]),
"große Straße": lambda x: "11111" in "".join(map(str,x)),
"Kniffel": lambda x: 5 in x
}
Interessant war auch
"kleine Straße": lambda x: "1111" in "".join(map(lambda t: str(int(bool(t))), x))
ist aber wesentlich langsamer.
Ich finde es meistens deutlich schwieriger, die Grafik zu bauen, als die Logik. Grade in Python sind die nötigen Abfragen sehr einfach. Hab dir mal ein kleines Programm gebastelt:
def print_all_options(dice: list[int]) -> None:
# Zeigt die Punkte für alle Spieloptionen an
if len(dice) != 5:
raise ValueError("In der Liste 'dice' müssen genau fünf Werte enthalten sein.")
if not all([(die in range(1,7)) for die in dice]):
raise ValueError("Alle Würfel müssen einen Wert zwischen 1 und 6 haben.")
# Obere Hälfte ("Nur Einser zählen" bis "nur Sechser zählen")
for pips in range(1,7):
print(f"Nur {pips}er zählen: {pips_sum(pips, dice)} Punkte")
# Dreierpasch
print(f"Dreierpasch: {three_of_a_kind(dice)} Punkte")
# Viererpasch
print(f"Viererpasch: {four_of_a_kind(dice)} Punkte")
# Full House
print(f"Full House: {full_house(dice)} Punkte")
# Kleine Straße
print(f"Kleine Straße: {small_straight(dice)} Punkte")
# Große Straße
print(f"Große Straße: {large_straight(dice)} Punkte")
# Kniffel
print(f"Kniffel: {kniffel(dice)} Punkte")
# Chance
print(f"Chance: {chance(dice)} Punkte")
def pips_sum(pips: int, dice: list[int]) -> int:
# Gleiche Würfelaugen summieren
return sum([die for die in dice if die == pips])
def three_of_a_kind(dice: list[int]) -> int:
# Falls eine Gruppe mit mindestens drei gleichen Zahlen vorhanden ist,
# alle Würfel zusammenzählen. Ansonsten 0 Punkte
if any([group_size for group_size in group_sizes(dice) if group_size >= 3]):
return sum(dice)
return 0
def four_of_a_kind(dice: list[int]) -> int:
# Falls eine Gruppe mit mindestens vier gleichen Zahlen vorhanden ist,
# alle Würfel zusammenzählen. Ansonsten 0 Punkte
if any([group_size for group_size in group_sizes(dice) if group_size >= 4]):
return sum(dice)
return 0
def full_house(dice: list[int]) -> int:
# Wenn eine Gruppe mit zwei und eine Gruppe mit drei gleichen Würfeln
# vorhanden ist, 25 Punkte zurückgeben. Ansonsten 0 Punkte.
if sorted(group_sizes(dice)) == [2, 3]:
return 25
return 0
def small_straight(dice: list[int]) -> int:
# Wenn eine kleine Straße (definiert durch die Optionen unten)
# in den Würfeln vorhanden ist, 30 Punkte zurückgeben. Ansonsten 0 Punkte.
if all([pips in dice for pips in [1, 2, 3, 4]]) \
or all([pips in dice for pips in [2, 3, 4, 5]]) \
or all([pips in dice for pips in [3, 4, 5, 6]]):
return 30
return 0
def large_straight(dice: list[int]) -> int:
# Wenn eine große Straße (definiert durch die Optionen unten)
# in den Würfeln vorhanden ist, 40 Punkte zurückgeben. Ansonsten 0 Punkte.
if all([pips in dice for pips in [1, 2, 3, 4, 5]]) \
or all([pips in dice for pips in [2, 3, 4, 5, 6]]):
return 40
return 0
def kniffel(dice: list[int]) -> int:
# Wenn in den Würfeln nur eine Gruppe mit 5 gleichen Würfeln vorkommt,
# 50 Punkte zurückgeben. Ansonsten 0 Punkte
if group_sizes(dice) == [5]:
return 50
return 0
def chance(dice: list[int]) -> int:
# Einfach die Anzahl der Würfelaugen zurückgeben
return sum(dice)
def group_sizes(dice: list[int]) -> list[int]:
# Listet die Anzahl der gleichen Würfelzahlen auf
return [len([die for die in dice if die == pips]) for pips in set(dice)]
if __name__ == "__main__":
# Diverse Würfelkombinationen testen
for dice in [[4, 2, 1, 3, 5], \
[2, 1, 1, 2, 3], \
[6, 5, 6, 5, 6], \
[4, 4, 4, 4, 4], \
[5, 3, 3, 2, 4], \
[2, 3, 4, 2, 2], \
[6, 6, 1, 6, 6]]:
print(f"Würfel: {dice}")
print_all_options(dice)
print()
dice ist das englische Wort für Würfel. Da stehen einfach die Zahlen der Würfel drin. Ist allerdings eine list[int]. Also die Zahlen der Würfel gibst du nicht mit "12345", sondern mit [1, 2, 3, 4, 5] ein.
Übrigens: "pips" sind die Würfelaugen und "die" ist die Einzahl von Würfel.
Ja ist mir schon bewusst aber warum schreibt man das in die Attribute und warum ist dann da ein -> ?
Damit du der Funktion "print_all_options" die geworfenen Würfel übergeben kannst. Wenn du z.B. print_all_options([1, 2, 3, 4, 5]) schreibst, listet die Funktion alle Optionen der Kniffel Gewinnkarte auf und du siehst, dass das Beste in dem Fall eine große Straße für 40 Punkte ist.
Die Sachen, wie "(dice: list[int]) -> None" sind sogenannte type hints. Damit sagst du dem Programm nur, welche Variablentypen die Funktion erwartet und zurückgibt. Die könnte man auch weglassen und nur "def print_all_options(dice):" schreiben.
Danke :D
Bei mir ist eher das Problem dass ich nicht weiß wie Python das überprüfen soll. Wenn ein Spieler zb 12348 als Große Straße einordnet ist das ja nicht richtig. Noch schwieriger wird das überprüfen bei einem Full House (2,2,3,3,3) Das könnten ja alle möglichen Zahlen sein. Meine Idee wäre dass ich auf alle Zahlen eine Forloop laufen lasse und schaue wie oft welche Zahl vorkommt.