Skip to content

Instantly share code, notes, and snippets.

@horstjens
Last active May 1, 2020 17:04
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 horstjens/dfcf2c116199d0616e089aa43b9dfde1 to your computer and use it in GitHub Desktop.
Save horstjens/dfcf2c116199d0616e089aa43b9dfde1 to your computer and use it in GitHub Desktop.
ThePythonGameBook-TicTacToe code files
board = """
[ ] [ ] [ ]
[ ] [ ] [ ]
[ ] [ ] [ ]"""
print(board)
print("[ ] [ ] [ ]\n" * 3) # all in one-line
"""desired display of board"""
board=r"""
r\c 0: 1: 2:
0: [ ] [ ] [ ]
1: [ ] [ ] [ ]
2: [ ] [ ] [ ]"""
print(board)
cells = [["x", "x", " "],
[" ", "x", "o"],
["o", " ", "o"],
]
board = r"""
r\c 0: 1: 2:
0: [{}] [{}] [{}]
1: [{}] [{}] [{}]
2: [{}] [{}] [{}]"""
print(board.format(cells[0][0], cells[0][1], cells[0][2],
cells[1][0], cells[1][1], cells[1][2],
cells[2][0], cells[2][1], cells[2][2] ))
cells = [["x", "x", " "],
[" ", "x", "o"],
["o", " ", "o"],
]
# ---- define the function ----
def display(): # function without arguments
"""displays the 3x3 array 'cells'
with heading row and column"""
print(r"r\c 0: 1: 2:") # header line. r\c is not an escape sequence -> raw string
for index, row in enumerate(cells):
print("{}: ".format(index), end="") # no new line at end of print
for element in row:
print("[{}] ".format(element), end="") # no new line at end of print
print() # print only a new line
# call the function
display()
cells = [["x", "x", " "],
[" ", "x", "o"],
["o", " ", "o"],
]
board = r"""
r\c 0: 1: 2:
0: [{}] [{}] [{}]
1: [{}] [{}] [{}]
2: [{}] [{}] [{}]"""
# convert the list of list (cells) into a one-dimensional array
flat_cells = []
for row in cells:
for element in row:
flat_cells.append(element) # adds 'element' toe list flat_cells (at the end)
print(flat_cells)
# or, in a neat one-liner:
flat_cells2 = [element for row in cells for element in row]
print(flat_cells2)
# pass the flat_cells array as argument list
print(board.format(*flat_cells))
while True: # endless loop
print("Please enter index of column: 0 or 1 or 2")
print("followed by index of row: 0 or 1 or 2")
print("like for example: 0 1")
command = input("and press ENTER: > ")
command = command.strip() # remove leading and trailing spaces
column_string = command[0] # the first char
row_string = command[-1] # the last (!) char
if column_string in ["0", "1", "2"] and row_string in ["0", "1", "2"]:
break
print("Wrong input. Please try again \n") # make an extra new line at the end!
print("column:", column_string, "row:", row_string)
cells = [["x", "x", " "],
[" ", "x", "o"],
["o", " ", "o"],
]
def is_free(row, column): # function with two mandatory arguments
"""checks a single coordinate in the cells array
returns True if the cell is free (contains a Space)
otherwise returns False"""
try:
content = cells[row][column]
except IndexError:
return "this cell does not exist"
except:
return "not even a legal index"
# slow but readable
if content == " ":
return True
return False
# faster but harder to read:
# return True if content == " " else False
# ---- testing ------
print("0,0:", is_free(0, 0))
print("2,1:", is_free(2, 1))
print("5,6:", is_free(5, 6))
print("x,0:", is_free("x", 0))
"""tic tac toe for 2 players, without win checking"""
def is_free(row, column):
"""checks a single coordinate in the the cells array
returns True if the cell is free (contains a Space)
otherwise returns False"""
try:
content = cells[row][column]
except IndexError:
print("this cell does not exist")
return False
return True if content == " " else False
def display():
"""displays the 3x3 array 'cells' with heading row and column"""
print(r"r\c 0: 1: 2:") # header line. r\c is not an escape sequence, leading r -> raw string
for index, row in enumerate(cells):
print("{}: ".format(index), end="") # no new line at end of print
for element in row:
print("[{}] ".format(element), end="") # no new line at end of print
print() # print only a new line
print() # empty line after board
# slow but good to read:
cells = [[" ", " ", " "],
[" ", " ", " "],
[" ", " ", " "],
]
# ore more elegant:
# cells = [[" " for x in range(3)] for y in range(3)]
symbols = ["x", "o"]
greeting = "This is turn {}. Player {}, where do you put your '{}'?"
text = "Please enter numbers (0 or 1 or 2) for column and row\n"
text += " like for example: '1 2' or '02' or '2x1'\n"
text += " and press ENTER >>> "
for turns in range(9): # play 9 legal moves, then the board is full
display()
player = turns % 2 # modulo: the remainder of a division by 2.
print(greeting.format(turns, player, symbols[player]))
while True: # ask until legal move
command = input(text)
command = command.strip()
if len(command) < 2:
print("Enter 2 coordinates. Try again!")
continue
raw_column, raw_row = command[0], command[-1] # 2 variables, 2 values
try:
row, column = int(raw_row), int(raw_column) # 2 variables, 2 values and only one line inside try: block
except ValueError:
print("Enter numbers only. Try again")
continue # go back to the start of the while loop
if is_free(row, column):
print("input accepted\n") # extra new line
cells[row][column] = symbols[player]
break # breaks out of this while loop
# print("*** next turn! *****")
print("all fields are full. Game Over")
"""tic tac toe for 2 players, wit win checking"""
# ---- functions ----
def check_win(char):
"""checks the array cells and returns True if 3 chars build a line"""
for row in range(3): # checking rows. range(3) returns 0, 1, 2, it is the same as 'for row in [0,1,2]:'
if cells[row][0] == char and cells[row][1] == char and cells[row][2] == char:
return True # checking columns
for col in range(3):
if cells[0][col] == char and cells[1][col] == char and cells[2][col] == char:
return True
# checking diagonal
if cells[0][0] == char and cells[1][1] == char and cells[2][2] == char:
return True
if cells[2][0] == char and cells[1][1] == char and cells[0][2] == char:
return True
return False # all win condition checked without success, therefore no win
def is_free(row, column):
"""checks a single coordinate in the the cells array returns True if the cell is free (contains a Space)
otherwise returns False"""
try:
content = cells[row][column]
except IndexError:
print("this cell does not exist")
return False
return True if content == " " else False
def display():
"""displays the 3x3 array 'cells' with heading row and column"""
print(r"r\c 0: 1: 2:") # header line. r\c is not an escape sequence, leading r -> raw string
for index, row in enumerate(cells):
print("{}: ".format(index), end="") # no new line at end of print
for element in row:
print("[{}] ".format(element), end="") # no new line at end of print
print() # print only a new line
print() # empty line after board
# ---- variables at top level ----
cells = [[" " for x in range(3)] for y in range(3)]
symbols = ["x", "o"]
greeting = "This is turn {}. Player {}, where do you put your '{}'?"
text = "Please enter numbers (0 or 1 or 2) for column and row\n"
text += " like for example: '1 2' or '02' or '2x1'\n"
text += " and press ENTER >>> "
# ---- the 'main loop' of the game -----
for turns in range(9): # play 9 legal moves, then the board is full
display()
player = turns % 2 # modulo: the remainder of a division by 2.
player_char = symbols[player]
print(greeting.format(turns, player, player_char))
while True: # ask until legal move
command = input(text)
command = command.strip()
if len(command) < 2:
print("Enter 2 coordinates. Try again!")
continue
raw_column, raw_row = command[0], command[-1] # 2 variables, 2 value
try:
row = int(raw_row)
column = int(raw_column)
except ValueError:
print("Enter numbers only. Try again")
continue # go back to the start of the while loop
if is_free(row, column):
print("input accepted\n") # extra new line
cells[row][column] = player_char
break
if check_win(player_char): # only the active player is checked
print(" -*- -*- -*- Congratulation, You have won, player {} -*- -*- -*-".format(player))
display() # final
break
# print("*** next turn! *****")
print("Game Over")
"""tic tac toe for 2 players, extra comfortable for humans """
cells = [[" " for x in range(3)] for y in range(3)] # create a 3 x 3 array
SYMBOLS = ["x", "o"] # ----- some constants, see code discussion
GREETING = "This is turn {}. Player {}, where do you put your '{}'?: >>> "
TEXT = "If asked for coordinates, please enter: column, row\n" \
" like for example: 'A 1' or 'b,2' or 'C3' and press ENTER"
def check_win(char):
"""checks the array cells and returns True if 3 chars build a line"""
for row in range(3): # checking rows
# if cells[row][0] == char and cells[row][1] == char and cells [row][2] == char:
# return True
return cells[row][0:3] == [char, char, char] # horizontal slice, see code discussion
for col in range(3): # checking columns
# if cells[0][col] == char and cells[1][col] == char and cells[2][col] == char:
# return True
return [element[row] for element in cells] == [char, char, char] # vertical slice
# checking diagonal
if cells[0][0] == char and cells[1][1] == char and cells[2][2] == char:
return True
if cells[2][0] == char and cells[1][1] == char and cells[0][2] == char:
return True
return False # all win condition checked without success, therefore no win
def display():
"""displays the 3x3 array 'cells' with heading row and column
human-friendly display: Rows are numbered 1-3, columns are numbered A-C"""
print("\n" + r"r\c A: B: C:") # empty line and header.
for index, row in enumerate(cells): # index starts with 0
print("{}: ".format(index + 1), end="") # no new line at end of print
for element in row: # index starts with 0
print("[{}] ".format(element), end="") # no new line at end of print
print() # print only a new line
print() # empty line after board
def input_checker(user_input):
"""Testing if user_input is a valid and free coordinate
in a 3x3 matrix (rows:1-3,columns: ABC)
returns Error Message as string and None, None (for x and y)
otherwise returns False and x, y as integer values
user_input must be alreay converted by user_input.strip().upper() """
if len(user_input) < 2:
return "Enter 2 coordinates. Try again!", None, None
raw_column = user_input[0]
raw_row = user_input[-1]
if raw_row in ("A", "B", "C") and raw_column in ("1", "2", "3"):
raw_column, raw_row = raw_row, raw_column # swap row with column
if raw_column not in ("A", "B", "C"):
return "Enter A or B or C for column. Try again", None, None
if raw_row not in ("1", "2", "3"):
return "Enter 1 or 2 or 3 for row. Try again", None, None
column = ord(raw_column) - 65 # 'A'=chr(65), 'B'=chr(66) 'C'=chr(67)
row = int(raw_row) - 1
# ---- checking if the coordinate is still free ----
if cells[row][column] != " ":
return "This cell is already occupied. Try again", None, None
return False, column, row
# ---- the 'main' function of the game -----
def game():
print(TEXT)
display()
for turns in range(9): # play 9 legal moves, then the board is full
player = turns % 2 # modulo: the remainder of a division by 2.
player_char = SYMBOLS[player]
while True: # ask until input is acceptable
prompt = GREETING.format(turns + 1, player + 1, player_char)
command = input(prompt).strip().upper()
if command in ("QUIT", "EXIT", "CANCEL", "Q", "BYE"):
return # -> bye bye
error, column, row = input_checker(command)
if error: # errormessage is a string or False
print(error)
continue # ask again
# ----- input accepted, update the game board ------
cells[row][column] = player_char
break # escape the while loop
# -- end of while loop. got acceptable input ---
display()
if check_win(player_char): # only the active player is checked
print("Congratulation, player {} has won!".format(player + 1))
break
# ---- proceed with the next turn -----
else: # ----- for loop has run 9 times without a break ---
print("All nine fields are occupied. It's a draw. No winner")
print("Game Over")
if __name__ == "__main__":
game()
print("bye bye")
first file to make sure all files in this gist have this name
see http://ThePythonGameBook.com:en:python:tictactoe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment