Last active
May 1, 2020 17:04
-
-
Save horstjens/dfcf2c116199d0616e089aa43b9dfde1 to your computer and use it in GitHub Desktop.
ThePythonGameBook-TicTacToe code files
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
board = """ | |
[ ] [ ] [ ] | |
[ ] [ ] [ ] | |
[ ] [ ] [ ]""" | |
print(board) |
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
print("[ ] [ ] [ ]\n" * 3) # all in one-line |
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
"""desired display of board""" | |
board=r""" | |
r\c 0: 1: 2: | |
0: [ ] [ ] [ ] | |
1: [ ] [ ] [ ] | |
2: [ ] [ ] [ ]""" | |
print(board) |
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
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] )) |
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
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() |
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
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)) |
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
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) |
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
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)) |
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
"""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") |
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
"""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") |
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
"""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") |
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
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