Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Drawing a net of a cube
#16
I want to change this 2-player game into a game against computer. I tried to implement this minimax algorithm that's in the first class in my code but I can't make it work. I tried a couple of options but I can't handle it.

I would appreciate some help!

Here's the old code version without my silly tries (XD) and class Robot with the minimax function that I'm trying to implement and adapt in the beginning of the code:

import tkinter as tk

#TRYING TO IMPLEMENT CLASS ROBOT

#START

class Robot:
    def __init__(self, cube):
        self.boards = cube.boards
 
    def get_scores(self, board):
        """Get scores for all open squares on a board"""
 
        def minimax(mark, square, alpha=-1000, beta=1000, depth=0):
            """minimax algorithm with alpha/beta pruning"""
            # Place the mark and check for a win
            square.mark = mark
            if square.check_win():
                # Give extra weight to earlier wins/losses
                score = 10 - depth if mark is ROBOT else depth - 10
                board.depth = min(board.depth, depth)
            elif len(empty_squares := board.empty_squares()) == 0:
                # No plays left.  Draw.
                score = 0
            elif mark is PLAYER:
                # Pick best move for robot
                score = -1000
                for s in empty_squares:
                    score = max(score, minimax(ROBOT, s, alpha, beta, depth+1))
                    alpha = max(alpha, score)
                    if alpha > beta:
                        break
            else:
                # Guess what move player will make
                score = 1000
                for s in empty_squares:
                    score = min(score, minimax(PLAYER, s, alpha, beta, depth+1))
                    beta = min(beta, score)
                    if alpha > beta:
                        break
 
            # Remove mark and return score for the square
            square.mark = EMPTY
            return score
 
        # Collect scores for empty squares.  If board is empty,
        # minimax will return 0 for all squares
        board.depth = 10
        empty_squares = board.empty_squares()
        if len(empty_squares) == 9:
            board.scores = [[0, s] for s in empty_squares]
        else:
            # Calling minimax twice.  The first is to find the square
            # giving us best chance to win board.  Second is to prevent
            # abandoning board early and giving player an easy win.
            board.scores = [[minimax("O", s), s] for s in empty_squares]
            [minimax("X", s, depth=1) for s in empty_squares]
 
    def play(self):
        """Place robot mark."""
        # Get scores for all empty squares
        depth = 10
        for board in self.boards:
            self.get_scores(board)
            depth = min(depth, board.depth)
 
        # Select board with minimum depth.  This is the board that
        # will win/lose in the least number of moves.
        scores = []
        for board in self.boards:
            if board.depth <= depth:
                scores.extend(board.scores)
 
        # Randomly select from best scores on the selected board.
        max_score = max(score[0] for score in scores)
        squares = [score[1] for score in scores if score[0] >= max_score]
        return random.choice(squares)
    
#END
 
class Square(tk.Button):
    """Special button for playing tic-tac-toe."""
    colors = {"O": "blue", "X": "red"}
  
    def __init__(self, parent, index):
        super().__init__(parent, width=3, font=('Comic Sans MS', 20, 'bold'))
        self.index = index
        self._mark = None
  
    @property
    def mark(self):
        """What marker appears in square."""
        return self._mark
  
    @mark.setter
    def mark(self, mark):
        self._mark = mark
        self["fg"] = self.colors.get(mark, 'black')
        self["text"] = '' if mark is None else mark
  
  
class TicTacToe(tk.Tk):
    """Play tic-tac-toe.  Players take turn clicking on empty buttons
    to place their marker.  The first player to get three markers in
    a row, up/down, sideways or diagonally, wins
    """
    # All possible winning conbinations
    wins = ((0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8),
            (9, 10, 11), (12, 13, 14), (15, 16, 17), (9, 12, 15), (10, 13, 16), (11, 14, 17),
            (18, 19, 20), (21, 22, 23), (24, 25, 26), (18, 21, 24), (19, 22, 25), (20, 23, 26),
            (27, 28, 29), (30, 31, 32), (33, 34, 35), (27, 30, 33), (28, 31, 34), (29, 32, 35),
            (36, 37, 38), (39, 40, 41), (42, 43, 44), (36, 39, 42), (37, 40, 43), (38, 41, 44),
            (45, 46, 47), (48, 49, 50), (51, 52, 53), (45, 48, 51), (46, 49, 52), (47, 50, 53),

            (3, 6, 36, 39), (4, 7, 37, 40), (5, 8, 38, 41),
            (18, 21, 39, 42), (19, 22, 40, 43), (20, 23, 41, 44),
            (28, 29, 36, 37), (31, 32, 39, 40), (34, 35, 42, 43),
            (37, 38, 45, 46), (40, 41, 48, 49), (43, 44, 51, 52),
            (9, 12, 21, 24), (10, 13, 22, 25), (11, 14, 23, 26),

            (0, 3, 12, 15), (1, 4, 13, 16), (2, 5, 14, 17), 
            (27, 28, 46, 47), (30, 31, 49, 50), (33, 34, 52, 53),

            (0, 1, 27, 30), (3, 4, 28, 31), (6, 7, 29, 32),
            (1, 2, 47, 50), (4, 5, 46, 49), (7, 8, 45, 48),

            (18, 19, 32, 35), (21, 22, 31, 34), (24, 25, 30, 33),
            (19, 20, 48, 51), (22, 23, 49, 52), (25, 26, 50, 53),

            (15, 16, 27, 28), (12, 13, 30, 31), (9, 10, 33, 34),
            (16, 17, 46, 47), (13, 14, 49, 50), (10, 11, 52, 53),

            (6, 37, 41, 51), (7, 38, 48, 52), (7, 32, 34, 36), (8, 35, 37, 39),
            (19, 28, 32, 42), (20, 29, 39, 43), (18, 41, 43, 45), (19, 44, 46, 48),
            (19, 23, 32, 42), (19, 21, 44, 48)) #last one example of a diagonal combo over 2 boards
              
    def __init__(self):
        super().__init__()
        self.title('Tic Tac Toe')
         
        # create a frame to hold all four boards
        self.boards_frame = tk.Frame(self)
        self.boards_frame.pack(side="top", padx=5, pady=5)
         
        # create the left board
        self.frame1 = tk.Frame(self.boards_frame)
        self.frame1.pack(side="left")
        
        self.squares1 = []

        for i in range(9):
            self.squares1.append(Square(self.frame1, i))
        for square in self.squares1:
            row = square.index // 3
            column = square.index % 3         
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares1))

        self.frame1.pack(side="top")
        
        self.frame2 = tk.Frame(self.boards_frame)
        self.frame2.pack(side="left")

        for i in range(9, 18):
            self.squares1.append(Square(self.frame2, i))
        for square in self.squares1:        
            row = square.index // 3
            column = square.index % 3
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares1))

        self.frame3 = tk.Frame(self.boards_frame)
        self.frame3.pack(side="left")

        for i in range(18, 27):
            self.squares1.append(Square(self.frame3, i))
        for square in self.squares1:
            row = square.index // 3
            column = square.index % 3         
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares1))

        
        self.frame4 = tk.Frame(self.boards_frame)
        self.frame4.pack(side="left")

        for i in range(27, 36):
            self.squares1.append(Square(self.frame4, i))
        for square in self.squares1:
            row = square.index // 3
            column = square.index % 3      
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares1))

        
        self.frame5 = tk.Frame(self.boards_frame)
        self.frame5.pack(side="left")

        for i in range(36, 45):
            self.squares1.append(Square(self.frame5, i))
        for square in self.squares1:
            row = square.index // 3
            column = square.index % 3      
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares1))

        
        self.frame6 = tk.Frame(self.boards_frame)
        self.frame6.pack(side="left")

        for i in range(45, 54):
            self.squares1.append(Square(self.frame6, i))
        for square in self.squares1:
            row = square.index // 3
            column = square.index % 3
                 
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares1))

        self.frame2.pack(side="bottom")
        self.frame3.pack(side="bottom")
        
        '''
        # create the middle-left board
        self.frame2 = tk.Frame(self.boards_frame)
        self.frame2.pack(side="left")
        
        self.squares2 = [Square(self.frame2, i) for i in range(9)]
        for square in self.squares2:
            row = square.index // 3
            column = square.index % 3
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares2, self.squares1))

        
        # create the middle-right board
        self.frame3 = tk.Frame(self.boards_frame)
        self.frame3.pack(side="left")
         
        self.squares3 = [Square(self.frame3, i) for i in range(9)]
        for square in self.squares3:
            row = square.index // 3
            column = square.index % 3
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares3, self.squares1, self.squares2, self.squares4, self.squares5, self.squares6))

        self.frame4 = tk.Frame(self.boards_frame)
        self.frame4.pack(side="left")

        self.squares4 = [Square(self.frame4, i) for i in range(9)]
        for square in self.squares4:
            row = square.index // 3
            column = square.index % 3
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares4, self.squares1, self.squares2, self.squares3, self.squares5, self.squares6))

        self.frame5 = tk.Frame(self.boards_frame)
        self.frame5.pack(side="left")

        self.squares5 = [Square(self.frame5, i) for i in range(9)]
        for square in self.squares5:
            row = square.index // 3
            column = square.index % 3
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares5, self.squares1, self.squares2, self.squares3, self.squares4, self.squares6))

        self.frame1.pack(side="bottom")
        self.frame2.pack(side="top")
        
        self.frame6 = tk.Frame(self.boards_frame)
        self.frame6.pack(side="left")

        self.squares6 = [Square(self.frame6, i) for i in range(9)]
        for square in self.squares6:
            row = square.index // 3
            column = square.index % 3
            square.grid(row=row, column=column, padx=5, pady=5)
            square.configure(command=lambda arg=square: self.play(arg, self.squares6, self.squares1, self.squares2, self.squares3, self.squares4, self.squares5))

        self.frame3.pack(side="bottom")
        '''
            
        self.message = tk.Label(self, text=' ', width=30)
        self.message.pack(side="bottom")
         
        self.new_game = False
         
        self.player = "X"
        self.reset(self.squares1)
 
    def reset(self, squares1):
        """Reset board to empty"""
        self.open_squares = 54
        self.new_game = False
        for square in squares1:
            square.mark = None
        '''
        for square in squares2:
            square.mark = None
        for square in squares3:
            square.mark = None
        for square in squares4:
            square.mark = None
        for square in squares5:
            square.mark = None
        for square in squares6:
            square.mark = None
        '''
        self.message['text'] = f"{self.player}'s turn"
  
    def play(self, square, squares1):
        """Put player marker in slot if open.  Check for win or tie"""
        if self.new_game:
            return
        if square.mark is not None:
            self.message['text'] = "Invalid move"
            return
        square.mark = self.player
        self.open_squares -= 1
  
        # check for a win
        for win in self.wins:
            if all(squares1[i].mark == self.player for i in win):
                self.message['text'] = f"{self.player} wins!"
                self.new_game = True
                return
            '''
            if all(squares2[i].mark == self.player for i in win):
                self.message['text'] = f"{self.player} wins!"
                self.new_game = True
                return
            if all(squares3[i].mark == self.player for i in win):
                self.message['text'] = f"{self.player} wins!"
                self.new_game = True
                return
            if all(squares4[i].mark == self.player for i in win):
                self.message['text'] = f"{self.player} wins!"
                self.new_game = True
                return
            if all(squares5[i].mark == self.player for i in win):
                self.message['text'] = f"{self.player} wins!"
                self.new_game = True
                return
            if all(squares6[i].mark == self.player for i in win):
                self.message['text'] = f"{self.player} wins!"
                self.new_game = True
                return
            '''
        # check for a tie
        if self.open_squares == 0:
            self.message['text'] = "Tie game"
            self.new_game = True
            return
  
        # switch players
        self.player = "O" if self.player == "X" else "X"
        self.message['text'] = f"{self.player}'s turn"
 
    def game_over(self, squares1):
        """Check for winner or tie"""
        # Check all winning combinations
        for win in self.wins:
            if all(squares1[i].mark == self.player for i in win):
                for i in win:
                    squares1[i]["fg"] = "green"
                self.message["text"] = f"{self.player} wins!"
                return True
            '''
            if all(squares2[i].mark == self.player for i in win):
                for i in win:
                    squares2[i]["fg"] = "green"
                self.message["text"] = f"{self.player} wins!"
                return True
            if all(squares3[i].mark == self.player for i in win):
                for i in win:
                    squares3[i]["fg"] = "green"
                self.message["text"] = f"{self.player} wins!"
                return True
            if all(squares4[i].mark == self.player for i in win):
                for i in win:
                    squares4[i]["fg"] = "green"
                self.message["text"] = f"{self.player} wins!"
                return True
            if all(squares5[i].mark == self.player for i in win):
                for i in win:
                    squares5[i]["fg"] = "green"
                self.message["text"] = f"{self.player} wins!"
                return True
            if all(squares6[i].mark == self.player for i in win):
                for i in win:
                    squares6[i]["fg"] = "green"
                self.message["text"] = f"{self.player} wins!"
                return True
            '''
            
        # Check for a tie
        if self.open_squares <= 0:
            self.message["text"] = "Game ends in a tie"
            return True
 
        return False
 
 
TicTacToe().mainloop()
Reply


Messages In This Thread
Drawing a net of a cube - by freethrownucleus - Mar-25-2023, 02:14 PM
RE: Drawing a net of a cube - by deanhystad - Mar-25-2023, 04:14 PM
RE: Drawing a net of a cube - by freethrownucleus - Mar-25-2023, 04:40 PM
RE: Drawing a net of a cube - by deanhystad - Mar-25-2023, 07:20 PM
RE: Drawing a net of a cube - by freethrownucleus - Mar-26-2023, 10:33 AM
RE: Drawing a net of a cube - by deanhystad - Mar-26-2023, 01:01 PM
RE: Drawing a net of a cube - by freethrownucleus - Mar-27-2023, 08:52 PM
RE: Drawing a net of a cube - by deanhystad - Mar-27-2023, 09:59 PM
RE: Drawing a net of a cube - by freethrownucleus - Mar-27-2023, 11:07 PM
RE: Drawing a net of a cube - by deanhystad - Mar-28-2023, 03:01 AM
RE: Drawing a net of a cube - by freethrownucleus - Mar-28-2023, 10:42 AM
RE: Drawing a net of a cube - by deanhystad - Mar-28-2023, 01:36 PM
RE: Drawing a net of a cube - by freethrownucleus - Mar-28-2023, 01:54 PM
RE: Drawing a net of a cube - by deanhystad - Mar-28-2023, 09:12 PM
RE: Drawing a net of a cube - by freethrownucleus - Apr-27-2023, 10:47 PM
RE: Drawing a net of a cube - by freethrownucleus - Apr-27-2023, 10:51 PM
RE: Drawing a net of a cube - by deanhystad - Apr-28-2023, 02:25 AM
RE: Drawing a net of a cube - by freethrownucleus - Apr-28-2023, 05:36 PM
RE: Drawing a net of a cube - by deanhystad - Apr-28-2023, 11:22 PM
RE: Drawing a net of a cube - by freethrownucleus - Apr-29-2023, 01:30 PM
RE: Drawing a net of a cube - by freethrownucleus - Apr-29-2023, 01:33 PM
RE: Drawing a net of a cube - by freethrownucleus - May-03-2023, 04:40 PM
RE: Drawing a net of a cube - by deanhystad - May-03-2023, 09:18 PM
RE: Drawing a net of a cube - by freethrownucleus - May-03-2023, 09:30 PM
RE: Drawing a net of a cube - by deanhystad - May-04-2023, 04:27 PM
RE: Drawing a net of a cube - by freethrownucleus - May-05-2023, 04:24 PM
RE: Drawing a net of a cube - by freethrownucleus - May-05-2023, 10:23 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Cube drawing freethrownucleus 51 11,021 Apr-12-2023, 08:04 AM
Last Post: ClaytonMorrison
  2D-Cube-Tic-Tac-Toe freethrownucleus 0 1,225 Mar-10-2023, 07:07 PM
Last Post: freethrownucleus
  PyGlet Trouble Drawing Cube. Windspar 3 5,841 Jan-02-2018, 06:37 PM
Last Post: Windspar

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020