1+ from __future__ import annotations
12import itertools
23import numpy
4+ from typing import List , Tuple , Iterable , Optional
35
46X = 1
57O = 2
68
79
810class Board :
9- def __init__ (self , dimensions = (3 , 3 ), x_in_a_row = 3 ) :
11+ def __init__ (self , dimensions : Tuple [ int , ...] = (3 , 3 ), x_in_a_row : int = 3 ) -> None :
1012 self .dimensions = dimensions
1113 self .x_in_a_row = x_in_a_row
1214 self .board = self .create_board ()
1315 self ._directions = self .find_directions ()
1416 self .move_count = 0
15- self .moves = []
16- self .x = []
17- self .o = []
17+ self .moves : List [ Move ] = []
18+ self .x : List [ Move ] = []
19+ self .o : List [ Move ] = []
1820 self .turn = X
1921
20- def create_board (self ):
22+ def create_board (self ) -> numpy . ndarray :
2123 return numpy .zeros (self .dimensions )
2224
23- def copy (self ):
25+ def copy (self ) -> Board :
2426 board = Board (self .dimensions , self .x_in_a_row )
2527 board .turn = self .turn
2628 board .board = self .board .copy ()
2729 return board
2830
29- def get_mark_at_position (self , position ) :
31+ def get_mark_at_position (self , position : Iterable [ int ]) -> int :
3032 position = tuple (position )
3133 return self .board [position ]
3234
33- def set_mark (self , coordinates , player ) :
35+ def set_mark (self , coordinates : Tuple [ int , ...], player : int ) -> None :
3436 self .board [coordinates ] = player
3537 if player == X :
3638 self .x .append (Move (coordinates ))
@@ -40,17 +42,17 @@ def set_mark(self, coordinates, player):
4042 def is_empty (self , position ):
4143 return self .get_mark_at_position (position ) == 0
4244
43- def push (self , coordinates ) :
45+ def push (self , coordinates : Iterable [ int ]) -> None :
4446 coordinates = tuple (coordinates )
4547 if not self .is_empty (coordinates ):
46- raise Exception ("Position is not empty." )
48+ raise ValueError ("Position is not empty." )
4749 move = Move (coordinates )
4850 self .set_mark (coordinates , self .turn )
4951 self .turn = X if self .turn == O else O
5052 self .moves .append (move )
5153 self .move_count += 1
5254
53- def find_directions (self ):
55+ def find_directions (self ) -> List [ Tuple [ int , ...]] :
5456 directions = list (itertools .product ([1 , 0 , - 1 ], repeat = len (self .dimensions )))
5557 correct_directions = []
5658 for direction in directions :
@@ -62,16 +64,16 @@ def find_directions(self):
6264 break
6365 return correct_directions
6466
65- def possible_moves (self ):
67+ def possible_moves (self ) -> numpy . ndarray :
6668 return numpy .argwhere (self .board == 0 )
6769
68- def out_of_bounds (self , pos ) :
70+ def out_of_bounds (self , pos : numpy . ndarray ) -> numpy . bool_ :
6971 return (pos < 0 ).any () or (pos >= self .dimensions ).any ()
7072
71- def in_bounds (self , pos ) :
73+ def in_bounds (self , pos : numpy . ndarray ) -> bool :
7274 return not self .out_of_bounds (pos )
7375
74- def has_won (self , player ) :
76+ def has_won (self , player : int ) -> bool :
7577 positions = numpy .argwhere (self .board == player )
7678 for position in positions :
7779 for direction in self ._directions :
@@ -83,21 +85,22 @@ def has_won(self, player):
8385 return True
8486 return False
8587
86- def result (self ):
88+ def result (self ) -> Optional [ int ] :
8789 if self .has_won (X ):
8890 return X
8991 elif self .has_won (O ):
9092 return O
9193 elif self .board .all ():
9294 return 0
95+ return None
9396
9497
9598class Move :
96- def __init__ (self , coordinate_move = None , str_move = None ):
99+ def __init__ (self , coordinate_move : Optional [ Tuple [ int , ...]] = None , str_move : Optional [ str ] = None ) -> None :
97100 assert coordinate_move or str_move
98101 self .coordinate_move = coordinate_move
99102 self .str_move = str_move
100103 if self .coordinate_move :
101104 self .str_move = "-" .join (map (str , tuple (self .coordinate_move )))
102- else :
105+ elif self . str_move :
103106 self .coordinate_move = tuple (map (int , self .str_move .split ("-" )))
0 commit comments