174 lines
4.5 KiB
Python
174 lines
4.5 KiB
Python
import random
|
|
|
|
class Player(object):
|
|
|
|
def __init__(self,rep):
|
|
self.rep = rep
|
|
|
|
def __repr__(self):
|
|
return self.rep
|
|
|
|
def count_win_chances(self, board):
|
|
chances = 0
|
|
for line in board.get_all_lines():
|
|
if all( map( lambda v: v == self or v == Board.empty, line) ):
|
|
chances += 1
|
|
return chances
|
|
|
|
class Board(object):
|
|
draw = object()
|
|
empty = Player(" ")
|
|
def __init__(self,size=3):
|
|
self.board = [ [Board.empty] * size for i in range(size) ]
|
|
self.size = size
|
|
|
|
def set(self, x, y, value):
|
|
if x < 0 or x >= self.size or y < 0 or y >= self.size:
|
|
raise Exception("Out of bounds!")
|
|
if value == Board.empty or isinstance(value,Player):
|
|
self.board[x][y] = value
|
|
else:
|
|
raise Exception("Invalid value %s" % str(value))
|
|
|
|
def get(self, x, y):
|
|
if x < 0 or x >= self.size or y < 0 or y >= self.size:
|
|
raise Exception("Out of bounds!")
|
|
else:
|
|
return self.board[x][y]
|
|
|
|
def get_all_lines(self):
|
|
lines = []
|
|
#diagonals
|
|
lines.append( [ self.board[xy][xy] for xy in range(self.size) ] )
|
|
lines.append( [ self.board[x][self.size-x-1] for x in range(self.size) ] )
|
|
|
|
#rows
|
|
lines += self.board
|
|
|
|
#cols
|
|
lines += [ [ self.board[x][y] for x in range(self.size) ] for y in range(self.size) ]
|
|
|
|
return lines
|
|
|
|
def get_empty_fields(self):
|
|
for x in range(self.size):
|
|
for y in range(self.size):
|
|
if self.board[x][y] == Board.empty:
|
|
yield (x,y)
|
|
|
|
def get_winner(self):
|
|
for line in self.get_all_lines():
|
|
if line[0] != self.empty and all(map(lambda v: v == line[0],line)):
|
|
return line[0]
|
|
for field in self.get_empty_fields():
|
|
return None
|
|
return Board.draw
|
|
|
|
def copy(self):
|
|
c = Board(size=self.size)
|
|
for x in range(self.size):
|
|
for y in range(self.size):
|
|
c.set(x,y, self.get(x,y))
|
|
return c
|
|
|
|
def __str__(self):
|
|
return ("\n-"+("*-"*(self.size-1)) +"\n").join( [ "|".join( [ str(pos) for pos in line ] ) for line in self.board ] )
|
|
|
|
|
|
class AI(Player):
|
|
def play(self,enemy, board):
|
|
if board.get_winner() is not None:
|
|
raise Exception("Game over!")
|
|
boardcopy = board.copy()
|
|
|
|
moves = []
|
|
|
|
#Check for win chance
|
|
for x,y in board.get_empty_fields():
|
|
boardcopy.set(x,y,self)
|
|
|
|
# Check for chance
|
|
chance = self.count_win_chances(boardcopy) - enemy.count_win_chances(boardcopy)
|
|
|
|
# Check for win
|
|
if boardcopy.get_winner() == self:
|
|
chance += 1000
|
|
|
|
|
|
|
|
# Check if enemy win
|
|
boardcopy.set(x,y,enemy)
|
|
|
|
if boardcopy.get_winner() == enemy:
|
|
chance += 500
|
|
|
|
boardcopy.set(x,y,Board.empty)
|
|
moves.append( (chance,(x,y)) )
|
|
|
|
moves.sort(key=lambda x: -x[0])
|
|
|
|
best_move = moves[0]
|
|
|
|
good_moves = []
|
|
|
|
for move in moves:
|
|
if move[0] == best_move[0]:
|
|
good_moves.append(move)
|
|
|
|
return random.choice(good_moves)[1]
|
|
|
|
class Human(Player):
|
|
def play(self, enemy, board):
|
|
while True:
|
|
s = input("Player %s's turn:" % self.rep)
|
|
try:
|
|
(x,y) = map(int, s.split(","))
|
|
return (x,y)
|
|
except Exception:
|
|
print("Try again?")
|
|
|
|
def rotate(l):
|
|
return l[1:] + l[:1]
|
|
|
|
def menu(prompt,choices):
|
|
print("> %s" % prompt)
|
|
for i,choice in enumerate(choices):
|
|
print("%d. %s" % (i,choice))
|
|
return int(input("Your choice: "))
|
|
|
|
if __name__ == "__main__":
|
|
c = menu("Playmode",["Ai vs Ai","Ai vs Player","Player vs Player"])
|
|
if c == 0:
|
|
players = [ AI("X"), AI("O") ]
|
|
elif c == 1:
|
|
players = [ Human("X"), AI("O") ]
|
|
elif c == 2:
|
|
players = [ Human("X"), Human("O") ]
|
|
else:
|
|
import sys
|
|
sys.exit(0)
|
|
|
|
board = Board(size=3)
|
|
|
|
print(str(board))
|
|
|
|
while board.get_winner() is None:
|
|
(x,y) = players[0].play(players[1],board)
|
|
while board.get(x,y) != Board.empty:
|
|
print("Try again!")
|
|
(x,y) = players[0].play(players[1],board)
|
|
|
|
board.set(x,y,players[0])
|
|
players = rotate(players)
|
|
|
|
print()
|
|
print(str(board))
|
|
|
|
winner = board.get_winner()
|
|
|
|
if winner == Board.draw:
|
|
print("Round draw!")
|
|
else:
|
|
print("%s has won!" % str(winner) )
|
|
|
|
|