Created
November 25, 2021 22:06
-
-
Save ArjixWasTaken/8b1043aa27bf27eab7c42bbceee71800 to your computer and use it in GitHub Desktop.
Tic Tac Toe! in python
This file contains hidden or 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
from typing import List | |
from itertools import cycle | |
from os import system as run_cmd | |
def get_player_id(): | |
id = 1 | |
while 1: | |
yield id | |
id += 1 | |
get_player_id = get_player_id() | |
class Player: | |
def __init__(self, char: str) -> None: | |
self.id = next(get_player_id) | |
self.char = char | |
if len(char) != 1: | |
raise Exception( | |
"A player can only have a single symbol as his char.") | |
if char.isdigit(): | |
raise Exception("A player can't have a digit as his char.") | |
def ask_input(self, available_moves: List[int]) -> int: | |
answer = input( | |
"Player {} - {} - Enter your move: ".format(self.id, self.char)) | |
while 1: | |
if not answer.isdigit(): | |
print("Invalid choice, you must enter a number.") | |
answer = input("Player {} - {} - Enter your move ({}): ".format( | |
self.id, | |
self.char, | |
", ".join([str(x) for x in available_moves]) | |
) | |
) | |
elif int(answer) not in available_moves: | |
print("Invalid choice: That move is not available.") | |
answer = input("Player {} - {} - Enter your move ({}): ".format( | |
self.id, | |
self.char, | |
", ".join([str(x) for x in available_moves]) | |
) | |
) | |
else: | |
break | |
return int(answer) | |
class Grid: | |
def __init__(self) -> None: | |
self.table = [ | |
[" 1 ", " 2 ", " 3 "], | |
[" 4 ", " 5 ", " 6 "], | |
[" 7 ", " 8 ", " 9 "] | |
] | |
@property | |
def is_full(self) -> bool: | |
return all([ | |
not x.strip().isdigit() | |
for row in self.table | |
for x in row | |
]) | |
def set_cell(self, index: int, char: str): | |
if index < 4: | |
self.table[0][index-1] = f" {char} " | |
elif index < 7: | |
self.table[1][index-4] = f" {char} " | |
else: | |
self.table[2][index-7] = f" {char} " | |
def get_available_moves(self) -> List[int]: | |
moves: List[int] = [] | |
for row in self.table: | |
for col in row: | |
if col.strip().isdigit(): | |
moves.append(int(col)) | |
return moves | |
def __repr__(self): | |
out = "_"*13 + "\n" | |
out += "|" + "|".join(self.table[0]) + "|" + "\n" + "-"*13 + "\n" | |
out += "|" + "|".join(self.table[1]) + "|" + "\n" + "-"*13 + "\n" | |
out += "|" + "|".join(self.table[2]) + "|" + "\n" | |
out += "‾"*13 | |
return out | |
class Game: | |
def __init__(self) -> None: | |
self.grid = Grid() | |
self.finished = False | |
self.player = cycle([Player("x"), Player("o")]) | |
def check_if_win(self, char): | |
winning_str = str([f" {char} "]*3) | |
if str(self.grid.table[0]) == winning_str: | |
return True | |
elif str(self.grid.table[1]) == winning_str: | |
return True | |
elif str(self.grid.table[2]) == winning_str: | |
return True | |
rev = list(reversed(list(zip(*self.grid.table)))) | |
if any([str(list(x)) == winning_str for x in rev]): | |
return True | |
if str([ | |
self.grid.table[0][0], | |
self.grid.table[1][1], | |
self.grid.table[2][2] | |
]) == winning_str: | |
return True | |
elif str([ | |
self.grid.table[0][2], | |
self.grid.table[1][1], | |
self.grid.table[2][0] | |
]) == winning_str: | |
return True | |
return False | |
def run(self): | |
while not self.finished: | |
run_cmd("cls || clear") | |
print(self.grid) | |
player = next(self.player) | |
move = player.ask_input(self.grid.get_available_moves()) | |
self.grid.set_cell(move, player.char) | |
if self.check_if_win(player.char): | |
print("Congrats! Player {} won!".format(player.id)) | |
break | |
elif self.grid.is_full: | |
print("It's a tie!") | |
break | |
game = Game() | |
game.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment