Skip to content

Commit c42ad4b

Browse files
committed
Added Tic Tac Toe program, but using MINIMAX Algorithm
1 parent f3dabfe commit c42ad4b

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

Player.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import math
2+
import random
3+
4+
5+
class Player():
6+
def __init__(self, player):
7+
self.player = player
8+
9+
def get_move(self, game):
10+
pass
11+
12+
13+
class Human(Player):
14+
def __init__(self, player):
15+
super().__init__(player)
16+
17+
def get_move(self, game):
18+
valid_square = False
19+
val = None
20+
while not valid_square:
21+
square = input(self.player + ' turn. Please introduce a move (1-9): ')
22+
try:
23+
val = int(square) - 1
24+
if val not in game.remaining_moves():
25+
raise ValueError
26+
valid_square = True
27+
except ValueError:
28+
print('Invalid square. Try again.')
29+
return val
30+
31+
32+
class RandomComputer(Player):
33+
def __init__(self, player):
34+
super().__init__(player)
35+
36+
def get_move(self, game):
37+
square = random.choice(game.remaining_moves())
38+
return square
39+
40+
41+
class SmartComputer(Player):
42+
def __init__(self, player):
43+
super().__init__(player)
44+
45+
def get_move(self, game):
46+
if len(game.remaining_moves()) == 9:
47+
square = random.choice(game.remaining_moves())
48+
else:
49+
square = self.minimax(game, self.player)['position']
50+
return square
51+
52+
def minimax(self, state, player):
53+
max_player = self.player
54+
min_player = '0' if player == 'X' else 'X'
55+
56+
# checking if the previous move is winner
57+
if state.actual_winner == min_player:
58+
return {'position': None,
59+
'score': 1 * (state.number_null_squares() + 1) if min_player == max_player
60+
else -1 * (state.number_null_squares() + 1)}
61+
elif not state.null_squares():
62+
return {'position': None, 'score': 0}
63+
64+
if player == max_player:
65+
best = {'position': None, 'score': -math.inf}
66+
else:
67+
best = {'position': None, 'score': math.inf}
68+
69+
for possible_move in state.remaining_moves():
70+
state.make_a_move(possible_move, player)
71+
sim_score = self.minimax(state, min_player)
72+
73+
# undo move
74+
state.board[possible_move] = ' '
75+
state.actual_winner = None
76+
sim_score['position'] = possible_move
77+
78+
if player == max_player:
79+
if sim_score['score'] > best['score']:
80+
best = sim_score
81+
else:
82+
if sim_score['score'] < best['score']:
83+
best = sim_score
84+
return best

TicTacToe.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import math
2+
import time
3+
from Player import SmartComputer, RandomComputer, Human
4+
5+
6+
class TicTacToe():
7+
def __init__(self):
8+
self.board = self.create_board()
9+
self.actual_winner = None
10+
11+
@staticmethod
12+
def create_board():
13+
return [' ' for _ in range(9)]
14+
15+
def board_show(self):
16+
for cell in [self.board[i*3:(i+1)*3] for i in range(3)]:
17+
print('| ' + ' | '.join(cell) + ' |')
18+
19+
@staticmethod
20+
def show_board_numbers():
21+
number_from_board = [[str(i + 1) for i in range(j*3, (j+1)*3)] for j in range(3)]
22+
for cell in number_from_board:
23+
print('| ' + ' | '.join(cell) + ' |')
24+
25+
def make_a_move(self, square, player):
26+
if self.board[square] == ' ':
27+
self.board[square] = player
28+
if self.winner_rules(square, player):
29+
self.actual_winner = player
30+
return True
31+
return False
32+
33+
def winner_rules(self, square, player):
34+
# Checking the row
35+
row_index = math.floor(square / 3)
36+
row = self.board[row_index*3:(row_index+1)*3]
37+
if all([l == player for l in row]):
38+
return True
39+
40+
# Checking the column
41+
col_index = square % 3
42+
column = [self.board[col_index+i*3] for i in range(3)]
43+
if all([l == player for l in column]):
44+
return True
45+
46+
# Checking for diagonal
47+
if square % 2 == 0:
48+
principal_diagonal = [self.board[i] for i in [0, 4, 8]]
49+
if all([l == player for l in principal_diagonal]):
50+
return True
51+
52+
secondary_diagonal = [self.board[i] for i in [2, 4, 6]]
53+
if all([l == player for l in secondary_diagonal]):
54+
return True
55+
56+
return False
57+
58+
def null_squares(self):
59+
return ' ' in self.board
60+
61+
def number_null_squares(self):
62+
return self.board.count(' ')
63+
64+
def remaining_moves(self):
65+
return [p for p, i in enumerate(self.board) if i == ' ']
66+
67+
68+
def play(game, x_player, o_player, show_game = True):
69+
if show_game:
70+
game.show_board_numbers()
71+
72+
player = 'X'
73+
while game.null_squares():
74+
if player == '0':
75+
square = o_player.get_move(game)
76+
else:
77+
square = x_player.get_move(game)
78+
if game.make_a_move(square, player):
79+
if show_game:
80+
print(f'{player} makes a move to square {square}')
81+
game.board_show()
82+
print(' ')
83+
84+
if game.actual_winner:
85+
if show_game:
86+
print(f'{player} wins!')
87+
return player
88+
player = '0' if player == 'X' else 'X'
89+
90+
time.sleep(.8)
91+
92+
if show_game:
93+
print('Tie!')
94+
95+
96+
if __name__ == '__main__':
97+
#x_player = RandomComputer('0')
98+
x_player = SmartComputer('0')
99+
o_player = Human('X')
100+
t = TicTacToe()
101+
play(t, o_player, x_player, True)
102+
103+
104+

0 commit comments

Comments
 (0)