Posts: 51
Threads: 6
Joined: Dec 2022
Mar-25-2023, 02:14 PM
(This post was last modified: Mar-25-2023, 02:14 PM by freethrownucleus.)
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()
Posts: 6,800
Threads: 20
Joined: Feb 2020
Mar-25-2023, 04:14 PM
(This post was last modified: Mar-25-2023, 04:14 PM by deanhystad.)
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.
Posts: 51
Threads: 6
Joined: Dec 2022
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.
Posts: 6,800
Threads: 20
Joined: Feb 2020
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()
Posts: 51
Threads: 6
Joined: Dec 2022
Mar-26-2023, 10:33 AM
(This post was last modified: Mar-26-2023, 10:36 AM by freethrownucleus.)
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.
Posts: 6,800
Threads: 20
Joined: Feb 2020
Mar-26-2023, 01:01 PM
(This post was last modified: Mar-26-2023, 06:46 PM by deanhystad.)
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.
Posts: 51
Threads: 6
Joined: Dec 2022
Mar-27-2023, 08:52 PM
(This post was last modified: Mar-27-2023, 08:52 PM by freethrownucleus.)
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()
Posts: 6,800
Threads: 20
Joined: Feb 2020
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()
Posts: 51
Threads: 6
Joined: Dec 2022
Mar-27-2023, 11:07 PM
(This post was last modified: Mar-27-2023, 11:07 PM by freethrownucleus.)
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 .
Posts: 6,800
Threads: 20
Joined: Feb 2020
Mar-28-2023, 03:01 AM
(This post was last modified: Mar-28-2023, 03:01 AM by deanhystad.)
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.
|