mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-05 20:40:25 -08:00
244 lines
7.0 KiB
Python
Executable File
244 lines
7.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from enum import Enum
|
|
|
|
|
|
class OccupiedBy(Enum):
|
|
COMPUTER = -1
|
|
EMPTY = 0
|
|
PLAYER = 1
|
|
|
|
|
|
class Winner(Enum):
|
|
NONE = 0
|
|
COMPUTER = 1
|
|
PLAYER = 2
|
|
DRAW = 3
|
|
|
|
|
|
class Space(Enum):
|
|
TOP_LEFT = 0
|
|
TOP_CENTER = 1
|
|
TOP_RIGHT = 2
|
|
MID_LEFT = 3
|
|
MID_CENTER = 4
|
|
MID_RIGHT = 5
|
|
BOT_LEFT = 6
|
|
BOT_CENTER = 7
|
|
BOT_RIGHT = 8
|
|
|
|
|
|
def line_170(board, g, h, j, k):
|
|
if g == OccupiedBy.Player and board[Space.MID_CENTER] == g:
|
|
if (
|
|
board[Space.TOP_RIGHT] == g and board[Space.BOTTOM_LEFT] is OccupiedBy.EMPTY
|
|
): # Line 171
|
|
return Space.BOTTOM_LEFT # Line 187
|
|
elif (
|
|
board[Space.BOTTOM_RIGHT] == g and board[Space.TOP_LEFT] is OccupiedBy.EMPTY
|
|
): # Line 172
|
|
return Space.TOP_LEFT # Line 181
|
|
elif (
|
|
board[Space.BOTTOM_LEFT] == g and board[Space.TOP_RIGHT] is OccupiedBy.EMPTY
|
|
) or (
|
|
board[Space.BOTTOM_RIGHT] is OccupiedBy.PLAYER
|
|
and board[Space.TOP_RIGHT] is OccupiedBy.EMPTY
|
|
): # Line 173 and 174
|
|
return Space.TOP_RIGHT # Line 183 and Line 189
|
|
elif g is OccupiedBy.COMPUTER:
|
|
g = OccupiedBy.PLAYER
|
|
h = OccupiedBy.COMPUTER
|
|
return line_118(board, g, h, j, k)
|
|
|
|
|
|
def line_150(board, g, h, j, k):
|
|
if board[k] != g: # line 150
|
|
return (
|
|
-1
|
|
if (
|
|
board[k] == h # line 160
|
|
or board[k + 6] != g # line 161
|
|
or board[k + 3] != g
|
|
)
|
|
else k + 3
|
|
)
|
|
elif board[k + 6] != g: # line 152
|
|
if board[k + 6] != 0 or board[k + 3] != g: # line 165
|
|
return -1 # Goto 170
|
|
elif board[k + 3]: # line 156
|
|
return -1
|
|
|
|
return k + 6
|
|
|
|
|
|
def line_120(board, g, h, j, k):
|
|
pass
|
|
|
|
|
|
def line_118(board, g, h):
|
|
for j in range(7):
|
|
for k in range(3):
|
|
return line_120(board, g, h, j, k)
|
|
|
|
|
|
def think(board, g, h, moves):
|
|
|
|
if board[Space.MID_CENTER] is OccupiedBy.EMPTY:
|
|
return Space.MID_CENTER
|
|
|
|
if board[Space.MID_CENTER] is OccupiedBy.PLAYER:
|
|
if (
|
|
board[Space.TOP_CENTER] is OccupiedBy.PLAYER
|
|
and board[Space.TOP_LEFT] is OccupiedBy.EMPTY
|
|
or board[Space.MID_LEFT] is OccupiedBy.PLAYER
|
|
and board[Space.TOP_LEFT] is OccupiedBy.EMPTY
|
|
):
|
|
return Space.BOT_LEFT
|
|
elif (
|
|
board[Space.MID_RIGHT] is OccupiedBy.PLAYER
|
|
and board[Space.BOT_RIGHT] is OccupiedBy.EMPTY
|
|
or board[Space.BOT_CENTER] is OccupiedBy.PLAYER
|
|
and board[Space.BOT_RIGHT] is OccupiedBy.EMPTY
|
|
):
|
|
return Space.BOT_RIGHT
|
|
|
|
if g == OccupiedBy.PLAYER:
|
|
j = 3 * int((moves - 1) / 3)
|
|
if move == j + 1: # noqa: This definitely is a bug!
|
|
k = 1
|
|
if move == j + 2: # noqa: This definitely is a bug!
|
|
k = 2
|
|
if move == j + 3: # noqa: This definitely is a bug!
|
|
k = 3
|
|
return subthink(g, h, j, k) # noqa: This definitely is a bug!
|
|
|
|
|
|
def render_board(board, space_mapping):
|
|
vertical_divider = "!"
|
|
horizontal_divider = "---+---+---"
|
|
lines = [
|
|
vertical_divider.join(space_mapping[space] for space in board[:3]),
|
|
horizontal_divider,
|
|
vertical_divider.join((space_mapping[space] for space in board[3:6])),
|
|
horizontal_divider,
|
|
vertical_divider.join((space_mapping[space] for space in board[6:9])),
|
|
]
|
|
return "\n".join(lines)
|
|
|
|
|
|
def determine_winner(board, g):
|
|
# Check for matching horizontal lines
|
|
for i in range(Space.TOP_LEFT.value, Space.BOT_LEFT.value + 1, 3): # Line 1095
|
|
if board[i] != board[i + 1] or board[i] != board[i + 2]: # Lines 1100 and 1105
|
|
continue # First third of Line 1115
|
|
elif board[i] == OccupiedBy.COMPUTER: #
|
|
return Winner.COMPUTER
|
|
elif board[i] == OccupiedBy.PLAYER:
|
|
return Winner.PLAYER
|
|
|
|
# Check for matching vertical lines
|
|
for i in range(
|
|
Space.TOP_LEFT.value, Space.TOP_RIGHT.value + 1, 1
|
|
): # Second third of Line 1115
|
|
if (
|
|
board[i] != board[i + 3] or board[i] != board[i + 6]
|
|
): # Last third of Line 1115
|
|
continue # First third of 1150
|
|
elif board[i] == OccupiedBy.COMPUTER: # Line 1135
|
|
return Winner.COMPUTER
|
|
elif board[i] == OccupiedBy.PLAYER: # Line 1137
|
|
return Winner.PLAYER
|
|
|
|
# Check diagonals
|
|
if any(space is OccupiedBy.EMPTY for space in board):
|
|
if board[Space.MID_CENTER.value] != g:
|
|
return Winner.NONE
|
|
elif (
|
|
board[Space.TOP_LEFT.value] == g and board[Space.BOT_RIGHT.value] == g
|
|
) or (board[Space.BOT_LEFT.value] == g and board[Space.TOP_RIGHT.value] == g):
|
|
return Winner.COMPUTER if g is OccupiedBy.COMPUTER else Winner.PLAYER
|
|
else:
|
|
return Winner.NONE
|
|
|
|
return Winner.DRAW
|
|
|
|
|
|
def computer_think(board):
|
|
empty_indices = [
|
|
index for index, space in enumerate(board) if space is OccupiedBy.EMPTY
|
|
]
|
|
|
|
return empty_indices[0]
|
|
|
|
|
|
def prompt_player(board):
|
|
while True:
|
|
move = int(input("\nWHERE DO YOU MOVE? "))
|
|
|
|
if move == 0:
|
|
return 0
|
|
|
|
if move > 9 or board[move - 1] is not OccupiedBy.EMPTY:
|
|
print("THAT SQUARE IS OCCUPIED.\n\n")
|
|
continue
|
|
|
|
return move
|
|
|
|
|
|
def main() -> None:
|
|
print(" " * 30 + "TIC-TAC-TOE")
|
|
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
|
print("\n\n")
|
|
|
|
print("THE BOARD IS NUMBERED:")
|
|
print(" 1 2 3")
|
|
print(" 4 5 6")
|
|
print(" 7 8 9")
|
|
print("\n\n")
|
|
|
|
# Default state
|
|
board = [OccupiedBy.EMPTY] * 9
|
|
current_player = OccupiedBy.PLAYER
|
|
space_mapping = {
|
|
OccupiedBy.EMPTY: " ",
|
|
OccupiedBy.PLAYER: " X ",
|
|
OccupiedBy.COMPUTER: " O ",
|
|
}
|
|
|
|
symbol = input("DO YOU WANT 'X' OR 'O'? ").upper()
|
|
|
|
# If the player doesn't choose X, then assume you want O
|
|
# and the computer goes first.
|
|
if symbol != "X":
|
|
space_mapping[OccupiedBy.PLAYER] = " O "
|
|
space_mapping[OccupiedBy.COMPUTER] = " X "
|
|
current_player = OccupiedBy.COMPUTER
|
|
|
|
while True:
|
|
if current_player is OccupiedBy.PLAYER:
|
|
move = prompt_player(board)
|
|
if move == 0:
|
|
print("THANKS FOR THE GAME.")
|
|
break
|
|
board[move - 1] = current_player
|
|
|
|
elif current_player is OccupiedBy.COMPUTER:
|
|
print("\nTHE COMPUTER MOVES TO...")
|
|
board[computer_think(board)] = current_player
|
|
|
|
print(render_board(board, space_mapping))
|
|
|
|
winner = determine_winner(board, current_player)
|
|
|
|
if winner is not Winner.NONE:
|
|
print(winner)
|
|
break
|
|
|
|
if current_player is OccupiedBy.COMPUTER:
|
|
current_player = OccupiedBy.PLAYER
|
|
elif current_player is OccupiedBy.PLAYER:
|
|
current_player = OccupiedBy.COMPUTER
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|