Created
February 9, 2025 22:45
-
-
Save hammamiomar/fff91f2f9c0bd5a48e3bd616eb773360 to your computer and use it in GitHub Desktop.
tictactoe
This file contains 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
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