Tic Tac Toe programmieren?
Moin,
ich will grad ein Tic Tac Toe in Python programmieren.
Jetzt stehe ich aber vor dem Problem:
print("Willkommen in Tic Tac Toe")
spielfeld = [" ",
"1","2","3",
"4","5","6",
"7","8","9"]
def spielfeld_ausgeben():
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
class GameLogic:
def Spielzug_Spieler1():
spielfeld_ausgeben()
spielzug1 = input("Auf welches Feld willst du setzen Spieler1 ? ")
def Spielzug_Spieler2():
spielfeld_ausgeben()
spielzug2 = input("Auf welches Feld willst du setzen Spieler2 ? ")
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Hier ist das Problem:
def Spielfeld_ändern():
spielfeld[spielzug1] = "X"
# Wie kann ich das spielfeld an der Stelle der beim Input angegeben wird ändern?
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Ich würde mich über Tips freuen.
2 Antworten
Also erstent würde ich Umlaut in Python vermeiden, aber grundsätzlich geht das so
feldVoll = False
spielFeld = [[0 for i in range(3)] for j in range(3)]
#Spielfeld ist anfangs mit 0 gefüllt 1=X, 2=O, Leer = #
def checkFeldVoll(feld):
for zeile in feld:
for spalte in zeile:
if spalte==0:
return False
return True
def feldUpdate(feld,y,x,spielerId):
if(feld[y][x] != 0):
return (False,[])
feld[y][x] = spielerId
return (True,feld)
def feldPrint(feld):
print('\n'.join('|'.join('#XO'[piece] for piece in i) for i in feld))
player = 1 #X beginnt
while not feldVoll:
moveOk = False
while not moveOk:
while True:
try:
zeile,spalte=map(int,input('Eingabe [Zeile,Spalte]: ').split(','))
if(zeile < 0 or zeile > 2 or spalte < 0 or spalte > 2):
print('Nur Zahlen von 0 bis 2 eingeben!')
else:
break
except ValueError:
print('Bitte nur Ganzzahlen eingeben!')
res = feldUpdate(spielFeld,zeile,spalte,player)
if res[0]:
spielFeld = res[1]
moveOk = True
else:
print('Feld breits voll!')
feldPrint(spielFeld)
feldVoll = checkFeldVoll(spielFeld)
if(player == 1):
player = 2
else:
player = 1
print('Feld komplett voll')
#Das ganze prüft nicht auf gewinn, aber das bekommst du sicher hin.
Was verstehst du denn nicht? Ich habe eigentlich alles angepasst, da ich dein Spielfeld nicht verstehe
spielfeld = [" ",
"1","2","3",
"4","5","6",
"7","8","9"]
Wie wolltest du denn das verwalten?
So wie ich es vorher geschrieben hab. Also mit spielfeld[xbeliebig] = ...
Das geht dann eben nur einmal, da wenn du z.B. die "7" durch X tauschsts du nicht mehr weißt was das 7te Feld ist. Bei TicTacToe ist das zwar kein Problem, jedoch würde ich dir trotzdem rate dir mal mein 2d Array anzscchauen.
#Diese Zeile
spielFeld = [[0 for i in range(3)] for j in range(3)]
#macht eigentlich nur so ein Feld
spielFeld = [[0,0,0],[0,0,0],[0,0,0]
#Auf dem Feld hast du dann in y-Richtung 3 Zeilen und in x-Richtung 3 spalten
#Also z.B. obere linke ecke
obenLinks = spielFeld[0][0] # == 0
#Ich habe mir jetzt einfach überleget, dass 0 leer, 1 X und 2 O bedeuten (was du auch in der feldPrint Funktion siehst
Saibotix07's Idee ist gar nicht schlecht. Er nummeriert die Felder von 1 bis 9 und zeigt entweder die Nummer des nochfreien Feldes oder seinen Inhalt (O oder X) an. Dann muss man keine Zeilen/Spalten abzählen, sondern gibt einfach eine der angezeigten Ziffern ein. Das macht auch die Prüfung frei/besetzt recht einfach.
Wie gesagt kann man es ja so machen, jedoch finde ich ist es auch gut gleich von Anfang sich ein wenig mit dem Standart vertraut zu machen ;)
Standart? Obststand oder Kleiderstand? ;-)
Aber wer setzt denn den Standard für TicTacToe? Nur weil viele ein 2D-Array benutzen, muss das doch nicht die allein selig machende Lösung sein. Man lernt als Anfänger mehr, wenn man seine Idee umsetzt, als wenn man fertige Lösungen von anderen abschreibt. Die 2D-Lösung bringt meiner bescheidenen Meinung nach hier keine Vorteile. Die 8 Möglichkeiten für Spalte, Reihe oder Diagonale kann man auch aufzählen, da muss man nicht unbedingt mit Schleifen arbeiten.
Wie gesagt er hat ja jetzt 2 richtige und gute Wege und kann wählen ;) Ich fände es einfach nur komisch das 2d-Array nicht zu erwähnen. Und Vorteile hat das 2d-Array hier wirklich keine, bis auf das, dass man es auch auf andere Felder wie ein 2048 Feld übertragen könnte. Zudem habe ich immer viel von Code von anderen veruscht zu lernen, deshalb der bisschen längere Code.
spielfeld[int(spielzug1)] = 'X'
input liefert dir eine Zeichenkette (String). Damit du das als Index benutzen kannst, musst du es in ein int umwandeln.
Ja, weil spielzug1 nur eine lokale Variable in Spielzug_Spieler1() ist. Besser du übergibst die Nummer des zu ändernden Spielfelds als Parameter :
def Spielfeld_aendern_auf_X(spielzug):
spielfeld[spielzug] = 'X'
def Spielfeld_aendern_auf_O(spielzug):
spielfeld[spielzug] = 'O'
oder besser beide zusammenfassen:
def spielfeld_aendern(spielzug,zeichen):
spielfeld[spielzug] = zeichen
Aufruf dann z.B.
spielfeld_aendern(spielzug1,'X')
spielfeld_aendern(spielzug2,'O')
Vorher hast du in Spielzug_Spieler geprüft, ob eine Ziffer 1-9 eingeben wurde und ob das Feld noch frei ist.
Ich sehe da ein kleines Problem: spielfeld ist eine globale Variable. Man kann sie in einer Methode „einfach so“ lesen, aber nicht überschreiben.
Außer, man sagt explizit dazu, dass man genau diese fehlerträchtige Pfuscherei beabsichtigt:
def spielfeld_aendern(spielzug,zeichen):
global spielfeld
spielfeld[spielzug] = zeichen
Autsch, mein Fehler: Es funktioniert (leider) auch ohne „global“, weil spielfeld eine Liste ist. Ihre Elemente darf man ungestraft „einfach so“ ändern.
Eigentlich sollte das verboten werden …
Fehlerträchtige Pfuscherei ;-)
Ja, das ist von einer funktionierenden Lösung noch ein paar Schritte entfernt. Wenn der Frager das irgendwann ans Laufen kriegt, dabei bleibt und das gleiche Problem in zwei Jahren mit mehr Erfahrung nochmal angeht, wird die Lösung sicher völlig anders aussehen.
Erfahrung ist die Summe aller selbst gemachten Fehler (beim Programmieren kann man die Fehler fast immer ungeschehen machen, im richtigen Leben leider nicht)
Aber das global definierte spielfeld kann tatsächlich in der Methode verwendet werden, ohne dass man spielfeld explizit als global definieren muss. global muss man nur schreiben, wenn eine Zuweisung stattfindet und diese keine lokale Variable erzeugen soll. Der Name spielfeld existiert bereits und bezeichnet ein existierendes Objekt, auf das per Index zugegriffen wird.
Das funktioniert natürlich nur, wenn der Spieler brav ist und nur Ziffern eingibt, die noch frei sind. Wenn du dich darauf nicht verlassen kannst, prüfst du das direkt bei der Eingabe. Aber vielleicht willst du dich um sowas auch erst kümmern, wenn alles andere klappt.
Danke erstmal. Aber für mich sieht das alles sehr komplex aus und ich weiß nicht ob ich das hinbekomme wenn ich den Rest nicht verstehe... :(