Skip to content

Instantly share code, notes, and snippets.

@fjkz
Created May 29, 2016 13:48
Show Gist options
  • Save fjkz/b01b7e8a0babd857f3331f03d85e3fc3 to your computer and use it in GitHub Desktop.
Save fjkz/b01b7e8a0babd857f3331f03d85e3fc3 to your computer and use it in GitHub Desktop.
A maru-batu game (tic tac toe) solver Raw
#!/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