Created
February 17, 2014 12:11
-
-
Save sanketsudake/9049493 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
""" | |
File :aitictac.py | |
Arficital Intelligence to play tictac toe | |
Using MinMax n-ply search algorithm | |
""" | |
class Board: | |
def __init__(self, board=[]): | |
self.boardvisual = {2: '-', 3:'X', 5: 'O' } | |
if board: | |
self.board = board | |
else: | |
self.board = [ 2 for i in range(0, 9)] | |
def visual_val(self, val): | |
return self.boardvisual[val] | |
def mark(self, val, pos): | |
self.board[pos] = val | |
def unmark(self, pos): | |
self.board[pos] = 2 | |
def freepos(self): | |
return [ i for i, val in enumerate(self.board) if val == 2] | |
def heuristic(self): | |
max = ((0, 1, 2), (3, 4, 5), (6, 7, 8), | |
(0, 3, 6), (1, 4, 7), (2, 5, 8), | |
(0, 4, 8), (2, 4, 6)) | |
values = [(self.board[k1], self.board[k2], self.board[k3]) for k1, k2, k3 in max] | |
#print(self.board) | |
count_occur = [ ( i.count(3), i.count(5)) for i in values] | |
x_win, o_win = 0, 0 | |
for x_val, o_val in count_occur: | |
if not x_val and not o_val: | |
x_win += 1 | |
o_win += 1 | |
elif not x_val and o_val: | |
o_win += 1 | |
elif x_val and not o_val: | |
x_win += 1 | |
else: | |
pass | |
return x_win - o_win | |
def checkwin(self): | |
max = ((0, 1, 2), (3, 4, 5), (6, 7, 8), | |
(0, 3, 6), (1, 4, 7), (2, 5, 8), | |
(0, 4, 8), (2, 4, 6)) | |
values = [(self.board[k1], self.board[k2], self.board[k3]) for k1, k2, k3 in max] | |
for i in values: | |
x_win, o_win = i.count(3), i.count(5) | |
if x_win == 3: | |
return 3 | |
elif o_win == 3: | |
return 5 | |
else: | |
pass | |
return 0 | |
def __str__(self): | |
return "\n\t" + '\n ------------------------\n\t'.join( | |
[' |\t'.join(map(self.visual_val, self.board[i:i+3])) | |
for i in map(lambda x: x*3, range(3))]) | |
class Game: | |
def __init__(self, board): | |
self.boardvisual = {2: '-', 3:'X', 5: 'O' } | |
self.choice = '-' | |
while self.choice not in ('X', 'O'): | |
self.choice = str(input("Select X or O: ")) | |
self.board = board | |
if self.choice == 'X': | |
self.human_choice = 3 | |
self.comp_choice = 5 | |
self.game_start = 0 | |
else: | |
self.comp_choice = 3 | |
self.human_choice = 5 | |
self.game_start = 1 | |
self.play() | |
def play(self): | |
for i in range(9): | |
print(str(self.board)) | |
win_val = self.board.checkwin() | |
if(win_val): | |
if win_val == 3: | |
print("X player won") | |
else: | |
print("O player won") | |
exit() | |
if self.game_start % 2: | |
self.comp() | |
else: | |
self.human() | |
self.game_start += 1 | |
def human(self): | |
print('Human =>') | |
free_positions = self.board.freepos() | |
valid_positions = range(0, 9) | |
pos = -1 | |
while (pos not in free_positions) or (pos not in valid_positions): | |
pos = int(input("Give position : ")) | |
self.board.mark(self.human_choice, pos - 1) | |
def comp(self): | |
print('Computer =>') | |
if self.comp_choice == 5: | |
status = 0 | |
else: | |
status = 1 | |
depth = 2 | |
self.board.mark(self.comp_choice, | |
self.minimax(Board(self.board.board.copy()), status, depth)[0]) | |
def minimax(self, board, status=True, depth=2): | |
bestscore = -1 | |
bestpos = -1 | |
free_positions = board.freepos() | |
states = {} | |
for i in free_positions: | |
board.mark(self.comp_choice, i) | |
h_val = board.heuristic() | |
if h_val not in states.keys(): | |
states[h_val] = [] | |
states[h_val].append([i, Board(board.board.copy()), h_val]) | |
board.unmark(i) | |
if(status): | |
next = states[max(states.keys())] | |
else: | |
next = states[min(states.keys())] | |
depth = depth - 1 | |
if len(next) == 1 or not depth or len(free_positions) == 1: | |
pos, h_val = next[0][0], next[0][2] | |
return (pos, h_val) | |
states = [] | |
i_index = -1 | |
if status: | |
check_val= 1000 | |
else: | |
check_val = -1000 | |
for i, entry in enumerate(next): | |
local_value = self.minimax(entry[1], (not status), depth) | |
m_value = local_value[1] | |
#retvals.append([entry[0], entry[2], m_value[0], m_value[1]]) | |
if status: | |
if m_value < check_val: | |
check_val = m_value | |
i_index = i | |
else: | |
if m_value > check_val: | |
check_val = m_value | |
i_index = i | |
pos , h_val= next[i_index][0], next[i_index][2] | |
return (pos, h_val) | |
def main(): | |
g = Game(Board()) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment