Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Drawing a net of a cube
#1
I need to draw a net of a cube. Each of squares of a cube will present a tic-tac-toe board.
I tried this but I can do nothing with it (making anything more than a drawing).

If anyone could help ...

import pygame

# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

# Initialize Pygame
pygame.init()

# Set the dimensions of the screen
size = (400, 400)
screen = pygame.display.set_mode(size)

# Load the images for each face of the cube
front = pygame.image.load("cube_model.png").convert()
back = pygame.image.load("cube_model.png").convert()
left = pygame.image.load("cube_model.png").convert()
right = pygame.image.load("cube_model.png").convert()
top = pygame.image.load("cube_model.png").convert()
bottom = pygame.image.load("cube_model.png").convert()

# Create a list of Rect objects for each face of the cube
faces = [
    pygame.Rect(100, 100, 100, 100),
    pygame.Rect(200, 100, 100, 100),
    pygame.Rect(0, 100, 100, 100),
    pygame.Rect(300, 100, 100, 100),
    pygame.Rect(100, 0, 100, 100),
    pygame.Rect(100, 200, 100, 100),
]

# Draw each face of the cube on the screen
screen.blit(front, faces[0])
screen.blit(back, faces[1])
screen.blit(left, faces[2])
screen.blit(right, faces[3])
screen.blit(top, faces[4])
screen.blit(bottom, faces[5])

# Update the screen
pygame.display.flip()

# Wait for the user to close the window
done = False
while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

# Quit Pygame
pygame.quit()
Reply
#2
Squares are places you can place an x or o. A tic-tac-toe board has 9 squares. Your board will have 54 squares.

This would be easier with tkinter using buttons for the squares

If you want to continue with pygame you need a sprite for each square. Using sprites will help detect where the mouse was clicked and you can change the sprite image to blank, x or o. You should start with a 3x3 board to iyon out the details.
Reply
#3
Yes, I need to have 6 boards with 9 places (in general 54 places).
Hmm, maybe it would be easier and better with tkinter but I think I would have the same problem if I used tkinter.
I would only know to draw the net which isn't useful for making the game.
Reply
#4
In tkinter there would be no drawing. This is one of the first programs I wrote in Python.
"""tkinter tic-tac-toe game"""
import tkinter as tk


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', 64, '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),
            (0, 4, 8), (6, 4, 2))

    def __init__(self):
        super().__init__()
        self.title('Tic Tac Toe')
        self.squares = [Square(self, i) for i in range(9)]
        for square in self.squares:
            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.message = tk.Label(self, text=' ', width=30)
        self.message.grid(row=4, column=0, columnspan=3)

        self.new_game = False
        self.player = "X"
        self.reset()

    def reset(self):
        """Reset board to empty"""
        self.open_squares = 9
        self.new_game = False
        for square in self.squares:
            square.mark = None
        self.message['text'] = f"{self.player}'s turn"

    def play(self, square):
        """Put player marker in slot if open.  Check for win or tie"""
        if self.new_game:
            self.reset()
        elif square.mark is not None:
            self.message['text'] = 'That space is already taken'
        else:
            square.mark = self.player
            self.open_squares -= 1
            self.new_game = self.game_over()
            self.player = "X" if self.player == "O" else "O"
            if not self.new_game:
                self.message['text'] = f"{self.player}'s turn"

    def game_over(self):
        '''Check for winner or tie'''
        # Check all winning combinations
        for win in self.wins:
            if all(self.player == self.squares[i].mark for i in win):
                for i in win:
                    self.squares[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
#5
Nice game but you didn't understand me well.
I need this shape for my game. Something like a cross of 6 squares and each square contains a tic-tac-toe board:
https://mega.nz/file/zNgRlRoJ#vXbnAswpwA...4auU_Vsq5o .

That's why I tried pygame at first.
Reply
#6
I understand you just fine. I provided an example of how to write a tic-tac-toe game using the grid layout in tkinter. It has 9 squares. Repeat 5 more times, adjusting the row and column values in the .grid() layout calls.
"""tkinter tic-tac-toe game"""
import tkinter as tk
import tkinter.ttk as ttk
from functools import partial


class Square(ttk.Button):
    """Special button for playing tic-tac-toe."""
    styles = {"X": "X.TButton", "O": "O.TButton", None: "X.TButton"}

    def __init__(self, parent, board, index):
        super().__init__(parent, width=3, style='X.TButton')
        self.board = board
        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.configure(style=self.styles[mark])
        self["text"] = '' if mark is None else mark


class Board(tk.Frame):
    """A tic-tac-toe board."""
    wins = ((0, 1, 2), (3, 4, 5), (6, 7, 8),
            (0, 3, 6), (1, 4, 7), (2, 5, 8),
            (0, 4, 8), (6, 4, 2))

    def __init__(self, parent, bg="black"):
        super().__init__(parent, bg=bg)
        self.squares = [Square(self, self, i) for i in range(9)]
        for s in self.squares:
            r = s.index // 3
            c = s.index % 3
            s.grid(row=r, column=c, padx=2, pady=2)
        self.new_game = False
        self.open_squares = 9

    def reset(self):
        """Reset board to empty"""
        self.open_squares = 9
        self.new_game = False
        for square in self.squares:
            square.mark = None

    def play(self, square, player):
        """Put player marker in slot if open.  Check for win or tie"""
        square.mark = player
        self.open_squares -= 1
        self.game_over(player)

    def game_over(self, player):
        '''Check for winner or tie'''
        # Check all winning combinations
        for win in self.wins:
            if all(player == self.squares[i].mark for i in win):
                for i in win:
                    self.squares[i].configure(style="win.TButton")
                self.new_game = True
                break
        else:
            self.new_game = self.open_squares <= 0


class TicTacToe(tk.Tk):
    """Multi-board tic-tac-toe game."""
    def __init__(self):
        super().__init__()
        # Define styles used by squares.
        style = ttk.Style(self)
        style.configure('X.TButton', padding=-10, font=('Comic Sans MS', 32, 'bold'), foreground="red")
        style.configure('O.TButton', padding=-10, font=('Comic Sans MS', 32, 'bold'), foreground="blue")
        style.configure('win.TButton', padding=-10, font=('Comic Sans MS', 32, 'bold'), foreground="green")
        self.title('Tic Tac Toe')
        self.player = "X"

        # Make the tic-tac-toe boards.  Bind squares command to self.play
        frame = tk.Frame(self, bg="black")
        frame.pack(side=tk.TOP)
        self.boards = [Board(frame, color) for color in ('red', 'green', 'blue')]
        for index, board in enumerate(self.boards):
            for square in board.squares:
                square.configure(command=partial(self.play, square))
            board.grid(row=index, column=index)

        self.message = tk.Label(self, text=f"{self.player}'s turn", font=("Comic Sans MS", 20))
        self.message.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)

    def play(self, square):
        """Put player mark in square if open"""
        if square.board.new_game:
            square.board.reset()
        elif square.mark is None:
            square.board.play(square, self.player)
            self.player = "X" if self.player == "O" else "O"
            self.message['text'] = f"{self.player}'s turn"


TicTacToe().mainloop()
You don't expect somebody to write all the code do you?

You can write the game in pygame, as you have already done with a different layout. It is just more difficult. Unlike tkinter you have to do all the layout and monitor for button clicks. The only advantage I can see to pygame is you have total control over the presentation. But total control also means you have to write all the code that updates the screen.
Reply
#7
No, I don't expect anyone to write the whole code ...
I just ask what I have problem with or don't understand.

I don't get exactly what you did with the new code.

I think I managed to modify your first code to get what I wanted.



But how can I modify the code in this case so I can set the winning combinations over all 6 boards, not over each for itself?




import tkinter as tk
 
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),
            (0, 4, 8), (6, 4, 2))
  
    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 = [Square(self.frame1, i) for i in range(9)]
        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.squares2, self.squares3, self.squares4, self.squares5, self.squares6))
         
        # 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, self.squares3, self.squares4, self.squares5, self.squares6))
         
        # 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.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.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.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, self.squares2, self.squares3, self.squares4, self.squares5, self.squares6)
 
    def reset(self, squares1, squares2, squares3, squares4, squares5, squares6):
        """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, squares2, squares3, squares4, squares5, squares6):
        """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, squares2, squares3, squares4, squares5, squares6):
        """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()
I tried next logic: not drawing 6 boards, but drawing all the squares together but I can't get the shape I need.

import tkinter as tk
 
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),
            (0, 4, 8), (6, 4, 2), (4, 8, 12, 22))
  
    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="top")
        
        self.squares1 = [Square(self.frame1, i) for i in range(54)]
        for square in self.squares1:
            if square.index >= 9 and square.index <= 17:
                row = 3
                column = square.index % 9
            elif square.index >= 18 and square.index <= 26:
                row = 4
                column = square.index % 9
            elif square.index >= 27 and square.index <= 35:
                row = 5
                column = square.index % 9
            else:
                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))


        '''
        # 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 = 18
        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
#8
You should not have squares1, squares2...squares6. You should have squares[] (or preferrably boards[]). If you have two things that are similar you should put them in a list or tuple. If you have 6 things that are similar you should most definitely put them in a list or tuple. Do not use individual attributes when you can make a collection.

You only ever have to check for winning combinations involving the last square played. That means you only have to check for a win on the board that contains the last square played. If you want to reset all boards after there is a winner on any board, the logic, and code, might actually be simpler.
"""tkinter tic-tac-toe game"""
import tkinter as tk
import tkinter.ttk as ttk
from functools import partial


class Square(ttk.Button):
    """Special button for playing tic-tac-toe."""

    styles = {"X": "X.TButton", "O": "O.TButton", None: "X.TButton"}

    def __init__(self, parent, board, index):
        super().__init__(parent, width=3, style="X.TButton")
        self.board = board
        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.configure(style=self.styles[mark])
        self["text"] = "" if mark is None else mark


class Board(tk.Frame):
    """A tic-tac-toe board."""

    wins = (
        (0, 1, 2),
        (3, 4, 5),
        (6, 7, 8),
        (0, 3, 6),
        (1, 4, 7),
        (2, 5, 8),
        (0, 4, 8),
        (6, 4, 2),
    )

    def __init__(self, parent, bg="black"):
        super().__init__(parent, bg=bg)
        self.squares = [Square(self, self, i) for i in range(9)]
        for s in self.squares:
            r = s.index // 3
            c = s.index % 3
            s.grid(row=r, column=c, padx=2, pady=2)
        self.new_game = False

    def reset(self):
        """Reset board to empty"""
        self.new_game = False
        for square in self.squares:
            square.mark = None

    def play(self, square, player):
        """Put player marker in slot if open.  Check for win or tie"""
        square.mark = player
        for win in self.wins:
            if all(player == self.squares[i].mark for i in win):
                for i in win:
                    self.squares[i].configure(style="win.TButton")
                self.new_game = True
                break


class TicTacToe(tk.Tk):
    """Multi-board tic-tac-toe game."""

    def __init__(self):
        super().__init__()
        # Define styles used by squares.
        style = ttk.Style(self)
        style.configure(
            "X.TButton",
            padding=-10,
            font=("Comic Sans MS", 32, "bold"),
            foreground="red",
        )
        style.configure(
            "O.TButton",
            padding=-10,
            font=("Comic Sans MS", 32, "bold"),
            foreground="blue",
        )
        style.configure(
            "win.TButton",
            padding=-10,
            font=("Comic Sans MS", 32, "bold"),
            foreground="green",
        )
        self.title("Tic Tac Toe")
        self.player = "X"
        self.new_game = False
        self.open_squares = 0

        # Make the tic-tac-toe boards.
        frame = tk.Frame(self, bg="black")
        frame.pack(side=tk.TOP)
        self.boards = [
            Board(frame, color)
            for color in ("red", "green", "blue", "orange", "yellow")
        ]
        # Bind squares to call self.play()
        for board in self.boards:
            for square in board.squares:
                square.configure(command=partial(self.play, square))

        # Arrange the boards in the grid
        self.boards[0].grid(row=0, column=0)
        self.boards[1].grid(row=0, column=2)
        self.boards[2].grid(row=1, column=1)
        self.boards[3].grid(row=2, column=0)
        self.boards[4].grid(row=2, column=2)

        self.message = tk.Label(
            self, text=f"{self.player}'s turn", font=("Comic Sans MS", 20)
        )
        self.message.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)

        self.reset()

    def play(self, square):
        """Put player mark in square if open"""
        board = square.board
        if self.new_game:
            self.reset()
        elif square.mark is None:
            board.play(square, self.player)
            self.open_squares -= 1
            self.new_game = board.new_game or self.open_squares <= 0
            self.player = "X" if self.player == "O" else "O"
            self.message["text"] = f"{self.player}'s turn"

    def reset(self):
        """Reset all the boards"""
        for board in self.boards:
            board.reset()
        self.new_game = False
        self.open_squares = len(self.boards) * 9


TicTacToe().mainloop()
Reply
#9
I don't know if you understand me well, sorry. This is what I meant by combining more boards (2 or even more) for winning combinations: https://mega.nz/file/uJw0VBRR#vbKjX5l_cK...2Nso9H2rlM .

That's why I tried drawing all 54 squares at once as you can see in my last reply (I believe I could easily add borders if I wanted those 6 boards separately).
These 3 boards that are horizontal: I treat them as 3 rows in the for loop (rows 3, 4 and 5 (index)). But I can't get the shape that I want. The best I got is this: https://mega.nz/file/XVhyhY7I#PDp0KtlqMr...njY1o1UbRM .

Firstly I saw the old version of the code that you sent so I tried to modify that one in the beginning.

For the new version of the code, I only understand the part with a list or tuple.


EDIT: Okay I think I got it (the idea with all 54 squares at once). If you think of some flaws here, feel free to say!


import tkinter as tk
 
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),
            (0, 4, 8), (6, 4, 2), (4, 8, 27, 31)) #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.frame2.pack(side="bottom")
        
        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.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 = 18
        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()
According to this code, the last winning combo will be this one (randomly chosen, just wanted to make a win over 2 or more boards possible): https://mega.nz/file/nZhUABAI#S-NVm_a_Tc...tAqDb6QS6A .
Reply
#10
This is a different approach. It uses a map to define the board. Kind of like using a map to lay out tiles in pygame.
"""tkinter tic-tac-toe game"""
import tkinter as tk
import tkinter.ttk as ttk
from functools import partial


def find_wins(map_):
    """Compute 3 in a row combinations in map_."""

    def combo(row, column, irow, icolumn, length=3):
        """Return index list of winning combination starting at row, column
        and advancing in irow, icolumn direction.  Return None if streak of
        consecutive squares is less than "length" long.
        """
        try:
            combo = [grid[row+irow*x][column+icolumn*x] for x in range(length)]
            if None not in combo:
                return combo
        except IndexError:
            pass
        return None

    columns = max(len(row) for row in map_)
    grid = [[None] * columns for _ in map_]

    index = 0
    for r, row in enumerate(map_):
        for c, key in enumerate(row):
            if key == "S":
                grid[r][c] = index
                index += 1

    wins = []
    for r, row in enumerate(map_):
        for c, key in enumerate(row):
            for irow, icolumn in ((1, 0), (-1, 1), (0, 1), (1, 1)):
                if win := combo(r, c, irow, icolumn):
                    wins.append(win)
    return wins


class Square(ttk.Button):
    """Special button for playing tic-tac-toe."""

    styles = {"X": "X.TButton", "O": "O.TButton", None: "X.TButton"}
 
    def __init__(self, parent, index):
        super().__init__(parent, width=3, style="X.TButton")
        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.configure(style=self.styles[mark])
        self["text"] = "" if mark is None else mark


class Board(tk.Frame):
    """A funky TicTacToe board.  Use map to make any shape you want."""
    def __init__(self, map_, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.squares = []
        for r, row in enumerate(map_):
            for c, key in enumerate(row):
                if key == "S":
                    square = Square(self, len(self.squares))
                    square.grid(row=r, column=c)
                    self.squares.append(square)
        # Convert win combos from numbers to squares
        self.wins = [[self.squares[i] for i in win] for win in find_wins(map_)]

    def play(self, square, player):
        """Put player marker in slot.  Check for win"""
        square.mark = player
        for win in self.wins:
            if square in win and all(player == s.mark for s in win):
                for s in win:
                    s.configure(style="win.TButton")
                self.new_game = True
                break

    def reset(self):
        """Reset board to empty"""
        self.new_game = False
        for square in self.squares:
            square.mark = None


class TicTacToe(tk.Tk):
    """A funky TicTacToe game.  Use map to make any shape board you want."""

    def __init__(self, map_):
        super().__init__()
        # Define styles used by squares.
        style = ttk.Style(self)
        style.configure(
            "X.TButton",
            padding=-10,
            font=("Comic Sans MS", 32, "bold"),
            foreground="red",
        )
        style.configure(
            "O.TButton",
            padding=-10,
            font=("Comic Sans MS", 32, "bold"),
            foreground="blue",
        )
        style.configure(
            "win.TButton",
            padding=-10,
            font=("Comic Sans MS", 32, "bold"),
            foreground="green",
        )
        self.title("Tic Tac Toe")
        self.player = "X"
        self.open_squares = 0

        self.board = Board(map_, self)
        for square in self.board.squares:
            square.configure(command=partial(self.play, square))
        self.board.pack(side=tk.TOP)

        self.message = tk.Label(
            self, text=f"{self.player}'s turn", font=("Comic Sans MS", 20)
        )
        self.message.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
        self.reset()

    def play(self, square):
        """Put player mark in square if open"""
        if self.new_game:
            self.reset()
        elif square.mark is None:
            self.board.play(square, self.player)
            self.open_squares -= 1
            self.new_game = self.board.new_game or self.open_squares <= 0
            self.player = "X" if self.player == "O" else "O"
            self.message["text"] = f"{self.player}'s turn"

    def reset(self):
        """Reset all the boards"""
        self.board.reset()
        self.new_game = False
        self.open_squares = len(self.board.squares)


board = ("BSSSBSSSB", "SSSSSSSSS", "BSSSBSSSB")  # B = Blank, S = Square

TicTacToe(board).mainloop()
Other than the way the squares get placed in the grid, the code is very similar to a 3x3 tic-tac-toe game.

On your 54 square board there are going to be many winning combinations. Using a map, you can write a function to find all the winning combinations instead of doing it by hand. With all the combinations you might need to make to modify the rules to require 4 consecutive marks to win to have the game be challenging.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Cube drawing freethrownucleus 51 9,936 Apr-12-2023, 08:04 AM
Last Post: ClaytonMorrison
  2D-Cube-Tic-Tac-Toe freethrownucleus 0 1,159 Mar-10-2023, 07:07 PM
Last Post: freethrownucleus
  PyGlet Trouble Drawing Cube. Windspar 3 5,745 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