I'm trying to create a Kivy based Tic-Tac-Toe game in Python using the Minimax algorithm, but the computer will not counter my movements

Viewed 133

As the title suggests, I'm trying to create a Tic-Tac-Toe game using the Minimax algorithm.

My problem occurs when the computer is supposed to counter my movements. Instead of doing so, it plays in what seems to be random yet repetitive patterns.

This is my first time using the Minimax algorithm, so any help or advice would be welcomed.

Thanks in advance!

Here is my code:

from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
import numpy as np
import random


class Board(GridLayout):
    def __init__(self):
        GridLayout.__init__(self)

        self.cols = 3
        self.level = 8
        self.listBoard = []

        array = ([0, 0, 0],
                 [0, 0, 0],
                 [0, 0, 0])

        self.array = np.array(array)

        for i in range(self.cols):
            listLine = []

            for j in range(self.cols):
                cell = Button(font_size=50, on_press=self.click)

                cell.i = i
                cell.j = j

                self.add_widget(cell)
                listLine.append(cell)

            self.listBoard.append(listLine)

        self.check = False

        start = random.randint(0, 1)

        self.player = ''
        self.computer = ''

        # player is 1, computer is 10

        if start == 1:

            self.player = 'X'
            self.computer = 'O'

        else:

            self.computer = 'X'
            self.player = 'O'

            move = self.minimax(self.array.copy(), self.level)
            self.listBoard[move[0]][move[1]].text = self.computer
            self.array[move[0]][move[1]] = 10

            print(self.array)

    def click(self, button):

        if button.text == '' and not self.check:
            button.text = self.player
            self.array[button.i][button.j] = 1

            print(self.array)

            if self.check_victory(self.array) == 'Player':
                print('Player Wins!')
                self.check = True

            moves = self.find_moves(self.array)

            if moves.any() and not self.check:
                move = self.minimax(self.array.copy(), self.level)
                self.listBoard[move[0]][move[1]].text = self.computer
                self.array[move[0]][move[1]] = 10

                print(self.array)

            elif self.check_victory(self.array) == 'None':
                print('Tie!')
                self.check = True

            if self.check_victory(self.array) == 'Computer' and not self.check:
                print('Computer Wins!')
                self.check = True

            moves = self.find_moves(self.array)

            if not moves.any() and self.check_victory(self.array) == 'None' and not self.check:
                print('Tie!')

    def find_moves(self, array):

        moves = np.argwhere(array == 0)
        return moves

    def check_victory(self, array):

        temp1 = array
        temp2 = np.rot90(array)

        column1 = np.sum(temp1, axis=0)
        column2 = np.sum(temp2, axis=0)

        diagonal1 = np.diag(temp1).sum()
        diagonal2 = np.diag(temp2).sum()

        for i in range(3):
            if column1[i] % 10 == 3 or column2[i] % 10 == 3:
                return 'Player'

            if column1[i] / 10 == 3 or column2[i] / 10 == 3:
                return 'Computer'

        if diagonal1 % 10 == 3 or diagonal2 % 10 == 3:
            return 'Player'

        if diagonal1 / 10 == 3 or diagonal2 / 10 == 3:
            return 'Computer'

        return 'None'

    def minimax(self, game_state, level):

        moves = self.find_moves(game_state)
        best_move = moves[0]
        best_score = float('-inf')

        for move in moves:
            clone = self.next_state(game_state.copy(), move[0], move[1], 'Computer')
            score = self.min_play(clone, level - 1)

            if score > best_score:
                best_move = move
                best_score = score

        return best_move

    def min_play(self, game_state, level):

        if self.check_victory(game_state) == 'Player' or level == 0:
            return self.evaluate(game_state)

        moves = self.find_moves(game_state)
        best_score = float('inf')

        for move in moves:

            clone = self.next_state(game_state.copy(), move[0], move[1], 'Player')
            score = self.max_play(clone, level - 1)

            if score < best_score:
                # best_move = move
                best_score = score

        return best_score

    def max_play(self, game_state, level):

        if self.check_victory(game_state) == 'Computer' or level == 0:
            return self.evaluate(game_state)

        moves = self.find_moves(game_state)
        best_score = float('-inf')

        for move in moves:
            clone = self.next_state(game_state, move[0], move[1], 'Computer')
            score = self.min_play(clone, level - 1)

            if score > best_score:
                # best_move = move
                best_score = score

        return best_score

    def next_state(self, array, i, j, who):

        if who == 'Player':
            array[i][j] = 1

        else:
            array[i][j] = 10

        return array

    def evaluate(self, array):

        if self.check_victory(array) == 'Player':
            return -1

        if self.check_victory(array) == 'Computer':
            return 1

        return 0

class TestApp(App):
    def build(self):
        self.title = 'based graphics'
        return Board()


TestApp().run()
0 Answers
Related