Created
May 29, 2016 13:48
-
-
Save fjkz/b01b7e8a0babd857f3331f03d85e3fc3 to your computer and use it in GitHub Desktop.
A maru-batu game (tic tac toe) solver Raw
This file contains 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/env python3 | |
from copy import deepcopy | |
from enum import Enum | |
from random import shuffle | |
class Simbol(Enum): | |
empty = 0 | |
maru = 1 | |
batu = 2 | |
def enemy(player): | |
if player == Simbol.maru: | |
return Simbol.batu | |
else: | |
return Simbol.maru | |
class Board(): | |
def __init__(self): | |
self.simbols = [ Simbol.empty for _ in range(9) ] | |
self.turn = 0 | |
def get(self, x, y): | |
return self.simbols[x + 3 * y] | |
def empties(self): | |
empties = [] | |
for y in range(3): | |
for x in range(3): | |
if self.get(x, y) == Simbol.empty: | |
empties.append((x, y)) | |
shuffle(empties) | |
return empties | |
def put(self, x, y, simbol): | |
self.simbols[x + 3 * y] = simbol | |
self.turn += 1 | |
def next_player(self): | |
if self.turn % 2 == 0: | |
return Simbol.maru | |
else: | |
return Simbol.batu | |
def copy(self): | |
return deepcopy(self) | |
def winner(self): | |
""" | |
Return winner's simbol if the game is ended. | |
If the game is not over return empty. | |
""" | |
for target in (Simbol.maru, Simbol.batu): | |
# column | |
for x in range(3): | |
if (self.simbols[x] == target and | |
self.simbols[x + 3] == target and | |
self.simbols[x + 6] == target): | |
return target | |
# row | |
for y in range(3): | |
if (self.simbols[3 * y] == target and | |
self.simbols[3 * y + 1] == target and | |
self.simbols[3 * y + 2] == target): | |
return target | |
# diagonal | |
if (self.simbols[0] == target and | |
self.simbols[4] == target and | |
self.simbols[8] == target): | |
return target | |
if (self.simbols[2] == target and | |
self.simbols[4] == target and | |
self.simbols[6] == target): | |
return target | |
return Simbol.empty | |
def print(self): | |
print("") | |
print(" +---+---+---+") | |
for y in range(3): | |
line = " | " | |
for x in range(3): | |
simbol = self.simbols[x + 3 * y] | |
if simbol == Simbol.empty: | |
line += " " | |
elif simbol == Simbol.maru: | |
line += "O" | |
else: | |
line += "X" | |
line += " | " | |
print(line) | |
print(" +---+---+---+") | |
print("") | |
def good_one(player, this, that): | |
if this == enemy(player): | |
if that == Simbol.empty or that == player: | |
return that | |
elif this == Simbol.empty: | |
if that == player: | |
return that | |
return this | |
def bad_one(player, this, that): | |
if this == player: | |
if that == Simbol.empty or that == enemy(player): | |
return that | |
elif this == Simbol.empty: | |
if that == enemy(player): | |
return that | |
return this | |
def minimax(player, board): | |
result = board.winner() | |
if result != Simbol.empty: | |
return result, None | |
empties = board.empties() | |
if len(empties) == 0: | |
return Simbol.empty, None | |
next_player = board.next_player() | |
if next_player == player: | |
best_score = enemy(player) | |
best_move = None | |
for move in empties: | |
new_board = board.copy() | |
new_board.put(move[0], move[1], next_player) | |
score, _ = minimax(player, new_board) | |
good = good_one(player, best_score, score) | |
if good == score: | |
best_score = score | |
best_move = move | |
if best_score == player: | |
break | |
return best_score, best_move | |
else: | |
worst_score = player | |
worst_move = None | |
for move in empties: | |
new_board = board.copy() | |
new_board.put(move[0], move[1], next_player) | |
score, _ = minimax(player, new_board) | |
bad = bad_one(player, worst_score, score) | |
if bad == score: | |
worst_score = score | |
worst_move = move | |
if worst_score == enemy(player): | |
break | |
return worst_score, worst_move | |
if __name__ == "__main__": | |
board = Board() | |
while True: | |
board.print() | |
best_score, best_move = minimax(board.next_player(), board) | |
if best_move == None: | |
break | |
board.put(best_move[0], best_move[1], board.next_player()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment