Skip to content

Instantly share code, notes, and snippets.

@alekxeyuk
Created September 13, 2021 12:05
Show Gist options
  • Save alekxeyuk/65da0e9a032c6a4b0250eee931375a75 to your computer and use it in GitHub Desktop.
Save alekxeyuk/65da0e9a032c6a4b0250eee931375a75 to your computer and use it in GitHub Desktop.
Domino game with basic AI
from enum import Enum, auto
from itertools import cycle
from typing import Counter, List, Tuple
import random
class GameState(Enum):
INIT = auto()
RUN = auto()
WIN = auto()
LOSS = auto()
DRAW = auto()
class Illegal(Exception):
pass
class DominoGame:
def __init__(self) -> None:
self.state = GameState.INIT
self.field: List[List[int]] = list()
self.status: str = str()
self.init()
def init(self) -> None:
pieces = [[x, y] for y in range(7) for x in range(y + 1)]
self.doubles = [[i, i] for i in range(7)]
random.shuffle(pieces)
self.stock = pieces[:14]
self.computer = pieces[14::2]
self.player = pieces[15::2]
self.data_base = {'c': self.computer, 'p': self.player}
winner = ''
for d in self.doubles:
if d in self.computer:
winner = ('c', d)
self.status = 'It\'s your turn to make a move. Enter your command.'
self.order = cycle('pc')
elif d in self.player:
winner = ('p', d)
self.status = 'Computer is about to make a move. Press Enter to continue...'
self.order = cycle('cp')
if winner:
self.data_base[winner[0]].remove(winner[1])
self.field.append(winner[1])
def print_field(self) -> None:
if len(self.field) > 6:
print("".join(map(str, self.field[:3])), "".join(map(str, self.field[-3:])), sep="...")
else:
print("".join(map(str, self.field)))
def print(self) -> None:
print('=' * 70)
print('Stock size::', len(self.stock))
print('Computer pieces:', len(self.computer), '\n')
self.print_field()
print()
print('Your pieces:')
for i, domino in enumerate(self.player, 1):
print(i, domino, sep=':')
print()
print('Status:', self.status)
def is_draw(self) -> bool:
if self.field[0][0] == self.field[-1][-1]:
if str(self.field).count(str(self.field[0][0])) == 8:
return True
return False
def is_legal(self, end: List[int], domino: List[int], side: int) -> bool:
if side == -1:
end_v = end[0]
if domino[1] == end_v:
return True
domino.reverse()
if domino[1] == end_v:
return True
return False
else:
end_v = end[1]
if domino[0] == end_v:
return True
domino.reverse()
if domino[0] == end_v:
return True
return False
def ai(self) -> None:
c = Counter(map(int, filter(str.isdigit, str(self.field + self.computer))))
hand_score: List[Tuple[int, List[int]]] = list()
for domino in self.computer:
score = 0
for i in domino:
score += c.get(i, 0)
hand_score.append((score, domino))
hand_score.sort(reverse=True)
played = False
for _, domino in hand_score:
if self.is_legal(self.field[0], domino, -1):
self.field.insert(0, domino)
self.computer.remove(domino)
played = True
elif self.is_legal(self.field[-1], domino, 1):
self.field.append(domino)
self.computer.remove(domino)
played = True
if played:
break
if not played and self.stock:
self.computer.append(self.stock.pop())
def run(self) -> None:
self.state = GameState.RUN
while self.state == GameState.RUN:
self.print()
u_input = input()
if next(self.order) == 'p':
while True:
try:
u_input = int(u_input)
if abs(u_input) > len(self.player):
raise ValueError
if u_input == 0:
if len(self.stock):
self.player.append(self.stock.pop())
else:
if u_input > 0:
if self.is_legal(self.field[-1], self.player[u_input - 1], 1):
self.field.append(self.player.pop(abs(u_input) - 1))
else:
raise Illegal
else:
if self.is_legal(self.field[0], self.player[abs(u_input) - 1], -1):
self.field.insert(0, self.player.pop(abs(u_input) - 1))
else:
raise Illegal
break
except ValueError:
u_input = input('Invalid input. Please try again.\n')
except Illegal:
u_input = input('Illegal move. Please try again.\n')
self.status = 'Computer is about to make a move. Press Enter to continue...'
if len(self.player) == 0:
self.status = 'The game is over. You won!'
self.state = GameState.WIN
self.print()
else:
self.ai()
self.status = 'It\'s your turn to make a move. Enter your command.'
if len(self.computer) == 0:
self.status = 'The game is over. The computer won!'
self.state = GameState.LOSS
self.print()
if self.is_draw():
self.status = 'The game is over. It\'s a draw!'
self.state = GameState.DRAW
self.print()
if __name__ == "__main__":
game = DominoGame()
game.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment