Skip to content

Instantly share code, notes, and snippets.

@abelsonlive
Last active September 9, 2019 16:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abelsonlive/92504fea5f0a18d3c6a27bba915fa710 to your computer and use it in GitHub Desktop.
Save abelsonlive/92504fea5f0a18d3c6a27bba915fa710 to your computer and use it in GitHub Desktop.
A simple two player game of tic tac toe in the terminal.

tic tac toe

A simple two player game of Tic Tac Toe written in Python 3.6+

To play, download the file below, open a terminal, and run the following command:

$ python3 tic-tac-toe.py

You should see the following output:

tic   tac    toe
〰〰〰〰〰〰〰〰〰

1️⃣      2️⃣      3️⃣

4️⃣      5️⃣      6️⃣

7️⃣      8️⃣      9️⃣

〰〰〰〰〰〰〰〰〰
⭕, choose a cell:

Follow the prompts and have fun!

#!/usr/bin/env python3
import random
# CONSTANTS #
X = "❎"
O = "⭕"
PIECES = [X, O]
HORIZONTAL_LINE = "〰〰〰〰〰〰〰〰〰"
YES = "yes"
NO = "no"
YES_NO_RESPONSES = (YES, NO)
WINNING_MOVES = [
["1", "4", "7"], # left, vertival
["2", "5", "8"], # middle, vertical
["3", "6", "9"], # right, vertical
["1", "2", "3"], # top, horizontal
["4", "5", "6"], # middle, horizontal
["7", "8", "9"], # bottom, horizontal
["1", "5", "9"], # top left to bottom right, diagonal
["3", "5", "7"], # top right to bottom left, diagonal
]
# the board comprises of numbered emoji
# we use 1-indexing for ease of use.
EMOJI = ["1️⃣ ", "2️⃣ ", "3️⃣ ", "4️⃣ ", "5️⃣ ", "6️⃣ ", "7️⃣ ", "8️⃣ ", "9️⃣ "]
EMOJI_TO_CELL = {emoji: str(cell) for cell, emoji in enumerate(EMOJI, start=1)}
class Board(object):
def __init__(self, players):
self.players = players
# set an empty board
self.labels = list(EMOJI_TO_CELL.keys())
self.cells = list(EMOJI_TO_CELL.values())
self.moves = {p: [] for p in self.players}
def set_cell(self, cell, player):
idx = int(cell) - 1 # handle 1-indexing of cell pieces
self.cells[idx] = player
self.labels[idx] = player.piece
self.moves[player].append(cell)
@property
def open_cells(self):
return list(filter(lambda cell: not isinstance(cell, Player), self.cells))
@property
def is_full(self):
return len(self.open_cells) == 0
def is_player_winning(self, player):
return len(self.active_winning_moves_for_player(player)) > 0
def active_winning_moves_for_player(self, player):
# find the list of winning moves that are currently "in-play" for a given player.
return list(
filter(
lambda move: all([cell in self.moves[player] for cell in move]),
WINNING_MOVES,
)
)
def __repr__(self):
return f"""
{ self.labels[0] } { self.labels[1] } { self.labels[2] }
{ self.labels[3] } { self.labels[4] } { self.labels[5] }
{ self.labels[6] } { self.labels[7] } { self.labels[8] }
"""
class Player(object):
def __init__(self, piece):
self.piece = piece
def __str__(self):
return self.piece
def __repr__(self):
return self.piece
class TicTacToe(object):
def __init__(self):
self.players = [Player(X), Player(O)]
self.board = Board(self.players)
self.last_player = None
@property
def current_player(self):
return self.player2 if self.last_player == self.player1 else self.player1
def move_for_player(self, player):
while True:
print(HORIZONTAL_LINE)
print(f"{self.current_player}, choose a cell:")
cell_name = str(input())
if cell_name not in self.board.open_cells:
open_cell_list = ", ".join(self.board.open_cells)
print(f"Try again! Cell must be one of: {open_cell_list}")
else:
break
self.board.set_cell(cell_name, player)
self.last_player = player
def turn(self):
self.move_for_player(self.current_player)
print(HORIZONTAL_LINE)
print(self.board)
def play(self):
# shuffle and set the players
random.shuffle(self.players)
self.player1, self.player2 = self.players
# print the empty board
print(self.board)
while True:
self.turn()
if self.board.is_player_winning(self.last_player):
print(HORIZONTAL_LINE)
print(f"{self.last_player} wins! ")
break
elif self.board.is_full:
print(HORIZONTAL_LINE)
print("It's a tie!")
break
class Game(object):
def ask_for_retry(self):
response = ""
print(f"Would you like to play again, {YES}/{NO}?")
while not (response in YES_NO_RESPONSES):
response = input().lower()
return response == YES
def play(self):
print("tic tac toe ")
print(HORIZONTAL_LINE)
while True:
TicTacToe().play()
print(HORIZONTAL_LINE)
if self.ask_for_retry():
continue
else:
print("Goodbye!")
break
if __name__ == "__main__":
Game().play()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment