TicTacToe von Anfänger

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
From The Pits
User
Beiträge: 8
Registriert: Montag 21. Juli 2008, 19:47

So, nach länger Abwesenheit sowohl von diesem Forum als auch von Python mal wieder was von mir.
Ich habe ein einfaches TicTacToe programmiert.
Es funktioniert zwar grundsätzlich,ist aber natürlich nicht ganz perfekt und ich hab noch eine Frage und will natürlich auch eure Kritik am Stil hören.

Frage: Die ewig langen if-Bedingungen wirken sehr unschön auf mich, hab aber keine Idee wie ich das verbessern könnte. Weiß jemand von euch wie das schöner gehen würde?



Code: Alles auswählen

import random

class TicTacToe():
	def __init__(self):
		self.feld = [1, 2, 3, 4, 5, 6, 7, 8, 9]
		self.spielergewonnen = False
		self.computergewonnen = False
		
		print "Das ist TicTacToe.\nDu bist Spieler x, der Computer Spieler o.\nUm zu gewinnen musst du 3 x \nin eine Reihe bekommen. \nUm ein x in ein Feld zu zeichnen, \ngib die entsprechende Nummer an."
		
	
	def Spielfeld(self):
		print "_______"
		print self.feld[0], "|", self.feld[1],"|", self.feld[2]
		print "_______"
		print self.feld[3], "|", self.feld[4],"|", self.feld[5]
		print "_______"
		print self.feld[6], "|", self.feld[7],"|", self.feld[8]
		print "_______"
	def Spieler(self):
		wahl = input("Welches Feld waehlst du?")
		if wahl not in self.feld:
			print "Ungueltige Eingabe"
		else:
			self.feld[wahl-1] = "x"
			
	def Computer(self):
		self.moeglich = False
		while self.moeglich == False:
			self.pcwahl = random.choice(self.feld)
			if self.pcwahl == "x" or self.pcwahl == "o":
				continue
			else:
				self.feld[self.pcwahl-1] = "o"
				self.moeglich = True
	def Ueberpruefung(self):
		if self.feld[0] == "x" and self.feld[1] == "x" and self.feld[2] == "x" or self.feld[3] == "x" and self.feld[4] == "x" and self.feld[5] == "x" or self.feld[6] == "x" and self.feld[7] == "x" and self.feld[8] == "x" or self.feld[0] == "x" and self.feld[3] == "x" and self.feld[6] == "x" or self.feld[1] == "x" and self.feld[4] == "x" and self.feld[7] == "x" or self.feld[2] == "x" and self.feld[5] == "x" and self.feld[8] == "x" or self.feld[0] == "x" and self.feld[3] == "x" and self.feld[6] == "x" or self.feld[1] == "x" and self.feld[4] == "x" and self.feld[7] == "x" or self.feld[2] == "x" and self.feld[5] == "x" and self.feld[8] == "x" or self.feld[2] == "x" and self.feld[4] == "x" and self.feld[6] == "x" or self.feld[0] == "x" and self.feld[4] == "x" and self.feld[8] == "x" :
			self.spielergewonnen = True
			print "Du hast gewonnen!"
		elif self.feld[0] == "o" and self.feld[1] == "o" and self.feld[2] == "o" or self.feld[3] == "o" and self.feld[4] == "o" and self.feld[5] == "o" or self.feld[6] == "o" and self.feld[7] == "o" and self.feld[8] == "o" or self.feld[0] == "o" and self.feld[3] == "o" and self.feld[6] == "o" or self.feld[1] == "o" and self.feld[4] == "o" and self.feld[7] == "o" or self.feld[2] == "o" and self.feld[5] == "o" and self.feld[8] == "o" or self.feld[0] == "o" and self.feld[3] == "o" and self.feld[6] == "o" or self.feld[1] == "o" and self.feld[4] == "o" and self.feld[7] == "o" or self.feld[2] == "o" and self.feld[5] == "o" and self.feld[8] == "o" or self.feld[2] == "o" and self.feld[4] == "o" and self.feld[6] == "o" or self.feld[0] == "o" and self.feld[4] == "o" and self.feld[8] == "o" :
			self.computergewonnen = True
			print "Du hast verloren."
		elif 1 not in self.feld and 2 not in self.feld and 3 not in self.feld and 4 not in self.feld and 5 not in self.feld and 6 not in self.feld and 7 not in self.feld and 8 not in self.feld and 9 not in self.feld: 
			print "Unentschieden."
			self.computergewonnen = True
			self.spielergewonnen = True
	
			
				
			
			
				
		
spiel = TicTacToe()
while spiel.spielergewonnen == False and spiel.computergewonnen == False:
	spiel.Spielfeld()
	spiel.Spieler()
	spiel.Computer()
	spiel.Ueberpruefung()
spiel.Spielfeld()


	
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Ist dir nicht aufgefallen, dass die beiden Gewinnbedingungen, abgesehen vom Spielerzeichen, identisch sind?

Die Abfrage lässt sich übrigens wirklich eleganter machen ;)
acoolon
User
Beiträge: 27
Registriert: Samstag 2. August 2008, 20:16

moin, bin zwar auch nicht weiter fortgeschritten als du( denke ich mal), aber ist mir etwas aufgefallen

Code: Alles auswählen

Maximum Line Length

    Limit all lines to a maximum of 79 characters.
http://www.python.org/dev/peps/pep-0008/

und es gab auch ne elegantere methode für dein print in zeile neun..irgendwohier im forum beschrieben...vor kurzem..finde ich bloss grad nur nicht ...

das nur von mir

mfg lukas

edit: mist zu spät...schuld ist edr blöde laptop :)
From The Pits
User
Beiträge: 8
Registriert: Montag 21. Juli 2008, 19:47

audax hat geschrieben:Ist dir nicht aufgefallen, dass die beiden Gewinnbedingungen, abgesehen vom Spielerzeichen, identisch sind?

Die Abfrage lässt sich übrigens wirklich eleganter machen ;)
Doch natürlich, aber ich weiß trotzdem nicht wie ich es anders machen kann.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Du könntest dafür eine Funktion oder Methode schreiben, der du das Parameter das Zeichen des Spielers übergibst.

Hier eine Version mit dem verbesserten Check und einem besseren Spielfield zeichnen:
http://paste.pocoo.org/show/86635

Aber bevor du dir den Code ansiehst, versuch es nochmal selbst: Lagere den check in eine Methode "check_for_winner(sign)" aus, die als "sign" das Zeichen des Spieler, also "x" oder "o" bekommt und die Überprüfung macht.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Die if-Anweisungen sind der Tat extrem hässlich. Zunächst sollte dir auffallen, dass du zweimal fast die selben Zeilen benutzt hast, einmal für "x" und einmal für "o". Ziehe den gemeinsamen Teil in eine eigene Methode:

Code: Alles auswählen

def hat_gewonnen(self, wer):
    return self.feld[0] == wer and self.feld[1] == wer and ...

def überprüfung(self):
    if self.hat_gewonnen("x"):
        print "Du hast gewonnen!"
    elif self.hat_gewonnen("o"):
        print "Du hast verloren!"
    ...
Das nächste, was auffallen sollte ist, dass du die Felder 0-1-2, 3-4-5, 6-7-8, sowie die vertikalen und die beiden kreuzweisen Kombinationen probierst. Das schreit nach einer Schleife für die 8 möglichen Tripel:

Code: Alles auswählen

def hat_gewonnen(self, wer):
    for (a, b, c) in (0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), ...:
        if self.feld[a] == wer and self.feld[b] == wer and self.feld[c] == wer:
            return True
    return False
Du kannst jetzt ausnutzen, dass man auch Tupel vergleichen kann. Außerdem würde ich das "return False" weglassen, da jetzt Funktion bzw. Methode ohne explizite "return"-Anweisung "None" zurück liefert, welches wie "False" als falsch interpretiert wird:

Code: Alles auswählen

def hat_gewonnen(self, wer):
    for (a, b, c) in (0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), ...:
        if (self.feld[a], self.feld[b], self.feld[c]) == (wer, wer, wer):
            return True
Ich könnte den Computer die 8 Index-Tripel berechnen lassen. Das erscheint mir allerdings aufwendiger als sie per Hand aufzuzählen. Stattdessen will ich auf Indizes verzichten und direkt die drei Feldinhalte mittels "slicing" aus dem Feld zu schneiden. Außerdem ist "(wer,) * 3" noch etwas kürzer als das dreimalige explizite Wiederholen:

Code: Alles auswählen

def hat_gewonnen(self, wer):
    f = self.feld
    for tripel in f[0:3], f[3:6], f[6:9], f[0::3], f[1::3], f[2::3], f[::4], f[8::-4]:
        if tripel == (wer,) * 3:
            return True
Bis auf die beiden etwas trickreicheren diagonalen Tripel erkennt man immer noch Regelmäßigkeiten, die man nochmals auflösen könnte. Dazu benutze ich eine Generatorfunktion. Ich bin mir aber nicht sicher, ob dies eine Verbesserung darstellt:

Code: Alles auswählen

def hat_gewonnen(self, wer):
    def tripels():
        f = self.feld;
        for i in range(3):
            yield f[i * 3:(i + 1) * 3]; yield f[i::3]
        yield f[::4]; yield f[8::-4]
    for t in tripels():
        if t == (wer,) * 3:
            return True
Für den Tripel-Vergleich könnte man auch "if all(t == wer for t in tripel)" benutzen, was zwar länger ist, sich aber netter liest als ein schnöder Tupelvergleich und nicht mehr von der Anzahl 3 abhängig ist. Alle anderen Konstanten könnte man durch die Wurzel aus der Länge von "feld" ersetzen.

Ach und noch eine Bitte: Benutze kein "if foo == False" or "if bar == True" in Bedingungen. Es reicht ein "if not foo" der "if bar", denn wie weit willst du den Vergleich treiben? Der Ausdruck "foo == False" liefert ja wieder ein True oder False zurück und das Ergebnis müsstest du dann ja auch noch testen, also "(foo == False) == True".

Stefan
Antworten