Skip to content

Instantly share code, notes, and snippets.

@itarato
Created August 19, 2015 06:25
Show Gist options
  • Select an option

  • Save itarato/aca4b3105f5c317d48a2 to your computer and use it in GitHub Desktop.

Select an option

Save itarato/aca4b3105f5c317d48a2 to your computer and use it in GitHub Desktop.
2 player (human + AI) Tic Tac Toe using Minimax
class Player():
def __init__(self): pass
def move(self, player_bit, game_map, evaluator): pass
class STDIOPlayer(Player):
def move(self, player_bit, game_map, evaluator):
idx = input('Your step (0-9): ')
game_map[int(idx)] = player_bit
class MinimaxPlayer(Player):
def move(self, player_bit, game_map, evaluator):
availables = self.get_availables(game_map)
max_score = -2
max_index = -1
for idx in availables:
new_game_map = game_map[:]
new_game_map[idx] = player_bit
score = self.get_score(player_bit, not player_bit, new_game_map, evaluator)
if score > max_score:
max_score = score
max_index = idx
game_map[max_index] = player_bit
def get_availables(self, game_map):
return filter(lambda x: x is not None, [idx if game_map[idx] is None else None for idx in range(len(game_map))])
def get_score(self, player_me_bit, player_next_bit, game_map, evaluator):
leaf_score = evaluator.check_win(game_map)
if leaf_score.left:
return 1 if player_me_bit else -1
if leaf_score.right:
return -1 if player_me_bit else 1
if leaf_score.drawn:
return 0
availables = self.get_availables(game_map)
if player_next_bit == player_me_bit: # Max.
curr_score = -2
for idx in availables:
new_game_map = game_map[:]
new_game_map[idx] = player_next_bit
score = self.get_score(player_me_bit, not player_next_bit, new_game_map, evaluator)
if curr_score < score:
curr_score = score
else: # Min.
curr_score = 2
for idx in availables:
new_game_map = game_map[:]
new_game_map[idx] = player_next_bit
score = self.get_score(player_me_bit, not player_next_bit, new_game_map, evaluator)
if curr_score > score:
curr_score = score
return curr_score
class GameFlow():
def __init__(self, game_map, player_left, player_right, evaluator):
self.evaluator = evaluator
self.player_left = player_left
self.player_right = player_right
self.map = game_map
self.current_player_left = True
self.result = WinResult()
def move(self):
if self.current_player_left:
self.player_left.move(self.current_player_left, self.map, self.evaluator)
else:
self.player_right.move(self.current_player_left, self.map, self.evaluator)
self.current_player_left = not self.current_player_left
self.result = self.evaluator.check_win(self.map)
print_map(self.map)
class Evaluator():
def __init__(self):
pass
def check_win(self, game_map):
for i in range(3):
if self.check_sequence(game_map, i * 3, 1) is not None:
return WinResult(winner=game_map[i * 3])
if self.check_sequence(game_map, i, 3) is not None:
return WinResult(winner=game_map[i])
if self.check_sequence(game_map, 0, 4) is not None:
return WinResult(winner=game_map[0])
if self.check_sequence(game_map, 2, 2) is not None:
return WinResult(winner=game_map[2])
if len(filter(lambda x: x is None, game_map)) == 0:
return WinResult(drawn=True)
return WinResult()
def check_sequence(self, game_map, from_idx=0, offset=1):
if game_map[from_idx] == game_map[from_idx + offset] == game_map[from_idx + offset * 2]:
return game_map[from_idx]
return None
class WinResult():
def __init__(self, winner=None, drawn=False):
self.left = winner is True
self.right = winner is False
self.drawn = drawn
def is_over(self):
return self.left or self.right or self.drawn
def print_map(map):
for j in range(3):
for i in range(3):
cell = map[j * 3 + i]
if cell is True:
print('O'),
elif cell is False:
print('X'),
else:
print('_'),
print('')
print('\n\n')
if __name__ == '__main__':
pl = MinimaxPlayer()
pr = STDIOPlayer()
m = [None] * 9
ev = Evaluator()
gf = GameFlow(m, pl, pr, ev)
while not gf.result.is_over():
gf.move()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment