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