2016-07-13 30 views
0

Ich habe versucht, mein Verständnis von Python durch die Programmierung kleiner Spiele, wie Tic Tac Toe zu verbessern. Ich habe eine Kopie des Spiels von Grund auf neu erstellt, bin dann aber gegangen, um einen Weg zu finden, ein vernünftiges API für das Spiel zu erstellen. Ich habe mich für den Einsatz von minimax entschieden, um dieses Ziel zu erreichen. Ich habe ein Tutorial für den Algorithmus gefunden und versucht, es für das Spiel zu formen.Python - Minimax-Algorithmus für Tic Tac Toe Aktualisierung der Platine durch Füllen jedes leeren Raum mit dem gleichen Symbol

Allerdings, wenn der Code ausgeführt wird, auf der ai der erste Zug ist. Jeder leere Platz, der auf dem Spielfeld übrig ist, wird mit dem gleichen Symbol gefüllt, was einen Gewinn erzwingt und das Spiel unspielbar macht.

Da ich mit dem Algorithmus nicht vertraut und unerfahren war, nahm ich den Code von einem Youtube-Tutorial und editierte es, so dass es für das Spiel funktional war.

Hier ist der Code

import random 
import time 
import sys 
from sys import maxsize 




#converts numbers from the board to X O and "" for printing out the board 
def numToSymbol(board): 
    visual = board 
    for i in range(0, 9): 
     if visual[i] == -1: 
      visual[i]= "X" 
     elif visual[i] == 1: 
      visual[i] = "O" 
     elif visual[i] == 0: 
      visual[i] = " " 
    return visual 


def symbolToNum(visual): 
    board = visual 
    for i in range(0, 9): 
     if board[i] == "X": 
      board[i] = -1 
     elif board[i] == "O": 
      board[i] = 1 
     elif board[i] == " ": 
      board[i] = 0 
    return board 


# prints the board, first coverting numbers throught numtoSymbol 
def drawBoard(): 
    visual = numToSymbol(board) 
    print(
     "|"+ str(visual[0]) + "|" + str(visual[1]) + "|" + str(visual[2]) + "| \n" 
     "-------\n" 
     "|"+ str(visual[3]) + "|" + str(visual[4]) + "|" + str(visual[5]) + "| \n" 
     "-------\n" 
     "|"+ str(visual[6]) + "|" + str(visual[7]) + "|" + str(visual[8]) + "| \n" 
     "-------") 
    symbolToNum(visual) 


# checks the possible options for 3 in a row and if any are all held by one side returns true 
def checkWin(board, winConditions, ai): 
    if ai == True: 
     win = 3 
    if ai == False: 
     win = -3 
    for row in winConditions: 
     checkA = board[row[0]] 
     checkB = board[row[1]] 
     checkC = board[row[2]] 
     if checkA + checkB + checkC == int(win): 
      return True 

    return False 

def checkDraw(board): 
    emptyTile = 9 
    for tile in board: 
     if tile != 0: 
      emptyTile -= 1 
    if emptyTile == 0: 
     completion(2) 

def availableMoves(board, bonus): 
    availableSlots = [] 
    for position in range(0,9): 
     if board[position] == 0: 
      availableSlots.append(position + bonus) 
    return availableSlots 



def playerTurn(board, remainingTurns): 
    board = board 
    checkDraw(board) 
    visual =drawBoard() 
    print("pick one of the available slots \n") 
    availableSlots = availableMoves(board, 1) 
    print(availableSlots) 
    choice = int(input('Select a tile from those shown above:\n')) -1 
    while True:  
     if 0 <= choice <= 8: 
      if board[choice] == 0: 
       board[choice] = -1 
       break 
      else: 
       choice = int(input('Select a tile from those shown above which has not already been selected:\n')) -1 
     else: 
      choice = int(input('Select a tile from those shown above:\n')) -1 
    visual = drawBoard() 
    if checkWin(board, winConditions, False) == True: 
     completion(0) 
    else: 
     aiTurn(board, remainingTurns - 1) 


class Node(object): 

    def __init__(self, remainingTurns, playerNum, board, value = 0): 
     self.depth = remainingTurns 
     self.playerNum = playerNum 
     self.board = board 
     self.value = value 
     self.moves = availableMoves(self.board, 0) 
     self.children = [] 
     self.createChildren() 

    def availableMoves(self, board): 
     self.availableSlots = [] 
     for position in range(0,9): 
      if board[position] == 0: 
       availableSlots.append(position) 
     return self.availableSlots 

    def winCheck(self, state, playerNum): 
     self.winConditions = [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]] 
     self.win = 3 
     for row in self.winConditions: 
      self.checkA = self.state[row[0]] 
      self.checkB = self.state[row[1]] 
      self.checkC = self.state[row[2]] 
      if self.checkA + self.checkB + self.checkC == int(self.win * self.playerNum): 
       return True 
     return False 

    def createChildren(self): 
     if self.depth > 0: 
      for i in self.moves: 
       self.state = self.board 
       self.state[i] = self.playerNum 
       print(board) 
       self.children.append(Node(self.depth - 1, self.playerNum * -1, self.state, self.realVal(self.state, self.playerNum))) 


    def realVal(self, value, playerNum): 
     value = self.winCheck(self.state, self.playerNum) 
     if value == True: 
      return maxsize * self.playerNum 
     else: 
      return 0 




def minimax(node, depth, playerNum): 
    if depth == 0 or abs(node.value) == maxsize: 
     return node.value 

    bestValue = maxsize * -playerNum 

    for i in range(len(node.children)): 
     child = node.children[i] 
     val = minimax(child, depth - 1, -playerNum) 
     if (abs(maxsize * playerNum - val) < abs(maxsize * playerNum - bestValue)): 
      bestValue = val 
    return bestValue 


def aiTurn(board, remainingTurns): 
    checkDraw(board) 
    print('Waiting for ai') 
    time.sleep(2) 
    board = board 
    state = board 
    currentPlayer = 1 
    tree = Node(remainingTurns, currentPlayer, state) 
    bestChoice = -100 
    bestValue = maxsize * -1 
    for i in range(len(tree.children)): 
     n_child = tree.children[i] 
     i_val = minimax(n_child, remainingTurns, -currentPlayer,) 
     if (abs(currentPlayer * maxsize - i_val) <= abs(currentPlayer * maxsize - bestValue)): 
      bestValue = i_val 
      bestChoice = i 
    print(bestChoice) 
    print(board) 
    #choice = minimax(tree, remainingTurns, 1) 
    board[bestChoice] = 1 
    print(board) 
    if checkWin(board, winConditions, True) == True: 
     completion(1) 
    else: 
     playerTurn(board, remainingTurns - 1) 



def completion(state): 
    if state == 1: 
     print('The computer has won this game.') 
     choice = str(input('press y if you would like to play another game; Press n if you would not \n')) 
     if choice == 'y' or choice == 'Y': 
      playGame() 
     else: 
      sys.exit() 
    if state == 0: 
     print('you win!') 
     choice = str(input('press y if you would like to play another game; Press n if you would not \n')) 
     if choice == 'y' or choice == 'Y': 
      playGame() 
     else: 
      sys.exit() 
    if state == 2: 
     print('you drew') 
     choice = str(input('press y if you would like to play another game; Press n if you would not \n')) 
     if choice == 'y' or choice == 'Y': 
      playGame() 
     else: 
      sys.exit()   




def playGame(): 
    global board 
    board = [0,0,0,0,0,0,0,0,0] 

    global winConditions 
    winConditions = [ 
       [0, 1, 2], 
       [3, 4, 5], 
       [6, 7, 8], 
       [0, 3, 6], 
       [1, 4, 7], 
       [2, 5, 8], 
       [0, 4, 8], 
       [2, 4, 6] 
       ] 


    global remainingTurns 
    remainingTurns = 9 
    playerFirst = random.choice([True, False]) 

    if playerFirst == True: 
     playerTurn(board, remainingTurns) 
    else: 
     aiTurn(board, remainingTurns) 


if __name__ == '__main__': 
    playGame() 

Dies ist die Ausgabe des obigen Code ist

[1, 0, 0, 0, 0, 0, 0, 0, 0] 
[1, -1, 0, 0, 0, 0, 0, 0, 0] 
[1, -1, 1, 0, 0, 0, 0, 0, 0] 
[1, -1, 1, -1, 0, 0, 0, 0, 0] 
[1, -1, 1, -1, 1, 0, 0, 0, 0] 
[1, -1, 1, -1, 1, -1, 0, 0, 0] 
[1, -1, 1, -1, 1, -1, 1, 0, 0] 
[1, -1, 1, -1, 1, -1, 1, -1, 0] 
[1, -1, 1, -1, 1, -1, 1, -1, 1] 
[1, -1, 1, -1, 1, -1, 1, -1, -1] 
[1, -1, 1, -1, 1, -1, 1, 1, -1] 
[1, -1, 1, -1, 1, -1, 1, 1, 1] 
[1, -1, 1, -1, 1, -1, -1, 1, 1] 
[1, -1, 1, -1, 1, -1, -1, -1, 1] 
[1, -1, 1, -1, 1, -1, -1, -1, -1 
[1, -1, 1, -1, 1, 1, -1, -1, -1] 
[1, -1, 1, -1, 1, 1, 1, -1, -1] 
[1, -1, 1, -1, 1, 1, 1, 1, -1] 
[1, -1, 1, -1, 1, 1, 1, 1, 1] 
[1, -1, 1, -1, -1, 1, 1, 1, 1] 
[1, -1, 1, -1, -1, -1, 1, 1, 1] 
[1, -1, 1, -1, -1, -1, -1, 1, 1] 
[1, -1, 1, -1, -1, -1, -1, -1, 1 
[1, -1, 1, -1, -1, -1, -1, -1, - 
[1, -1, 1, 1, -1, -1, -1, -1, -1 
[1, -1, 1, 1, 1, -1, -1, -1, -1] 
[1, -1, 1, 1, 1, 1, -1, -1, -1] 
[1, -1, 1, 1, 1, 1, 1, -1, -1] 
[1, -1, 1, 1, 1, 1, 1, 1, -1] 
[1, -1, 1, 1, 1, 1, 1, 1, 1] 
[1, -1, -1, 1, 1, 1, 1, 1, 1] 
[1, -1, -1, -1, 1, 1, 1, 1, 1] 
[1, -1, -1, -1, -1, 1, 1, 1, 1] 
[1, -1, -1, -1, -1, -1, 1, 1, 1] 
[1, -1, -1, -1, -1, -1, -1, 1, 1 
[1, -1, -1, -1, -1, -1, -1, -1, 
[1, -1, -1, -1, -1, -1, -1, -1, 
[1, 1, -1, -1, -1, -1, -1, -1, - 
[1, 1, 1, -1, -1, -1, -1, -1, -1 
[1, 1, 1, 1, -1, -1, -1, -1, -1] 
[1, 1, 1, 1, 1, -1, -1, -1, -1] 
[1, 1, 1, 1, 1, 1, -1, -1, -1] 
[1, 1, 1, 1, 1, 1, 1, -1, -1] 
[1, 1, 1, 1, 1, 1, 1, 1, -1] 
[1, 1, 1, 1, 1, 1, 1, 1, 1] 
8 
[1, 1, 1, 1, 1, 1, 1, 1, 1] 
[1, 1, 1, 1, 1, 1, 1, 1, 1] 
The computer has won this game. 

Irgendwelche Vorschläge?

Antwort

0

Problem liegt, wenn Sie Ihren Knoten init Sie einfach den ref von board kopieren:

self.board = board 

während Sie die Werte

self.board = board[::] 

Else alle Ihre Knoten Objekte beziehen sich auf derselben Platte kopieren sollten: der globale.