Skip to content

Instantly share code, notes, and snippets.

@hammamiomar
Created February 9, 2025 22:45
Show Gist options
  • Save hammamiomar/fff91f2f9c0bd5a48e3bd616eb773360 to your computer and use it in GitHub Desktop.
Save hammamiomar/fff91f2f9c0bd5a48e3bd616eb773360 to your computer and use it in GitHub Desktop.
tictactoe
import os
import sys
import select
import termios
import time
boardFrame = [
" ┌─────────────┬────────────┬────────────┐ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" ┼─────────────┼────────────┼────────────┼ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" ┼─────────────┼────────────┼────────────┼ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" │ │ │ │ ",
" └─────────────┴────────────┴────────────┘ "
]
boardPieces = {
'X': [
"██╗ ██╗",
"╚██╗██╔╝",
" ╚███╔╝ ",
" ██╔██╗ ",
"██╔╝ ██╗",
"╚═╝ ╚═╝"
],
'O': [
" ██████╗ ",
"██╔═══██╗",
"██║ ██║",
"██║ ██║",
"╚██████╔╝",
" ╚═════╝ "
],
'-': [
" ",
" ",
"█████╗ ",
"╚════╝ ",
" ",
" "
]
}
boardPiecesInverse = {
'X': [
" ╗██ ╗",
"╚ ╗ ╔╝",
"█╚ ╔╝█",
"█ ╔ ╗█",
" ╔╝█ ╗",
"╚═╝██╚═╝"
],
'O': [
"█ ╗█",
" ╔═══ ╗",
" ╗███ ║",
" ║███ ║",
"╚ ╔╝",
"█╚═════╝█"
],
'-': [
"████████",
"████████",
" ╗██",
"╚════╝██",
"████████",
"████████"
]
}
class Board:
def __init__(self):
self.state = [
['-','-','-'],
['-','-','-'],
['-','-','-']
]
self.turn = 0 # 0 is x turn, 1 is O turn
self.frameNum = 0
self.row, self.col = 0,0
def getFrame(self):
def getReplacement(i, j, inverse=False):
frameRow, frameCol = positionsMap[(i,j)]
piece = self.state[i][j]
pieces = boardPiecesInverse if inverse else boardPieces
for lineIndex, line in enumerate(pieces[piece]):
frame_line = list(frame[frameRow + lineIndex])
frame_line[frameCol:frameCol + len(line)] = line
frame[frameRow + lineIndex] = ''.join(frame_line)
frame = boardFrame
positionsMap = {
(0,0): (1, 10), (0,1): (1, 25), (0,2): (1, 38),
(1,0): (8, 10), (1,1): (8, 25), (1,2): (8, 38),
(2,0): (15, 10), (2,1): (15, 25), (2,2): (15, 38)
}
for i in range(3):
for j in range(3):
getReplacement(i,j)
if self.frameNum %2 == 0:
getReplacement(self.row,self.col,inverse=True)
return frame
def placePiece(self):
if self.state[self.row][self.col] == "-":
if self.turn == 0:
self.state[self.row][self.col] = "X"
else:
self.state[self.row][self.col] = "O"
self.turn = 1 - self.turn
return True
else:
return False
def checkWin(self):
for rowI in range(3):
if self.state[rowI][0] != "-" and self.state[rowI][0] == self.state[rowI][1] == self.state[rowI][2]:
return self.state[rowI][0]
for colI in range(3):
if self.state[0][colI] != "-" and self.state[0][colI] == self.state[1][colI] == self.state[2][colI]:
return self.state[0][colI]
if self.state[0][0] != '-' and self.state[0][0] == self.state[1][1] == self.state[2][2]:
return self.state[0][0]
if self.state[0][2] != '-' and self.state[0][2] == self.state[1][1] == self.state[2][0]:
return self.state[0][2]
if all(self.state[i][j] != '-' for i in range(3) for j in range(3)):
return 'Tie'
return None
def clearScreen():
print('\033[H\033[J', end='')
def drawFrame(frame,status):
terminalWidth = os.get_terminal_size().columns
sys.stdout.write("Ticy taca ta, y ticy taca to".center(terminalWidth) + "\n")
sys.stdout.write(status.center(terminalWidth) + "\n")
for line in frame:
sys.stdout.write(line.center(terminalWidth) + "\n")
sys.stdout.write("Move with wasd keys. Place with Space. Quit with q.".center(terminalWidth)+ "\n")
sys.stdout.flush()
def main():
# Set up non-blocking input
old_settings = termios.tcgetattr(sys.stdin)
new_settings = termios.tcgetattr(sys.stdin)
new_settings[3] = new_settings[3] & ~(termios.ECHO | termios.ICANON) # turn off echo and canonical mode.
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, new_settings) #tcsa flush allows output queue to be read, and also flush anything that is stuck in input queue
board = Board()
status = "X turn"
try:
while True:
clearScreen()
frame = board.getFrame()
print("\033[H",end='')
drawFrame(frame,status=status)
if sys.stdin in select.select([sys.stdin],[],[],0)[0]:
key = sys.stdin.read(1)
# movement
if key == "q":
break
elif key == "w" and board.row>0:
board.row -=1
elif key == "a" and board.col>0:
board.col -=1
elif key == "s" and board.row <2:
board.row +=1
elif key == "d" and board.col <2:
board.col +=1
elif key == " ":
if board.placePiece():
winner = board.checkWin()
if winner:
if winner == "Tie":
status="Tie. Press r to restart"
else:
status=f"{winner} wins. Press r to restart"
else:
if board.turn==0:
status="X turn"
else:
status="O turn"
elif key == "r":
board = Board()
status = "X turn"
time.sleep(0.2)
board.frameNum+=1
except KeyboardInterrupt:
clearScreen()
finally:
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, old_settings)
clearScreen()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment