Skip to content

Commit 98d86cb

Browse files
authored
Merge pull request larymak#366 from Marinel-Neagu/main
Tic Tac Toe Modern looking, full customize.
2 parents d5fd9f2 + c4dcaaa commit 98d86cb

File tree

12 files changed

+1073
-329
lines changed

12 files changed

+1073
-329
lines changed

GAMES/TIC_TAC_TOE/README.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Tic Tac Toe with ttkbootstrap and pygame
2+
3+
Simple and good looking tic tac toe game including sound. The game is only for 2 player, sadly I am not ready
4+
enough to add the AI boot (I don't want to add the random boot :) )
5+
6+
## Description
7+
8+
The game is made only in ttkboostrap and some little pygame for the sound. You can customize this game as you
9+
want. The main thing you can do is to change the color and many things. To see them check the OPTION part.
10+
11+
## Installation
12+
13+
Use the package manager [pip](https://pip.pypa.io/en/stable/) to
14+
install [ttkboostrap](https://ttkbootstrap.readthedocs.io/en/latest/) and the [pygame ](https://www.pygame.org/news)
15+
16+
```bash
17+
pip install ttkboostrap
18+
```
19+
20+
```bash
21+
pip install pygame
22+
```
23+
24+
## Option
25+
26+
The configuration.py file is made in that the information is stored in dictionary/hash-map or like json file.
27+
In this way is very easy to change the color, the font and kind of everthing you want :/ (so be carefull)
28+
29+
## Visual
30+
31+
<img alt="empty" height="200" src="/home/mary/Documents/Marinel_Projects/Apps_GUI/TIC_TAC_TOE/Tic_Tac_Toe.png" width="200"/>
32+
33+
## Contributing
34+
35+
Pull request are wellcome, if you have any advice I am open. If you know to add the AI boot, I will very happy
36+
to add to my code
37+
38+
## License
39+
40+
[GNU GPLv3](https://choosealicense.com/licenses/gpl-3.0/)

GAMES/TIC_TAC_TOE/Tic_Tac_Toe.png

55.1 KB
Loading

GAMES/TIC_TAC_TOE/configuration.py

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# size of the app
2+
3+
MAIN_SIZE: tuple[int, int] = (800, 900)
4+
5+
# Music
6+
MUSIC_PATH: str = 'media/tictacktoe_sound.mp3'
7+
8+
# Layout BoardScore and BoardGame.
9+
BOARD_SIZE: tuple[int, int] = (3, 3)
10+
BOARD_ROW: list[int] = list(range(BOARD_SIZE[0]))
11+
BOARD_COL: list[int] = list(range(BOARD_SIZE[1]))
12+
13+
BOARD_SCORE_SIZE: tuple[int, int] = (9, 2)
14+
15+
# Style and attributes for widgets.
16+
17+
FRAME_STYLE_SCORE: str = 'BoardScore.TFrame'
18+
FRAME_STYLE_GAME: str = 'BoardGame.TFrame'
19+
BUTTON_BOARD_STYLE: str = 'BoardGame.TButton'
20+
BUTTON_RESET_STYLE: str = 'ResetButton.TButton'
21+
LABEL_SCORE_STYLE: str = 'BoardScore.TLabel'
22+
23+
BOARD_GAME = {
24+
'BACKGROUND': '#1F1F1F',
25+
'BACKGROUND_FRAME': '#375a7f',
26+
'BORDER_COLOR': '#375a7f',
27+
'BORDER_THICKNESS': 0,
28+
'BORDER_WIDTH': 0,
29+
'FONT': 'Arial',
30+
'FONT_SIZE': 110,
31+
'HOVER_COLOR_ACTIVE': '#222222',
32+
'HOVER_COLOR_DISABLED': '#222222',
33+
'JUSTIFY': 'center',
34+
'RELIEF': 'raised',
35+
'TEXT_COLOR_ACTIVE': '#E1D9D1',
36+
'TEXT_COLOR_DISABLED': '#E1D9D1',
37+
'PADX': 3,
38+
'PADY': 3
39+
}
40+
BOARD_SCORE = {
41+
# the layout of the board
42+
'COLUMNS': list(range(10)),
43+
'ROWS': list(range(2)),
44+
45+
# the style and config
46+
'BACKGROUND': '#121212',
47+
'BACKGROUND_LABEL': '#303030',
48+
'FONT': 'Helvetica',
49+
'FONT_SIZE': 34,
50+
'TEXT_COLOR': '#E1D9D1',
51+
'PLAYER_1': {
52+
'text': 'Player X',
53+
'row': 0,
54+
'col': 0,
55+
'columnspan': 3,
56+
},
57+
'PLAYER_2': {
58+
'text': 'Player O',
59+
'row': 0,
60+
'col': 6,
61+
'columnspan': 3,
62+
},
63+
'TIE': {
64+
'text': 'TIE ',
65+
'row': 0,
66+
'col': 4,
67+
'columnspan': 2,
68+
},
69+
'RESET_BUTTON': {
70+
'row': 0,
71+
'col': 9,
72+
'columnspan': 3,
73+
'rowspan': 2,
74+
},
75+
'PLAYER_1_SCORE': {
76+
'row': 1,
77+
'column': 0,
78+
'columnspan': 3,
79+
},
80+
'PLAYER_2_SCORE': {
81+
'row': 1,
82+
'column': 6,
83+
'columnspan': 3,
84+
},
85+
}
86+
RESET_BUTTON = {
87+
'BACKGROUND': '#E74C3C',
88+
'BORDER_COLOR': '#222222',
89+
'BORDER_THICKNESS': 10,
90+
'BORDER_WIDTH': 2,
91+
'FONT': 'Helvetica',
92+
'HOVER_COLOR_ACTIVE': '#E74C3C',
93+
'HOVER_COLOR_DISABLED': '#E74C3C',
94+
'JUSTIFY': 'center',
95+
'RELIEF': 'solid',
96+
'SIZE': 34,
97+
'TEXT_COLOR_ACTIVE': '#E1D9D1',
98+
'TEXT_COLOR_DISABLED': '#E1D9D1',
99+
}

GAMES/TIC_TAC_TOE/main.py

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import os
2+
import sys
3+
import ttkbootstrap as ttk
4+
5+
from tkinter import IntVar
6+
from widgets import BoardGame, BoardScore
7+
from configuration import (
8+
# layout
9+
MAIN_SIZE, BOARD_GAME, BOARD_SCORE, RESET_BUTTON,
10+
# style
11+
FRAME_STYLE_SCORE, FRAME_STYLE_GAME, BUTTON_BOARD_STYLE, BUTTON_RESET_STYLE, LABEL_SCORE_STYLE,
12+
)
13+
14+
# import the modules for windows (it works only on windows)
15+
16+
try:
17+
from ctypes import windll, byref, sizeof, c_int
18+
except Exception:
19+
pass
20+
21+
22+
def path_resource(relative_path: str) -> str:
23+
"""
24+
it take the relative path and return the absolute path of the file from your system, is used for making the
25+
app into a exe file for window
26+
27+
"""
28+
try:
29+
base_path: str = sys._MEIPASS
30+
except Exception:
31+
base_path = os.path.abspath('.')
32+
return os.path.join(base_path, relative_path)
33+
34+
35+
class TicTacToe(ttk.Window):
36+
37+
player_1: IntVar
38+
player_2: IntVar
39+
tie_score: IntVar
40+
41+
def __init__(self):
42+
super().__init__()
43+
44+
self.bind('<Alt-s>', lambda event: self.destroy())
45+
self.title('')
46+
self.set_emtpy_icon()
47+
self.set_title_bar_color()
48+
self.set_window_size(width = MAIN_SIZE[0], height = MAIN_SIZE[1])
49+
50+
# set up the style
51+
self.Style = ttk.Style(theme = 'darkly')
52+
53+
# style for the score/ board_score
54+
self.Style.configure(
55+
56+
background = BOARD_SCORE['BACKGROUND'],
57+
style = FRAME_STYLE_SCORE,
58+
59+
)
60+
61+
self.Style.configure(
62+
63+
background = BOARD_GAME['BACKGROUND_FRAME'],
64+
style = FRAME_STYLE_GAME,
65+
66+
)
67+
68+
self.Style.configure(
69+
70+
background = BOARD_GAME['BACKGROUND'],
71+
bordercolor = BOARD_GAME['BORDER_COLOR'],
72+
borderthickness = BOARD_GAME['BORDER_THICKNESS'],
73+
borderwidth = BOARD_GAME['BORDER_WIDTH'],
74+
font = (BOARD_GAME['FONT'], BOARD_GAME['FONT_SIZE']),
75+
justify = BOARD_GAME['JUSTIFY'],
76+
relief = BOARD_GAME['RELIEF'],
77+
style = BUTTON_BOARD_STYLE,
78+
79+
)
80+
81+
self.Style.map(
82+
83+
style = BUTTON_BOARD_STYLE,
84+
foreground = [
85+
('active', BOARD_GAME['TEXT_COLOR_ACTIVE']),
86+
('disabled', BOARD_GAME['TEXT_COLOR_DISABLED'])
87+
],
88+
background = [
89+
('active', BOARD_GAME['HOVER_COLOR_ACTIVE']),
90+
('disabled', BOARD_GAME['HOVER_COLOR_DISABLED'])
91+
]
92+
)
93+
94+
self.Style.configure(
95+
96+
background = RESET_BUTTON['BACKGROUND'],
97+
bordercolor = RESET_BUTTON['BORDER_COLOR'],
98+
borderthickness = RESET_BUTTON['BORDER_THICKNESS'],
99+
borderwidth = RESET_BUTTON['BORDER_WIDTH'],
100+
font = (RESET_BUTTON['FONT'], RESET_BUTTON['SIZE']),
101+
justify = RESET_BUTTON['JUSTIFY'],
102+
relief = RESET_BUTTON['RELIEF'],
103+
style = BUTTON_RESET_STYLE,
104+
105+
)
106+
self.Style.map(
107+
108+
style = BUTTON_RESET_STYLE,
109+
foreground = [
110+
('active', RESET_BUTTON['TEXT_COLOR_ACTIVE']),
111+
('disabled', RESET_BUTTON['TEXT_COLOR_DISABLED'])
112+
],
113+
background = [
114+
('active', RESET_BUTTON['HOVER_COLOR_ACTIVE']),
115+
('disabled', RESET_BUTTON['HOVER_COLOR_DISABLED'])]
116+
117+
)
118+
119+
self.Style.configure(
120+
121+
background = BOARD_SCORE['BACKGROUND'],
122+
font = (BOARD_SCORE['FONT'], BOARD_SCORE['FONT_SIZE']),
123+
foreground = BOARD_SCORE['TEXT_COLOR'],
124+
style = LABEL_SCORE_STYLE,
125+
126+
)
127+
128+
# set player data
129+
self.player_1 = ttk.IntVar(value = 0)
130+
self.player_2 = ttk.IntVar(value = 0)
131+
self.tie_score = ttk.IntVar(value = 0)
132+
133+
# set widgets
134+
self.board_game = BoardGame(
135+
136+
parent = self,
137+
style_cells = BUTTON_BOARD_STYLE,
138+
style_frame = FRAME_STYLE_GAME,
139+
player_1 = self.player_1,
140+
tie = self.tie_score,
141+
player_2 = self.player_2,
142+
143+
)
144+
145+
self.board_score = BoardScore(
146+
147+
parent = self,
148+
style_labels = LABEL_SCORE_STYLE,
149+
style_frame = FRAME_STYLE_SCORE,
150+
style_button = BUTTON_RESET_STYLE,
151+
player_1 = self.player_1,
152+
tie = self.tie_score,
153+
player_2 = self.player_2,
154+
function = self.clean_board
155+
156+
)
157+
158+
# run
159+
self.mainloop()
160+
161+
def clean_board(self):
162+
"""
163+
It clean the board and reset the score
164+
"""
165+
self.board_game.clean_board()
166+
self.player_1.set(0)
167+
self.player_2.set(0)
168+
self.tie_score.set(0)
169+
170+
def set_emtpy_icon(self) -> None:
171+
"""
172+
It sets the icon to one empty from the title bar
173+
174+
"""
175+
try:
176+
path_image: str = path_resource('image/empty.ico')
177+
self.iconbitmap(path_image)
178+
except Exception:
179+
pass
180+
181+
def set_window_size(self, width: int, height: int) -> None:
182+
"""
183+
It adjust the window size to be in the center of the screen
184+
185+
"""
186+
left = int(self.winfo_screenwidth() / 2 - width / 2)
187+
top = int(self.winfo_screenheight() / 2 - height / 2)
188+
self.geometry(f'{width}x{height}+{left}+{top}')
189+
190+
def set_title_bar_color(self) -> None:
191+
"""
192+
It works only on Windows, not on GNU/Linux and macOS.
193+
"""
194+
try:
195+
HWND = windll.user32.GetParent(self.winfo_id())
196+
DWMWA_ATTRIBUTE: int = 35 # target the title bar
197+
color_tile: int = 0x00030303
198+
windll.dwmapi.DwmSetWindowAttribute(HWND, DWMWA_ATTRIBUTE, byref(c_int(color_tile)), sizeof(c_int))
199+
except Exception:
200+
pass
201+
202+
203+
if __name__ == '__main__':
204+
205+
# starts the game
206+
TicTacToe()

GAMES/TIC_TAC_TOE/media/empty.ico

4.19 KB
Binary file not shown.
34.3 KB
Binary file not shown.
66.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)