Skip to content

Commit 82a1489

Browse files
committed
add tictactoe game tutorial
1 parent f8eb700 commit 82a1489

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -271,5 +271,6 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
271271
- [How to Make a Real-Time GUI Spelling Checker in Python](https://www.thepythoncode.com/article/make-a-realtime-spelling-checker-gui-python). ([code](gui-programming/realtime-spelling-checker))
272272
- [How to Create a GUI Hangman Game using PyGame in Python](https://www.thepythoncode.com/article/hangman-gui-game-with-pygame-in-python). ([code](gui-programming/hangman-game-gui))
273273
- [How to Make a Tetris Game using PyGame in Python](https://www.thepythoncode.com/article/create-a-tetris-game-with-pygame-in-python). ([code](gui-programming/tetris-game))
274+
- [How to Build a Tic Tac Toe Game in Python](https://www.thepythoncode.com/article/make-a-tic-tac-toe-game-pygame-in-python). ([code](gui-programmming/tictactoe-game))
274275

275276
For any feedback, please consider pulling requests.
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [How to Build a Tic Tac Toe Game in Python](https://www.thepythoncode.com/article/make-a-tic-tac-toe-game-pygame-in-python)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pygame
+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import pygame
2+
from pygame.locals import *
3+
4+
pygame.init()
5+
pygame.font.init()
6+
7+
window_size = (450, 500)
8+
9+
screen = pygame.display.set_mode(window_size)
10+
pygame.display.set_caption("Tic Tac Toe")
11+
12+
13+
class TicTacToe():
14+
15+
def __init__(self, table_size):
16+
self.table_size = table_size
17+
self.cell_size = table_size // 3
18+
self.table_space = 20
19+
20+
self.player = "X"
21+
self.winner = None
22+
self.taking_move = True
23+
self.running = True
24+
self.table = []
25+
for col in range(3):
26+
self.table.append([])
27+
for row in range(3):
28+
self.table[col].append("-")
29+
30+
self.background_color = (255, 174, 66)
31+
self.table_color = (50, 50, 50)
32+
self.line_color = (190, 0, 10)
33+
self.instructions_color = (17, 53, 165)
34+
self.game_over_bg_color = (47, 98, 162)
35+
self.game_over_color = (255, 179, 1)
36+
self.font = pygame.font.SysFont("Courier New", 35)
37+
self.FPS = pygame.time.Clock()
38+
39+
40+
# draws table representation
41+
def _draw_table(self):
42+
tb_space_point = (self.table_space, self.table_size - self.table_space)
43+
cell_space_point = (self.cell_size, self.cell_size * 2)
44+
r1 = pygame.draw.line(screen, self.table_color, [tb_space_point[0], cell_space_point[0]], [tb_space_point[1], cell_space_point[0]], 8)
45+
c1 = pygame.draw.line(screen, self.table_color, [cell_space_point[0], tb_space_point[0]], [cell_space_point[0], tb_space_point[1]], 8)
46+
r2 = pygame.draw.line(screen, self.table_color, [tb_space_point[0], cell_space_point[1]], [tb_space_point[1], cell_space_point[1]], 8)
47+
c2 = pygame.draw.line(screen, self.table_color, [cell_space_point[1], tb_space_point[0]], [cell_space_point[1], tb_space_point[1]], 8)
48+
49+
50+
def _change_player(self):
51+
self.player = "O" if self.player == "X" else "X"
52+
53+
54+
# processing clicks to move
55+
def _move(self, pos):
56+
try:
57+
x, y = pos[0] // self.cell_size, pos[1] // self.cell_size
58+
if self.table[x][y] == "-":
59+
self.table[x][y] = self.player
60+
self._draw_char(x,y,self.player)
61+
self._game_check()
62+
self._change_player()
63+
except:
64+
print("Click inside the table only")
65+
66+
67+
# draws character of the recent player to the selected table cell
68+
def _draw_char(self, x, y, player):
69+
if self.player == "O":
70+
img = pygame.image.load("images/Tc-O.png")
71+
elif self.player == "X":
72+
img = pygame.image.load("images/Tc-X.png")
73+
img = pygame.transform.scale(img, (self.cell_size, self.cell_size))
74+
screen.blit(img, (x * self.cell_size, y * self.cell_size, self.cell_size, self.cell_size))
75+
76+
77+
# instructions and game-state messages
78+
def _message(self):
79+
if self.winner is not None:
80+
screen.fill(self.game_over_bg_color, (130, 445, 193, 35))
81+
msg = self.font.render(f'{self.winner} WINS!!', True, self.game_over_color)
82+
screen.blit(msg,(144,445))
83+
elif not self.taking_move:
84+
screen.fill(self.game_over_bg_color, (130, 445, 193, 35))
85+
instructions = self.font.render('DRAW!!', True, self.game_over_color)
86+
screen.blit(instructions,(165,445))
87+
else:
88+
screen.fill(self.background_color, (135, 445, 188, 35))
89+
instructions = self.font.render(f'{self.player} to move', True, self.instructions_color)
90+
screen.blit(instructions,(135,445))
91+
92+
93+
def _game_check(self):
94+
# vertical check
95+
for x_index, col in enumerate(self.table):
96+
win = True
97+
pattern_list = []
98+
for y_index, content in enumerate(col):
99+
if content != self.player:
100+
win = False
101+
break
102+
else:
103+
pattern_list.append((x_index, y_index))
104+
if win == True:
105+
self._pattern_strike(pattern_list[0],pattern_list[-1],"ver")
106+
self.winner = self.player
107+
self.taking_move = False
108+
break
109+
110+
# horizontal check
111+
for row in range(len(self.table)):
112+
win = True
113+
pattern_list = []
114+
for col in range(len(self.table)):
115+
if self.table[col][row] != self.player:
116+
win = False
117+
break
118+
else:
119+
pattern_list.append((col, row))
120+
if win == True:
121+
self._pattern_strike(pattern_list[0],pattern_list[-1],"hor")
122+
self.winner = self.player
123+
self.taking_move = False
124+
break
125+
126+
# left diagonal check
127+
for index, row in enumerate(self.table):
128+
win = True
129+
if row[index] != self.player:
130+
win = False
131+
break
132+
if win == True:
133+
self._pattern_strike((0,0),(2,2),"left-diag")
134+
self.winner = self.player
135+
self.taking_move = False
136+
137+
# right diagonal check
138+
for index, row in enumerate(self.table[::-1]):
139+
win = True
140+
if row[index] != self.player:
141+
win = False
142+
break
143+
if win == True:
144+
self._pattern_strike((2,0),(0,2),"right-diag")
145+
self.winner = self.player
146+
self.taking_move = False
147+
148+
# blank table cells check
149+
blank_cells = 0
150+
for row in self.table:
151+
for cell in row:
152+
if cell == "-":
153+
blank_cells += 1
154+
if blank_cells == 0:
155+
self.taking_move = False
156+
157+
158+
# strikes a line to winning patterns if already has
159+
def _pattern_strike(self, start_point, end_point, line_type):
160+
# gets the middle value of the cell
161+
mid_val = self.cell_size // 2
162+
163+
# for the vertical winning pattern
164+
if line_type == "ver":
165+
start_x, start_y = start_point[0] * self.cell_size + mid_val, self.table_space
166+
end_x, end_y = end_point[0] * self.cell_size + mid_val, self.table_size - self.table_space
167+
168+
# for the horizontal winning pattern
169+
elif line_type == "hor":
170+
start_x, start_y = self.table_space, start_point[-1] * self.cell_size + mid_val
171+
end_x, end_y = self.table_size - self.table_space, end_point[-1] * self.cell_size + mid_val
172+
173+
# for the diagonal winning pattern from top-left to bottom right
174+
elif line_type == "left-diag":
175+
start_x, start_y = self.table_space, self.table_space
176+
end_x, end_y = self.table_size - self.table_space, self.table_size - self.table_space
177+
178+
# for the diagonal winning pattern from top-right to bottom-left
179+
elif line_type == "right-diag":
180+
start_x, start_y = self.table_size - self.table_space, self.table_space
181+
end_x, end_y = self.table_space, self.table_size - self.table_space
182+
183+
# draws the line strike
184+
line_strike = pygame.draw.line(screen, self.line_color, [start_x, start_y], [end_x, end_y], 8)
185+
186+
187+
def main(self):
188+
screen.fill(self.background_color)
189+
self._draw_table()
190+
while self.running:
191+
self._message()
192+
for self.event in pygame.event.get():
193+
if self.event.type == pygame.QUIT:
194+
self.running = False
195+
196+
if self.event.type == pygame.MOUSEBUTTONDOWN:
197+
if self.taking_move:
198+
self._move(self.event.pos)
199+
200+
pygame.display.flip()
201+
self.FPS.tick(60)
202+
203+
204+
if __name__ == "__main__":
205+
g = TicTacToe(window_size[0])
206+
g.main()

0 commit comments

Comments
 (0)