ubuntuusers.de

Python 2 oder 3?

Status: Gelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

JörnS schrieb:

An 2D ist an und für sich nichts Schlechtes - aber ich hab das Gefühl, dass man damit kaum jemanden noch begeistern kann.

Ich würde es mal gelinde so ausdrücken: Die gefühlt meisten OS-Spiele basieren auf 2D-Tile-Engines 😉

Als Kompromiss find ich Raycasting auch ganz nett. Siehe zB http://de.wikibooks.org/wiki/Spielewelten_mit_Raycasting

Das ist aber ein schwacher Kompromiss, wenn man keine Ego-Perspektive benögigt. Und das dürfte wohl auch bei der Mehrheit der Spiele der Fall sein 😉

Du kannst ja gerne der Ansicht sein, dass es sich nicht lohnt Spiele auf eine 2D-Engine fußen zu lassen - viele (gute) OS-Spiele leben vor, dass sich durchaus viele auch heute noch dafür begeistern lassen.

Ich habe ja nichts gegen 3D. Im Grunde genommen kann ich jede 2D-Tile-Engine in eine 3D-Engine "mappen" - aber das kostet neben CPU-Ressourcen auch tiefere Kenntnisse in Sachen 3D, aufwendigeres Wissen zur Erstellung / Beschaffung von Content uvm. Genau daher ist es für einen Hobbyisten durchaus sinnvoll, sich mit 2D zu befassen.

Quasi alle Brett- und Kartenspiele lassen sich damit schick umsetzen. Dazu kommen dann noch lauter Dinge wie Rogue-likes, Strategiespiele, Jump'n Runs uvm.

Mobai

(Themenstarter)
Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

Ich melde mich nun auch wieder - war die letzten Wochen im Urlaub ohne Internet, deshalb so spät.

Python bereitet mir große Freude: Bereits mit Bordmitteln habe ich ein Konsolenspiel entwickelt - "Wer wird Milliardär?"

Ich mag auch 2D Spiele, z.B. Jump'n'Runs, aber pseudo-3D-Spiele haben auch ihren Reiz... Aber sind bestimmt komplizierter, oder?

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Mobai schrieb:

Python bereitet mir große Freude: Bereits mit Bordmitteln habe ich ein Konsolenspiel entwickelt - "Wer wird Milliardär?"

Cool ☺ Gibt's das irgend wo zum Download / Review?

Ich mag auch 2D Spiele, z.B. Jump'n'Runs, aber pseudo-3D-Spiele haben auch ihren Reiz... Aber sind bestimmt komplizierter, oder?

2D kannst Du angehen, wenn die Grundlagen von Python sitzen. Mit pygame ist das wirklich nicht so schwer, einfache Dinge umzusetzen.

JörnS Team-Icon

Anmeldungsdatum:
25. November 2010

Beiträge: 2107

Mobai schrieb:

Ich mag auch 2D Spiele, z.B. Jump'n'Runs, aber pseudo-3D-Spiele haben auch ihren Reiz... Aber sind bestimmt komplizierter, oder?

Das mit Raycasting nach der Anleitung ist recht easy. Gestern hab ich spaßeshalber mal floorcasting ausprobiert (damit der Boden auch texturiert dargestellt werden kann). Aber ohne Optimierung recht lahm und einen kleinen Fehler hab ich auch noch drin, der sich mir spanton nicht erschliesst. Wenn Interesse besteht schick ich dir gerne mal den Code - dann kannst du dir ansehen ob das deine Kragenweite ist.

Mobai

(Themenstarter)
Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

Sorry dass ich soo spät antworte, aber irgendwie habe ich keine Benachrichtigung bekommen... Da war doch mal das System kaputt, oder?

Lysander schrieb:

Mobai schrieb:

Python bereitet mir große Freude: Bereits mit Bordmitteln habe ich ein Konsolenspiel entwickelt - "Wer wird Milliardär?"

Cool ☺ Gibt's das irgend wo zum Download / Review?

Ja, guckst du hier:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python3

import random, sys

fragen = ["""Wie heißt der von Richard Stollman "erfundene" Kernel?\nA) Heart\nB) Hurt\nC) Hurd\nD) Heard""", "Der Vater von Linus Torvalds heisst mit Vornamen...\nA) Nils\nB) Jens\nC) Stefan\nD) Robert", """"Gymnos" ist griechisch und bedeutet...\nA) fleißig\nB) nackt\nC) stark\nD) schlau""", "Welches der Folgenden Wesen gibt es wirklich?\nA) Steinlaus\nB) Felsenbeißer\nC) Steinbeißer\nD) Felsenfresser", "Welches ist keine Kopfbedeckung?\nA) Melone\nB) Kreissäge\nC) Dreispitz\nD) Zuckerhut", 'Wie heißt Angela Merkel mit Vornamen?\nA) Barbara\nB) Angelika\nC) Aranka\nD) Angela', 'Was ist das schwerste Objekt?\nA) der Mond\nB) ein Elefant\nC) ein Bärtierchen\nD) Angela Merkel', 'Wie heißt der Linux-Schöpfer mit Nachnamen?\nA) Ballmer\nB) Valentine\nC) Torvalds\nD) Tanenbaum', 'Bekommt man sein Geld zurück, wenn man in einem Taxi rückwärts fährt?\nA) Ja\nB) Nein', 'Was ist "DDoS"?\nA) eine neue, stabilere Dosenform\nB) eine Angriffsart um Server ausser Kraft zu setzen\nC) eine neue Programmiersprache\nD) eine Schnittstelle zwischen Netzwerk und PC', 'Was ist das schnellste Tier der Welt?\nA) Gepard\nB) Bärtierchen\nC) Wanderfalke\nD) Sebastian Vettel', 'Kernfusion ist...\nA) umweltschädlich, da es radioaktive Abfälle produziert\nB) umweltfreundlich, da es kein CO2 ausstößt\nC) umweltfreundlich, aber uneffizient\nD) umweltfreundlich und hocheffizient', 'Ein anderes Wort für "Nerd" ist...\nA) Geek\nB) Dweeb\nC) Dork\nD) Fork', 'Omjakon ist ein Ort in...\nA) Tansania\nB) Pandora\nC) Paraguay\nD) Russland', 'Der Führer der SS war...\nA) Adolf Hitler\nB) Heinrich Himmler\nC) Joseph Göbbels\nD) Herman Goering']
antworten = ["C", "A", "B", "C", "D", 'D', 'A', 'C', 'B', 'B', 'C', 'D', 'A', 'D', 'B']

def menu():
	print("""Wilkommen bei "Wer wird Milliardär?".""")
	wahl = input("Hauptmenü:\n1) Spielen\n")
	if wahl == "1":
		spielen()

def spielen():
	geloest = []
	while len(geloest) != 15:
		zufall = random.randint(0, 15)
		if zufall not in geloest:
			print(fragen[zufall])
			antwort = input()
			if antwort == antworten[zufall]:
				print("Richtig!")
				geloest.append(zufall)
			else:
				print("Oh, leider falsch.")
				print("Du hast", len(geloest), "Fragen gelöst.")
				sys.exit(0)
	else:
		print("Unglaublich. Du hast alle Fragen gelöst. Ich bin stolz auf Dich. Nicht. Huhahaha!")

if __name__ == "__main__":
	menu()

Das ganze ist Python3. Aber irgendwie kriege ich den Fehler (IndexError: list index out of range) nicht weg, keine Ahnung wieso...

Zu den Spielen:

Ein Bekannter hat mir das Buch "Coding for fun" vermacht. Dort werden PyGame und OpenGL besprochen. Aber bis ich soweit bin, dauert es noch ein bisschen 😉

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Der Typ heißt allerdings "Stallman" und nicht "Stollman". ^^

Ansonsten ist der Code für den Anfang ganz okay, finde ich. Du wirst, sofern du am Ball bleibst, in 6 Monaten sicherlich ein paar Dinge anders machen, aber das ist normal. Es gibt Anfängercode, der wirklich grausig ist. Das kann man von deinem IMHO nicht sagen.

"Wie heißt Angela Merkel mit Vornamen?" 😀

Mobai

(Themenstarter)
Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

Ach, verdammt 😉

Nun gut, diese überlange Liste am Anfang ist vielleicht nicht so toll, aber mir fiel keine andere Lösung ein, die den Code nicht noch wesentlich verlängert hätte...

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Der von Dir gepostete Code läuft ja nicht einmal für die erste Frage! Wie kannst Du denn so viel Code schreiben, wenn es da elementare Probleme gibt? *wunder*

Generell solltest Du Dir mal PEP8 anschauen; Einrückung sollten 4 Spaces sein und keine Tabs!

Der Fehler lässt sich übrigens ganz einfach lösen; die Meldung ist da ja sehr explizit!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
In [9]: values = list(range(4))

In [10]: values
Out[10]: [0, 1, 2, 3]

In [12]: values[4]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
/home/nelson/<ipython-input-12-d0ba089e22fd> in <module>()
----> 1 values[4]

IndexError: list index out of range

In [13]: values[3]
Out[13]: 3

Mir gefällt an Deinem Ansatz die Datenstruktur nicht! Du entkoppelst die Fragen und die Antworten voneinander - wieso? Zudem sind die Antwortmöglichkeiten in fester Reihenfolge an die Frage gebunden. Das kann man sicherlich eleganter lösen; damit wäre es auch möglich, die Reihenfolge der Antworten zu variieren.

Das Menü ist in seiner jetzigen Form obsolet 😉

Deine Zufallsfunktion ist auch sehr ineffizient! Du wählst per Zufall eine Frage und prüfst danach, ob die evtl. schon mal vorkam. Falls ja, wählst Du per Zufall wieder eine beliebige Frage. Dies könnte im schlimmsten Fall immer dieselbe sein, was dann zu einem Dead-lock führte. Spätestens sobald weniger Fragen offen sind als bereits gestellte, wird es damit also immer schlechter. Besser ist es, sich einen Weg zu überlegen, bereits gestellte Fragen von der Zufallssuche nach der nächsten Frage auszuschließen! Ich würde das wohl über random.shuffle lösen und die neu entstandene zufällige Sequenz der Reihe nach durchlaufen. Alternativ könnte man auch per random.choice eine Frage wählen und diese dann per .pop aus der Liste entfernen; komfortabler ist aber imho die erste Variante.

Da man als Anfänger noch keine Klassen beherrscht, würde ich für die Datenstruktur einer Frage wohl ein Dictionary wählen. Ich stelle mir vor, dass es in dieser Datenstruktur einen Platz für die Frage und für mindestens vier Antworten geben muss. Evtl. könnte man da noch mehr einbauen; das würde die Wiederspielbarkeit sicher erhöhen. Für die Frage reicht also ein String aus; für die Antworten eine Liste aus Strings. Ich definiere, dass die erste Antwort immer die richtige ist. Keine Angst! Nur in der Datenstruktur - im Spiel mixen wir die Antworten natürlich beliebig 😉

So könnte der erste Ansatz aussehen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
In [45]: question = {
   ....: "text": "Was ist eine Programmiersprache?",
   ....: "answers": ["Python", "Boa", "Natter", "Viper"]
   ....: }

In [46]: correct = question["answers"][0]

In [47]: correct
Out[47]: 'Python'

In [48]: random.shuffle(question["answers"])

In [49]: question["answers"]
Out[49]: ['Boa', 'Viper', 'Natter', 'Python']

Bevor wir also in einem Durchgang "mixen", merken wir uns für das spätere Prüfen auf die richtige Antwort die korrekte Antwort (correct). Haken dieser Methode ist es, dass die ursprüngliche Datenstruktur verfälscht wird; will ich nach einem Durchgang das Spiel von vorne starten, muss ich die Fragen resetten. Will ich das umgehen, könnte ich mir mittels copy-Modul eine Kopie der Frage anlegen oder sogar nur der Antwortmöglichkeiten, die durch random.shuffle gemixt werden:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
In [11]: question
Out[11]: 
{'answers': ['Python', 'Boa', 'Natter', 'Viper'],
 'text': 'Was ist eine Programmiersprache?'}

In [12]: possibilities = copy.copy(question["answers"])

In [13]: possibilities
Out[13]: ['Python', 'Boa', 'Natter', 'Viper']

In [14]: random.shuffle(possibilities)

In [15]: possibilities
Out[15]: ['Viper', 'Natter', 'Python', 'Boa']

In [16]: question["answers"]
Out[16]: ['Python', 'Boa', 'Natter', 'Viper']

Als zunächst triviale dritte Möglichkeit könnte man sich die korrekte Antwort auch separat in einem zusätzlichen Schlüssel merken; Gefahr hierbei sind natürlich Tippfehler, wie immer bei Redundanz. Man könnte diesen Schlüssel aber auch zuvor "berechnen", dann wäre das - wie mir grad auffällt - in der Tat die simpelste Methode, die ganz ohne "Resetten" o.ä. auskommt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In [23]: question
Out[23]: 
{'answers': ['Python', 'Boa', 'Natter', 'Viper'],
 'text': 'Was ist eine Programmiersprache?'}

In [24]: question["correct"] = question["answers"][0]

In [25]: question
Out[25]: 
{'answers': ['Python', 'Boa', 'Natter', 'Viper'],
 'correct': 'Python',
 'text': 'Was ist eine Programmiersprache?'}

Damit man beim Stellen der Fragen die vorbildlichen Buchstaben verwenden kann, kann man sich einfach ein Mapping bauen (hier sind in possibilities die geshuffelten Antworten!):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In [17]: choices = dict(zip("ABCD", possibilities))

In [18]: choices
Out[18]: {'A': 'Viper', 'B': 'Natter', 'C': 'Python', 'D': 'Boa'}

In [22]: for char in "ABCD":
   ....:     print("{}) {}".format(char, choices[char]))
   ....:     
A) Viper
B) Natter
C) Python
D) Boa

Achtung: Ein Dictionary speichert die Schlüssel nicht deterministisch nach Alphabet oder der Sequenz des Hinzufügens. Daher muss ich bei der sortierten Ausgabe über die Schlüssel "ABCD" gehen. Um möglichst magic numbers zu vermeiden, sollte man zu Beginn des Programms ggf. diese "ABCD"-Sequenz fest definieren, also etwas ABCD = 'ABCD'.

Ich kann nun einfach testen, ob die Antwort des Spielers mit der korrekten Lösung übereinstimmt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In [33]: choices
Out[33]: {'A': 'Viper', 'B': 'Natter', 'C': 'Python', 'D': 'Boa'}

In [34]: user_input = "b".upper()

In [35]: choices[user_input] == question["correct"]
Out[35]: False

In [36]: user_input = "c".upper()

In [37]: choices[user_input] == question["correct"]
Out[37]: True

Diese Fragmente zu einem Spiel zusammenzusetzen überlasse ich mal einem interessierten Leser 😉

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Mobai schrieb:

Nun gut, diese überlange Liste am Anfang ist vielleicht nicht so toll, aber mir fiel keine andere Lösung ein, die den Code nicht noch wesentlich verlängert hätte...

Die Daten würde ich immer in eine externe Datenquell auslagern. Für den Anfang (und vieles spätere natürlich auch 😉 ) würde ich Dir da das json-Modul empfehlen. Damit hast Du quasi eine 1:1-Abbildung von den fundamentalen Python-Datenstrukturen in ein serialisierbares Format.

Anbei mal eine Beispieldatei nach meinem Obigen Muster:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[
    {
        "text": "Was ist eine Programmiersprache?",
        "answers": ["Python", "Boa", "Natter", "Viper"]
    },
    {
        "text": "Was ist das schnellste Tier der Welt?",
        "answers": ["Gepard", "Bärtierchen", "Wanderfalke", "Sebastian Vettel"]
    }
]

Und wie man diese dann in den Speicher bekommt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
In [49]: import json

In [50]: with open("questions.json", "r") as infile:
   ....:     questions = json.load(infile)
   ....:     

In [51]: questions
Out[51]: 
[{'answers': ['Python', 'Boa', 'Natter', 'Viper'],
  'text': 'Was ist eine Programmiersprache?'},
 {'answers': ['Gepard', 'Bärtierchen', 'Wanderfalke', 'Sebastian Vettel'],
  'text': 'Was ist das schnellste Tier der Welt?'}]

In [52]: for question in questions:
   ....:     question["correct"] = question["answers"][0]
   ....:     

In [53]: questions
Out[53]: 
[{'answers': ['Python', 'Boa', 'Natter', 'Viper'],
  'correct': 'Python',
  'text': 'Was ist eine Programmiersprache?'},
 {'answers': ['Gepard', 'Bärtierchen', 'Wanderfalke', 'Sebastian Vettel'],
  'correct': 'Gepard',
  'text': 'Was ist das schnellste Tier der Welt?'}]

Also sehr einfach das ganze! ☺

Edit: Oops, der Wanderfalke wärs wohl 😀 Da hab ich beim Adaptieren Deiner Frage nicht aufgepasst 😉

Mobai

(Themenstarter)
Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

Guten Tag.

Danke für die Kritik. Leider habe ich statt dem ausführlichen nur einen mageren Fehler bekommen aus dem ich nicht schlau wurde.

Traceback (most recent call last):
  File "/home/mobai/Dokumente/Python/quiz/main.py", line 30, in <module>
    menu()
  File "/home/mobai/Dokumente/Python/quiz/main.py", line 10, in menu
    spielen()
  File "/home/mobai/Dokumente/Python/quiz/main.py", line 17, in spielen
    print(fragen[zufall])
IndexError: list index out of range

Ich werde mir deinen Beitrag nochmal ganz in Ruhe anschauhen und hoffentlich schlauer werden 😉

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Na, das ist doch sehr ausführlich 😉

Ich gebe zu mein Beispiel oben (erstes Beispiel) war unglücklich gewählt, weil ich Zahlen als Datenelemente der Beispielliste gewählt habe, wodurch man evtl. als Anfänger mit den Indizes durcheinander kommt und diese verwechselt. Also noch mal ohne Zahlen, sondern mit Buchstaben:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In [57]: text = "ABCD"

In [58]: text[4]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
/home/nelson/src/Python/snippets/forum/<ipython-input-58-36911859e3ea> in <module>()                                                                  
----> 1 text[4]

IndexError: string index out of range

In [59]: text[3]
Out[59]: 'D'

Es gibt einfach den Index 4 nicht. Der höchste Index ist eben die 3, denn an 3. Stelle steht nun einmal das "D". Achtung: Bei den meisten Sprachen hat das erste Element den Index 0! Es gibt also 4 Elemente in der Liste, aber der höchste Index ist eben die 3:

0 -> 1. Stelle
1 -> 2. Stelle
2 -> 3. Stelle
3 -> 4. Stelle

Das kann man sich auch mit enumerate klar machen, einer Funktion, die einen expliziten Index zu einem Iterable erzeugt:

1
2
In [61]: list(enumerate("ABCD"))
Out[61]: [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D')]

Wohingegen:

1
2
In [62]: len(text)
Out[62]: 4

Der höchste Index ist also immer die Länge der Liste - 1.

Jetzt schau Dir noch mal an, welche Zahlen Deine Zufallsfunktion erzeugen kann 😉

Mobai

(Themenstarter)
Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

Aaaaach, Mist! Ich hab mich auf len() verlassen, und len() fängt mit 1 an zu zählen! Gut, jetzt weiß ich wo der Fehler liegt ☺

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Mobai schrieb:

Aaaaach, Mist! Ich hab mich auf len() verlassen, und len() fängt mit 1 an zu zählen! Gut, jetzt weiß ich wo der Fehler liegt ☺

Naja, genau genommen fängt len nicht bei 1 an, sondern es zählt eben die Elemente 😉

Mobai

(Themenstarter)
Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

Ja, gut, egal.

Und wieso ich so viel geschrieben habe, obwohl es elementare Probleme gibt? Nun, ich hatte am Anfang nur 3 Fragen, da hat alles funktioniert. Später wurden dann die anderen hinzugefügt, und da hat sich erst der Fehler eingeschlichen 😉

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Mobai schrieb:

Und wieso ich so viel geschrieben habe, obwohl es elementare Probleme gibt? Nun, ich hatte am Anfang nur 3 Fragen, da hat alles funktioniert. Später wurden dann die anderen hinzugefügt, und da hat sich erst der Fehler eingeschlichen 😉

Das ist ein gutes (Negativ-)Beispiel, dass man keine magic numbers benutzen sollte! Du hast die Obergrenze von randint per Hand gesetzt - dabei besteht zwischen ihr und der Frageliste ja ein mathematischer Zusammenhang. Es wäre also sinnvoll, diesen zu nutzen und nicht einen konstanten Wert da rein zu schreiben 😉