Skip to content

Instantly share code, notes, and snippets.

@Hemie143
Created June 25, 2020 19:21
Show Gist options
  • Save Hemie143/8856fe5205153f377914bb73a2acea32 to your computer and use it in GitHub Desktop.
Save Hemie143/8856fe5205153f377914bb73a2acea32 to your computer and use it in GitHub Desktop.
import random
class Board:
def __init__(self):
self.field = list(EMPTY_CELL * 9)
# self.cells = set(range(9))
def show_field(self):
print('---------')
for i in range(3):
print('|', self.field[3 * i], self.field[3 * i + 1], self.field[3 * i + 2], '|')
print('---------')
def isvalid(self, coordinates):
if is_valid_coordinates(coordinates):
return self.field[coordinate_change(*coordinates)] == EMPTY_CELL
def move(self, index, side):
self.field[index] = side
def judge(self, side):
for i, j, k in ROWS:
if self.field[i] == self.field[j] == self.field[k] == side:
return True
return False
class Player:
def __init__(self, side, level):
self.side = side
self.level = level
class HumanPlayer(Player):
def info_before_move(self):
pass
def get_index(self, board):
while True:
coordinates = input('Enter the coordinates: ').split()
if board.isvalid(coordinates):
return coordinate_change(*coordinates)
else:
invalid_message()
class AIPlayer(Player):
def info_before_move(self):
print('Making move level "{}"'.format(self.level))
def get_random_index(self, board):
while True:
index = random.randint(0, 8)
if board.field[index] == EMPTY_CELL:
break
return index
def get_win_index(self, board):
for i, j, k in ROWS:
if [board.field[i], board.field[j], board.field[k]].count(self.side) == 2:
for index in [i, j, k]:
if board.field[index] == ' ':
return index
return -1
def get_no_lose_index(self, board):
if self.side == 'X':
opponent_side = 'O'
else:
opponent_side = 'X'
for i, j, k in ROWS:
if [board.field[i], board.field[j], board.field[k]].count(opponent_side) == 2:
for index in [i, j, k]:
if board.field[index] == ' ':
return index
return -1
def get_index_minimax(self, board):
score, index = minimax(board, self, self.side)
return index
class EasyPlayer(AIPlayer):
def get_index(self, board):
return self.get_random_index(board)
class MediumPlayer(AIPlayer):
def get_index(self, board):
index = self.get_win_index(board)
if index != -1:
return index
index = self.get_no_lose_index(board)
if index != -1:
return index
return self.get_random_index(board)
class HardPlayer(AIPlayer):
def get_index(self, board):
return self.get_index_minimax(board)
def is_valid_coordinates(coordinates):
valid_coordinates = ['1', '2', '3']
for coordinate in coordinates:
if coordinate not in valid_coordinates:
return False
if len(coordinates) != 2:
return False
else:
return True
def invalid_message():
print('Bad parameters!')
def coordinate_change(*coordinates):
return 8 + int(coordinates[0]) - 3 * int(coordinates[1])
def minimax(board, player, side):
opponent_side = get_opponent_side(player.side)
if board.judge(player.side):
return 10, -1
if board.judge(opponent_side):
return -10, -1
if not any(board.field[i] == EMPTY_CELL for i in range(9)):
return 0, -1
next_side = get_opponent_side(side)
moves = {}
for i in range(9):
if board.field[i] == EMPTY_CELL:
board_after_move = Board()
board_after_move.field = board.field[:]
board_after_move.field[i] = side
score, index = minimax(board_after_move, player, next_side)
moves[i] = score
best_index = -1
if player.side == side:
best_score = -100
for index, score in moves.items():
if score > best_score:
best_score = score
best_index = index
else:
best_score = 100
for index, score in moves.items():
if score < best_score:
best_score = score
best_index = index
return best_score, best_index
def get_opponent_side(side):
if side == 'X':
return 'O'
if side == 'O':
return 'X'
return None
EMPTY_CELL = ' '
SIDES = ['X', 'O']
TYPES = ['user', 'easy', 'medium', 'hard']
ROWS = [(0, 3, 6), (1, 4, 7), (2, 5, 8),
(0, 1, 2), (3, 4, 5), (6, 7, 8),
(0, 4, 8), (2, 4, 6)]
while True:
command = input('Input command: ')
if command == 'exit':
break
commands = command.split()
if len(commands) == 3 and commands[0] == 'start' \
and commands[1] in TYPES and commands[2] in TYPES:
players = [None, None]
for i in range(2):
if commands[i + 1] == 'user':
players[i] = HumanPlayer(SIDES[i], commands[i + 1])
elif commands[i + 1] == 'easy':
players[i] = EasyPlayer(SIDES[i], commands[i + 1])
elif commands[i + 1] == 'medium':
players[i] = MediumPlayer(SIDES[i], commands[i + 1])
else:
players[i] = HardPlayer(SIDES[i], commands[i + 1])
new_board = Board()
new_board.show_field()
step = 0
while step < 9:
players[step % 2].info_before_move()
new_board.move(players[step % 2].get_index(new_board), players[step % 2].side)
new_board.show_field()
if new_board.judge(players[step % 2].side):
print(players[step % 2].side, 'wins')
step = -1
break
step += 1
if step == 9:
print('Draw')
else:
invalid_message()
continue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment