2727clock = pygame .time .Clock ()
2828
2929# ── Fonts ─────────────────────────────────────────────────
30- def sf (size , bold = False ):
30+ from typing import Optional , Tuple , List , Any
31+
32+ def sf (size : int , bold : bool = False ) -> pygame .font .Font :
33+ """Create a sans-serif font."""
3134 for n in ["Segoe UI" , "Helvetica Neue" , "Arial" , "DejaVu Sans" ]:
3235 try : return pygame .font .SysFont (n , size , bold = bold )
3336 except : pass
3437 return pygame .font .Font (None , size )
3538
36- def mf (size , bold = False ):
39+ def mf (size : int , bold : bool = False ) -> pygame .font .Font :
40+ """Create a monospace font."""
3741 for n in ["Consolas" , "Courier New" , "DejaVu Sans Mono" ]:
3842 try : return pygame .font .SysFont (n , size , bold = bold )
3943 except : pass
@@ -61,7 +65,8 @@ def mf(size, bold=False):
6165BX = (W - (3 * CELL + 2 * GAP )) // 2 # board left edge = 43
6266BY = 270 # board top edge
6367
64- def cell_rect (i ):
68+ def cell_rect (i : int ) -> pygame .Rect :
69+ """Get the rectangle for a given cell index."""
6570 r , c = divmod (i , 3 )
6671 return pygame .Rect (BX + c * (CELL + GAP ), BY + r * (CELL + GAP ), CELL , CELL )
6772
@@ -79,24 +84,28 @@ def cell_rect(i):
7984BTN2 = pygame .Rect ((W // 2 ) + 12 , BTN_Y , BW , BH )
8085
8186# ── Helpers ───────────────────────────────────────────────
82- def rrect (surf , color , rect , r = 14 , bw = 0 , bc = None ):
87+ def rrect (surf : pygame .Surface , color : Tuple [int , int , int ], rect : pygame .Rect , r : int = 14 , bw : int = 0 , bc : Optional [Tuple [int , int , int ]] = None ) -> None :
88+ """Draw a rounded rectangle."""
8389 pygame .draw .rect (surf , color , rect , border_radius = r )
8490 if bw and bc :
8591 pygame .draw .rect (surf , bc , rect , bw , border_radius = r )
8692
87- def tc (surf , txt , font , color , cx , cy ):
93+ def tc (surf : pygame .Surface , txt : str , font : pygame .font .Font , color : Tuple [int , int , int ], cx : int , cy : int ) -> None :
94+ """Draw centered text."""
8895 s = font .render (txt , True , color )
8996 surf .blit (s , (cx - s .get_width ()// 2 , cy - s .get_height ()// 2 ))
9097
91- def check_winner ():
98+ def check_winner () -> Tuple [Optional [str ], Optional [List [int ]]]:
99+ """Check if there is a winner and return the winner and winning combination."""
92100 for a ,b ,c in WINS :
93101 if board [a ] and board [a ]== board [b ]== board [c ]:
94102 return board [a ], [a ,b ,c ]
95103 if "" not in board :
96104 return "D" , []
97105 return None , None
98106
99- def play (i ):
107+ def play (i : int ) -> None :
108+ """Make a move at the given index."""
100109 global current , game_over
101110 if game_over or board [i ]: return
102111 board [i ] = current
@@ -108,11 +117,13 @@ def play(i):
108117 else :
109118 current = "O" if current == "X" else "X"
110119
111- def new_game ():
120+ def new_game () -> None :
121+ """Start a new game."""
112122 global board , current , game_over
113123 board = ["" ] * 9 ; current = "X" ; game_over = False
114124
115- def reset_all ():
125+ def reset_all () -> None :
126+ """Reset the game scores and start a new game."""
116127 scores ["X" ] = scores ["O" ] = scores ["D" ] = 0
117128 new_game ()
118129
0 commit comments