Tic Tac Toe programmieren?

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.
Woher ich das weiß:Studium / Ausbildung – Informatikstudent

Saibotix07 
Beitragsersteller
 16.07.2021, 20:44

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... :(

2
whgoffline  16.07.2021, 20:45
@Saibotix07

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?

0
Saibotix07 
Beitragsersteller
 16.07.2021, 20:46
@whgoffline

So wie ich es vorher geschrieben hab. Also mit spielfeld[xbeliebig] = ...

0
whgoffline  16.07.2021, 20:50
@Saibotix07

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
1
Schachpapa  16.07.2021, 20:52
@whgoffline

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.

2
whgoffline  16.07.2021, 20:53
@Schachpapa

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 ;)

0
Schachpapa  16.07.2021, 21:00
@whgoffline

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.

4
whgoffline  16.07.2021, 21:07
@Schachpapa

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.

0
spielfeld[int(spielzug1)] = 'X'

input liefert dir eine Zeichenkette (String). Damit du das als Index benutzen kannst, musst du es in ein int umwandeln.


Saibotix07 
Beitragsersteller
 16.07.2021, 20:51

Bei mir wird spielzug1 nicht gefunden

0
Schachpapa  16.07.2021, 21:12
@Saibotix07

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.

1
ralphdieter  16.07.2021, 21:54
@Schachpapa

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
1
ralphdieter  16.07.2021, 22:07
@ralphdieter

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 …

2
Schachpapa  16.07.2021, 22:18
@ralphdieter

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.

1
Saibotix07 
Beitragsersteller
 16.07.2021, 20:44

Danke :D

0
Schachpapa  16.07.2021, 20:49
@Saibotix07

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.

1