Tic Tac Toe

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
FroxGame
User
Beiträge: 12
Registriert: Samstag 1. September 2018, 11:35

Hallo,
ich habe ein kleines Problem in meinem Tic Tac Toe, und zwar funktioniert der Zug des Computers nicht(Funktion: computer_move). Ich möchte aber schon, dass der Computerzug erstmal random ist. Die " richtige KI" möchte ich auch selber coden :) . Was habe ich falsch gemacht?
Vielen Dank für Antworten.

Code: Alles auswählen

import random
def draw_board(board):
    #Gibt das Spielfeld mit eingesetzten Zeichen wider
    print("   |   |   ")
    print(" " + board[7] + " | " + board[8] + " | " + board[9])
    print("   |   |   ")
    print("------------")
    print("   |   |   ")
    print(" " + board[4] + " | " + board[5] + " | " + board[6])
    print("   |   |   ")
    print("------------")
    print("   |   |   ")
    print(" " + board[1] + " | " + board[2] + " | " + board[3])
    print("   |   |   ")

def player_move(board, sign):
    #Lässt den Spieler/die Spieler den Zug bestimmen
    while True:
        try:  #Idiotensicher
            field = int(input("Auf welchem Feld möchtest du {} platzieren? (Zahl von 1 - 9)".format(sign)))
            if field < 1 or field > 9:
                print("Gib Zahl von 1 -9 ein.")
            elif board[field] != " ":
                print("Das Feld ist schon belegt, nimm ein anderes Feld!")
            else:
                break
        except ValueError:
            player_move(board,sign)
    board[field] = sign
    draw_board(board)

def main_player(turn):
    #Leitet den Spieler richtig zur player_move Funktion
    if turn == 1:
        player_move(board, "X")
    elif turn == -1:
        player_move(board, "O")

def main_computer(turn):
    #Leitet den Computer richtig zur computer_move Funktion
    if turn == 1:
        computer_move(board, "X")
    elif turn == -1:
        computer_move(board, "O")

def is_winner(bo, le):
    #Checkt, ob jemand gewonnen hat
    if le == 1:
        le = "X"
    elif le == -1:
        le = "O"
    return ((bo[1] == le and bo[2] == le and bo[3] == le) or
    (bo[4] == le and bo[5] == le and bo[6] == le) or
    (bo[7] == le and bo[8] == le and bo[9] == le) or
    (bo[1] == le and bo[4] == le and bo[7] == le) or
    (bo[2] == le and bo[5] == le and bo[8] == le) or
    (bo[3] == le and bo[6] == le and bo[9] == le) or
    (bo[1] == le and bo[5] == le and bo[9] == le) or
    (bo[3] == le and bo[5] == le and bo[7] == le))

def play_again():
    #Fragt nach, ob nochmal gespielt werden soll
    print("Möchtest du nochmal spielen?(ja oder nein)")
    return input().lower().startswith("j" or "J")

def is_free(board, move):
    #Vielleicht unnötig??????????????????
    return board[move]==[" "]

def computer_move(board, letter):
    #Lässt den Computer seinen Zug bestimmen. Diese Funktion meinte ich in der Frage!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    print("Der Computer ist dran:")
    move = 1
    while board[move] != [" "]:
        move = random.randint(1,9)
    else:
        board[move] = letter
        draw_board(board)

sign = "O" and "X"

print("WIllkomen bei Tic Tac Toe!")
while True:
    counter = 0
    move = 1       						
    mode = 0						#Hier wird alles resettet
    board = [" "] * 10
    gameIsPlaying = True
    while mode != "PvP" and  mode != "PvE" and mode != "EvE":
        mode = input("Möchtest du PvP, PvE oder EvE spielen?")
    if mode == "PvP":
    #ES wird Spieler gegen Spieler gespielt
        while gameIsPlaying:
            if move == 1 or move == -1:
                main_player(move)
                counter = counter+1
                if is_winner(board, move):
                    if move == 1:
                        move = "X"
                    elif move == -1:
                        move = "O"
                    print("Super, Spieler {} hat gewonnen!".format(move))
                    gameIsPlaying = False
                elif counter == 9:
                    print("Unentschieden!")
                    gameIsPlaying = False
                move = move * -1

        if not play_again():
            break

    elif mode == "PvE":
    #Es wird Spieler gegen Computer gespielt
        while gameIsPlaying:
            if move == 1:
                main_player(1)
                move = -1
                counter = counter + 1
                if is_winner(board, "X"):
                    print("Super, du hast gewonnen!")
                    gameIsPlaying = False
                elif counter == 9:
                    print("Unentschieden")
                    gameIsPlaying = False
            elif move == -1:
                computer_move(board)
                move = 1
                counter = counter + 1
                if is_winner(board, "O"):
                    print("Schade, der Computer gewinnt!")
                    gameIsPlaying = False
                elif counter == 9:
                    print("Unentschieden")
                    gameIsPlaying = False

        if not play_again():
            break

    elif mode == "EvE":
    #ES wird Computer gegen Computer gespielt
        while gameIsPlaying:
            if move == 1 or move == -1:
                main_computer(move)
                counter = counter + 1
                if is_winner(board, move):
                    if move == 1:
                        move = "X"
                    elif move == -1:
                        move = "O"
                    print("Computer {} hat gewonnen!".format(move))
                    gameIsPlaying = False
                elif counter == 9:
                    print("Unentschieden!")
                    gameIsPlaying = False
                move = move * -1

            if not play_again():
                break
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@FroxGame: player_move ist fehlerhaft. Rekursion ist selten sinnvoll und hier falsch angewendet. Statt also player_move nochmal aufzurufen wäre ein `print('falsche Eingabe')` ausreichend.

Die Kommentare gleich anch den defs wären besser doc-Strings.

Warum bekommen main_player und main_computer `turn` als -1 und 1 und nicht gleich als X oder O? Dann sind die beiden Funktionen (bei denen das main für mich keinen Sinn macht) überflüssig.
Die Funktionen bekommen `board` aus dem nichts, das sollte ein Parameter sein.
Bei is_winner heißt turn sogar le, was ein völlig nichtssagender Name ist.

Mit `turn == bo[1] == bo[2] == bo[3]` kann man die Bedinung kürzer schreiben.

In `play_again` ist der Sinn von `'j' or 'J'` ziemlich fraglich, weil das einfach nur 'j' ist. Schau Dir nochmal die Funktionsweise von `or` und `and` als logische Operatoren an.

Da `is_free` nicht benutzt wird, ist es im Moment unnötig. Vor allem ist es aber falsch, weil ein String nie gleich einer Liste ist. In `computer_move` hast Du den selben Fehler nochmal gemacht.

Ein `else` bei einem `while` ohne `break` ist verwirrend. Es ist auch unzufällig, wenn der Computer immer als ersten Zug das erste Feld belegt.

Bei `sign = "O" and "X"` gilt das selbe wie bei `or`. Schau dir nochmal die Funktionsweise von logische Operatoren an.

Dreimal fast den selben Code für PvP PvE oder EvE zu schreiben, ist schlechter Stil; definier Dir zwei Variablen, welche main_-Funktion X und welche O aufruft und Du hast nur noch einen Fall.

Statt eines Flags `gameIsPlaying` (das übrigens nicht nach Konvention geschrieben ist) benutzt man eine Endlosschleife, die man mit break verläßt. Da man hier aber nur 9 Durchgänge hat, ist eine for-Schleife das beste.

Im PvP-Fall: Wäre die if-Abfrage für mode nicht erfüllt, hättest Du eine nie endende Schleife, da es aber immer erfüllt ist, ist sie einfach nur überflüssig.

Im EvE-Fall ist play_again falsch eingerückt.

`mode` wird für sehr viele verschiedene Dinge benutzt. Das führt nur zu fehlerhaften Programmen. Benutze für jeden Zweck eine eigene Variable.

die Hauptschleife könnte also so aussehen:

Code: Alles auswählen

from itertools import islice, cycle

for turn in islice(cycle('XO'), 9):
    if mode == "PVP" or (turn == "X" and mode == "PvE"):
        player_move(board, turn)
    else:
        computer_move(board, turn)
    if is_winner(board, turn):
        print("Spieler {} hat gewonnen!".format(turn))
        break
else:
    print("Unentschieden")
FroxGame
User
Beiträge: 12
Registriert: Samstag 1. September 2018, 11:35

@Sirius3: Vielen Dank für die vielen Tips, allerdings ist meine Hauptfrage noch nicht geklärt, und zwar wie ich den Zug vom Computer zum Laufen bekomme. Aber sonst vielen Dank!
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@FroxGame: den Fehler habe ich Dir genannt. Die Frage ist, was der richtige Vergleich ist.
FroxGame
User
Beiträge: 12
Registriert: Samstag 1. September 2018, 11:35

@Sirius3: Ich habe deine Hinweise verstanden, allerdings wird bei mir beim Zug des Computers nichts ausgegeben
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Wsa bedeutet, „Es wird nichts ausgegeben”?
FroxGame
User
Beiträge: 12
Registriert: Samstag 1. September 2018, 11:35

Naja das ist zum Beispiel die Ausgabe, wenn ich PvE nehme. Das Programm sagt einfach nix mehr und ich weiß nicht, warum.:

WIllkomen bei Tic Tac Toe!
Möchtest du PvP, PvE oder EvE spielen?PvE
Auf welchem Feld möchtest du X platzieren? (Zahl von 1 - 9)1
| |
| |
| |
------------
| |
| |
| |
------------
| |
X | |
| |
Der Computer ist dran:
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Es sagt nichts mehr, weil es in einer Endlosschleife hängt, weil die Abbruchbedingung nie erfüllt sein kann.
FroxGame
User
Beiträge: 12
Registriert: Samstag 1. September 2018, 11:35

Ok, vielen Dank. Ich kümmer mich drum.
Antworten