# Please always run this code block.
%config InteractiveShell.ast_node_interactivity="none"
%pip install termcolor
import base64
import termcolor
# Defines print_locals
code="ZGVmIG1ha2VfcHJpbnRfbG9jYWxzKCk6IAogICMgSW4gYSBmdW5jdGlvbiB0byBwcmV2ZW50IGxvY2FscyBhbmQgaW1wb3J0cyBmcm9tIGxlYWtpbmcuCiAgICBnbG9iYWwgbWFrZV9wcmludF9sb2NhbHMKICAgIGRlbCBtYWtlX3ByaW50X2xvY2FscyAgIyBPbmx5IHJ1biB0aGlzIGZ1bmN0aW9uIG9uY2UuCgogICAgaW1wb3J0IElQeXRob24KICAgIGltcG9ydCBhc3QKICAgIGltcG9ydCBpbnNwZWN0CgogICAgY2xhc3MgVmlzaXRvcihhc3QuTm9kZVZpc2l0b3IpOgogICAgICAgIGRlZiBfX2luaXRfXyhzZWxmKToKICAgICAgICAgICAgc2VsZi52YXJpYWJsZXMgPSBzZXQoKQogICAgICAgIGRlZiB2aXNpdF9OYW1lKHNlbGYsIG5hbWUpOgogICAgICAgICAgICBzZWxmLnZhcmlhYmxlcy5hZGQobmFtZS5pZCkKICAgICAgICAjIFRPRE86IFBvc3NpYmx5IGRldGVjdCB3aGV0aGVyIHZhcmlhYmxlcyBhcmUgYXNzaWduZWQgdG8uCgogICAgQUxMT1dfVFlQRVMgPSBbaW50LCBmbG9hdCwgc3RyLCBib29sLCBsaXN0LCBkaWN0LCB0dXBsZSwgcmFuZ2VdCiAgICBkZWYgZmlsdGVyX3ZhcmlhYmxlcyh2YXJpYWJsZXMsIGxvY2Fscyk6CiAgICAgICAgZm9yIHYgaW4gdmFyaWFibGVzOgogICAgICAgICAgICBpZiB2IGluIGxvY2FscyBhbmQgdHlwZShsb2NhbHNbdl0pIGluIEFMTE9XX1RZUEVTOgogICAgICAgICAgICAgICAgeWllbGQgdgogIAogICAgIyBVbmZvcnR1bmF0ZWx5LCB0aGVyZSBkb2Vzbid0IHNlZW0gdG8gYmUgYSBzdXBwb3J0ZWQgd2F5IG9mIGdldHRpbmcKICAgICMgdGhlIGN1cnJlbnQgY2VsbCdzIGNvZGUgdmlhIHRoZSBwdWJsaWMgSVB5dGhvbiBBUElzLiBIb3dldmVyLCBiZWNhdXNlCiAgICAjIHdlIGFyZSBnZXR0aW5nIGNhbGxlZCBmcm9tIElQeXRob24gaXRzZWxmIGFuZCB3ZSBhcmUgYWxyZWFkeSBpbnNwZWN0aW5nCiAgICAjIHRoZSBzdGFja3RyYWNlLCB3ZSBtaWdodCBhcyB3ZWxsIGp1c3QgcGVlayBpbnRvIGl0cyBmcmFtZS4uLgogICAgaWYgSVB5dGhvbi5fX3ZlcnNpb25fXyA9PSAiNS41LjAiOgogICAgICAgICMgY29sYWIKICAgICAgICBkZWYgZ2V0X2FzdChmcmFtZSk6CiAgICAgICAgICAgIHJldHVybiBhc3QuTW9kdWxlKGZyYW1lLmZfYmFjay5mX2JhY2suZl9sb2NhbHNbIm5vZGVsaXN0Il0pCiAgICAgICAgZGVmIGZpbmRfbG9jYWxzKGZyYW1lKToKICAgICAgICAgICAgc2hlbGwgPSBmcmFtZS5mX2JhY2suZl9iYWNrLmZfbG9jYWxzWyJzZWxmIl0KICAgICAgICAgICAgcmV0dXJuIHNoZWxsLnVzZXJfbnMKICAgIGVsaWYgSVB5dGhvbi5fX3ZlcnNpb25fXyA9PSAiOC40LjAiOgogICAgICAgICMgbGFiIGNvbXB1dGVycwogICAgICAgIGRlZiBnZXRfYXN0KGZyYW1lKToKICAgICAgICAgICAgcmV0dXJuIGFzdC5Nb2R1bGUoZnJhbWUuZl9iYWNrLmZfYmFjay5mX2xvY2Fsc1sibm9kZWxpc3QiXSkKICAgICAgICBkZWYgZmluZF9sb2NhbHMoZnJhbWUpOgogICAgICAgICAgICByZXR1cm4gZnJhbWUuZl9sb2NhbHMKICAgIGVsc2U6CiAgICAgICAgcHJpbnQoZiJwcmludF9sb2NhbHMoKSBub3Qgc3VwcG9ydGVkIG9uIElQeXRob24gdmVyc2lvbiB7SVB5dGhvbi5fX3ZlcnNpb25fX30iKQoKICAgIGRlZiBnZXRfY2VsbF9uYW1lcyhmcmFtZSk6CiAgICAgICAgdHJlZSA9IGdldF9hc3QoZnJhbWUpCiAgICAgICAgdmlzaXRvciA9IFZpc2l0b3IoKQogICAgICAgIHZpc2l0b3IudmlzaXQodHJlZSkKICAgICAgICByZXR1cm4gZmlsdGVyX3ZhcmlhYmxlcyh2aXNpdG9yLnZhcmlhYmxlcywgZnJhbWUuZl9sb2NhbHMpCgogICAgZGVmIGZpbmRfd2hpY2goZnJhbWUpOgogICAgICAgICMgRnJhbWUgaXMgdGhlIGZyYW1lIHdob3NlIGxvY2FscyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBwcmludGluZy4KICAgICAgICBpZiBpbnNwZWN0LmdldG1vZHVsZW5hbWUoZnJhbWUuZl9iYWNrLmZfY29kZS5jb19maWxlbmFtZSkgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICMgVGhlIHBhcmVudCBmcmFtZSBvZiB0aGUgaW50ZXJlc3RlZCBmcmFtZSBpcyBhIG1vZHVsZSwgbW9zdCBsaWtlbHkKICAgICAgICAgICAgIyAiaW50ZXJhY3RpdmVzaGVsbCIuIFRoaXMgbWVhbnMgd2UgYXJlIGluIHRoZSBnbG9iYWwgc2NvcGUsIHNpbmNlCiAgICAgICAgICAgICMgb25seSB0aGUgZ2xvYmFsIHNjb3BlIHNob3VsZCBiZSBkaXJlY3RseSBydW4gYnkgdGhlIGludGVyYWN0aXZlIHNoZWxsLgogICAgICAgICAgICByZXR1cm4gc2V0KGdldF9jZWxsX25hbWVzKGZyYW1lKSkKICAgICAgICAjIFRoZSBwYXJlbnQgZnJhbWUgaXMgbm90IGEgbW9kdWxlLCBzbyB3ZSBhcmUgaW4gYSBsb2NhbCBzY29wZS4KICAgICAgICByZXR1cm4gc2V0KGZyYW1lLmZfbG9jYWxzKQoKICAgIGRlZiBwcmludF9sb2NhbHMoKndoaWNoLCB0eXBlcz1GYWxzZSk6CiAgICAgICAgIiIiUHJpbnQgdGhlIGxvY2FsIHZhcmlhYmxlcyBpbiB0aGUgY2FsbGVyJ3MgZnJhbWUuIiIiCiAgICAgICAgaW1wb3J0IGluc3BlY3QKICAgICAgICAjIGN1cnJlbnRmcmFtZSgpIGZyYW1lIGlzIHByaW50X2xvY2Fscy4gV2Ugd2FudCB0aGUgY2FsbGVyJ3MgZnJhbWUKICAgICAgICBmcmFtZSA9IGluc3BlY3QuY3VycmVudGZyYW1lKCkuZl9iYWNrCiAgICAgICAgbG9jYWxzID0gZmluZF9sb2NhbHMoZnJhbWUpCiAgICAgICAgd2hpY2ggPSBzZXQod2hpY2gpIGlmIHdoaWNoIGVsc2UgZmluZF93aGljaChmcmFtZSkKICAgICAgICBsbCA9IHtrOiB2IGZvciBrLCB2IGluIGxvY2Fscy5pdGVtcygpIGlmIGsgaW4gd2hpY2h9CiAgICAgICAgaWYgdHlwZXM6CiAgICAgICAgICAgIHByaW50KCJcbiIuam9pbihmIntrfToge3R5cGUodikuX19uYW1lX199IOKGkCB7dn0iIGZvciBrLCB2IGluIGxsLml0ZW1zKCkpKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHByaW50KCI7ICIuam9pbihmIntrfSDihpAge3Z9IiBmb3IgaywgdiBpbiBsbC5pdGVtcygpKSkKCiAgICByZXR1cm4gcHJpbnRfbG9jYWxzCgpwcmludF9sb2NhbHMgPSBtYWtlX3ByaW50X2xvY2Fscygp"
exec(base64.b64decode(code), globals(), locals())
del code
EMPTY_TILE = 0
X_PIECE = 1
O_PIECE = 2
NO_WINNER = "NO_WINNER"
In part two, we programmed part of this week's final project: Connect Four 🎉. Here are the signatures of some of the functions you implemented there:
def print_board(board):
"""Prints a visual representation of the board.
Input: board (list of lists of ints).
Output: (None)
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
def get_piece(board, row, column):
"""Retrieves the piece at the given row and column in the board.
Input: board (list of lists of ints), row (int), column (int).
Output: piece (int)
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
def set_piece(board, row, column, piece):
"""Sets the piece on the board at the given row and column.
Input: board (list of lists of ints), row (int), column (int), piece (int).
Output: (None)
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
def update_board(board, column, piece):
"""Updates the board as if a player dropped piece into the given column.
If there is no empty tile in that column, does not change the board.
Input: board (list of lists of ints), column (int), piece (int).
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
# Defines functions implemented in part 2.
code = "ZGVmIGdldF9waWVjZShib2FyZCwgcm93LCBjb2x1bW4pOgogICAgIiIiUmV0cmlldmVzIHRoZSBwaWVjZSBhdCB0aGUgZ2l2ZW4gcm93IGFuZCBjb2x1bW4gaW4gdGhlIGJvYXJkLiIiIgogICAgIyBZT1VSIENPREUgSEVSRQogICAgcmV0dXJuIGJvYXJkWy1yb3ctMV1bY29sdW1uXQoKCmRlZiBzZXRfcGllY2UoYm9hcmQsIHJvdywgY29sdW1uLCBwaWVjZSk6CiAgICAiIiJTZXRzIHRoZSBwaWVjZSBvbiB0aGUgYm9hcmQgYXQgdGhlIGdpdmVuIHJvdyBhbmQgY29sdW1uLiIiIgogICAgIyBZT1VSIENPREUgSEVSRQogICAgYm9hcmRbLXJvdy0xXVtjb2x1bW5dID0gcGllY2UKCmRlZiB1cGRhdGVfYm9hcmQoYm9hcmQsIGNvbHVtbiwgcGllY2UpOgogICAgIiIiVXBkYXRlcyB0aGUgYm9hcmQgYXMgaWYgYSBwbGF5ZXIgZHJvcHBlZCBwaWVjZSBpbnRvIHRoZSBnaXZlbiBjb2x1bW4uCiAgICAKICAgIElmIHRoZXJlIGlzIG5vIGVtcHR5IHRpbGUgaW4gdGhhdCBjb2x1bW4sIGRvZXMgbm90IGNoYW5nZSB0aGUgYm9hcmQuCiAgICAiIiIKICAgICMgWU9VUiBDT0RFIEhFUkUKICAgIGZvciByb3cgaW4gcmFuZ2UobGVuKGJvYXJkKSk6CiAgICAgICAgaWYgZ2V0X3BpZWNlKGJvYXJkLCByb3csIGNvbHVtbikgPT0gRU1QVFlfVElMRToKICAgICAgICAgICAgc2V0X3BpZWNlKGJvYXJkLCByb3csIGNvbHVtbiwgcGllY2UpCiAgICAgICAgICAgIHJldHVybgoKZGVmIHByaW50X3RpbGUodGlsZSk6CiAgICAiIiJHaXZlbiBhIG51bWVyaWNhbCB0aWxlLCBwcmludHMgaXRzIHZpc3VhbCByZXByZXNlbnRhdGlvbi4iIiIKICAgIGlmIHRpbGUgPT0gRU1QVFlfVElMRToKICAgICAgICAjIE5vIGNvbG9yaW5nIGhlcmUgYmVjYXVzZSB3ZSBkb24ndCBrbm93IGlmIGl0J3MgCiAgICAgICAgcHJpbnQoIsK3IiwgZW5kID0gJycpCiAgICBlbGlmIHRpbGUgPT0gWF9QSUVDRToKICAgICAgICBwcmludCh0ZXJtY29sb3IuY29sb3JlZCgnWCcsICdyZWQnKSwgZW5kID0gJycpCiAgICBlbGlmIHRpbGUgPT0gT19QSUVDRToKICAgICAgICBwcmludCh0ZXJtY29sb3IuY29sb3JlZCgnTycsICdibHVlJyksIGVuZCA9ICcnKQogICAgZWxzZToKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoZiJFcnJvcjogdGhlIHRpbGUgZ2l2ZW4gd2FzIG5vdCAwLCAxLCBvciAyIChnb3Qge3RpbGV9KSIpCgpkZWYgcHJpbnRfYm9hcmRfY29vcmRzKGJvYXJkKToKICAgIGZvciBpLCByb3cgaW4gZW51bWVyYXRlKGJvYXJkKToKICAgICAgICBwcmludChsZW4oYm9hcmQpIC0gaSAtIDEsIGVuZD0iICIpCiAgICAgICAgZm9yIHRpbGUgaW4gcm93OgogICAgICAgICAgICBwcmludF90aWxlKHRpbGUpCiAgICAgICAgICAgIHByaW50X3NwYWNlKCkKICAgICAgICBwcmludCgpCgogICAgaWYgbGVuKGJvYXJkKSA+IDA6CiAgICAgICAgbnVtX2l0ZW1zID0gbGVuKGJvYXJkWzBdKQogICAgICAgIHByaW50X3NwYWNlKCkKICAgICAgICBwcmludF9zcGFjZSgpCiAgICAgICAgcHJpbnQoIiAiLmpvaW4oc3RyKGkpIGZvciBpIGluIHJhbmdlKG51bV9pdGVtcykpKQoKCmRlZiBwcmludF9zcGFjZSgpOgogICAgIiIiUHJpbnRzIGEgc3BhY2UsIHdpdGhvdXQgcHJpbnRpbmcgYSBuZXcgbGluZS4iIiIKICAgIHByaW50KCcgJywgZW5kPScnKQ=="
exec(base64.b64decode(code), globals(), locals())
del code
print_board = print_board_coords
One important thing a game does is check if there is a winner. In Connect Four, there is a winner if there are four pieces that belong to the same player that are connected vertically, diagonally, or horizontally.
We have implemented the code for checking vertical and diagonal checks, as well as a function, check_winner
, that calls functions for all directions for you. For reference, here are the function skeletons for
check_vertical_winner
check_back_diagonal_winner
check_forward_diagonal_winner
check_winner
You do not need to modify or edit these functions; they are here for your reference.
def check_vertical_winner(board):
"""Check whether a player won by *vertically* connecting four pieces.
Input: board (list of lists of ints).
Output: X_PIECE, O_PIECE, or NO_WINNER.
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
def check_back_diagonal_winner(board):
"""Check whether a player won by *diagonally* connecting four pieces going down and right (\).
Input: board (list of lists of ints).
Output: X_PIECE, O_PIECE, or NO_WINNER.
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
def check_forward_diagonal_winner(board):
"""Check whether a player won by *diagonally* connecting four pieces going down and left (/).
Input: board (list of lists of ints).
Output: X_PIECE, O_PIECE, or NO_WINNER.
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
# <Function Contents Hidden>
def check_winner(board):
"""Check whether a player won by connecting four pieces vertically,
horizontally, or diagonally.
Input: board (list of lists of ints).
Output: X_PIECE, O_PIECE, or NO_WINNER.
"""
# You do not need to edit the contents or signature of this function. We have defined it for you.
vertical_winner = check_vertical_winner(board)
if vertical_winner != NO_WINNER:
return vertical_winner
back_diagonal_winner = check_back_diagonal_winner(board)
if back_diagonal_winner != NO_WINNER:
return back_diagonal_winner
forward_diagonal_winner = check_forward_diagonal_winner(board)
if forward_diagonal_winner != NO_WINNER:
return forward_diagonal_winner
horizontal_winner = check_horizontal_winner(board)
if horizontal_winner != NO_WINNER:
return horizontal_winner
return NO_WINNER
# Defines check vertical and diagonal winners.
code = "ZGVmIG1ha2VfY2hlY2tfd2lubmVyKHNlcSk6CiAgICBkZWYgY2hlY2tfd2lubmVyKGJvYXJkKToKICAgICAgICBoZWlnaHQgPSBsZW4oYm9hcmQpCiAgICAgICAgaWYgaGVpZ2h0ID09IDA6CiAgICAgICAgICAgIHJldHVybiBOT19XSU5ORVIKICAgICAgICB3aWR0aCA9IGxlbihib2FyZFswXSkKCiAgICAgICAgZm9yIHJvdyBpbiByYW5nZShoZWlnaHQpOgogICAgICAgICAgICBmb3IgY29sIGluIHJhbmdlKHdpZHRoKToKICAgICAgICAgICAgICAgIHN0YXJ0ID0gZ2V0X3BpZWNlKGJvYXJkLCByb3csIGNvbCkKICAgICAgICAgICAgICAgIGZvciBkciwgZGMgaW4gc2VxOgogICAgICAgICAgICAgICAgICAgIGlmIG5vdCAoMCA8PSByb3cgKyBkciA8IGhlaWdodCk6CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgICAgICAgICAgaWYgbm90ICgwIDw9IGNvbCArIGRjIDwgd2lkdGgpOgogICAgICAgICAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAgICAgICAgIGlmIHN0YXJ0ICE9IGdldF9waWVjZShib2FyZCwgcm93ICsgZHIsIGNvbCArIGRjKToKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgaWYgc3RhcnQgIT0gRU1QVFlfVElMRToKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHN0YXJ0CiAgICAgICAgcmV0dXJuIE5PX1dJTk5FUgogICAgcmV0dXJuIGNoZWNrX3dpbm5lcgoKY2hlY2tfdmVydGljYWxfd2lubmVyID0gbWFrZV9jaGVja193aW5uZXIoWygtMSwgMCksICgtMiwgMCksICgtMywgMCldKQpjaGVja19iYWNrX2RpYWdvbmFsX3dpbm5lciA9IG1ha2VfY2hlY2tfd2lubmVyKFsoLTEsIC0xKSwgKC0yLCAtMiksICgtMywgLTMpXSkKY2hlY2tfZm9yd2FyZF9kaWFnb25hbF93aW5uZXIgPSBtYWtlX2NoZWNrX3dpbm5lcihbKC0xLCAxKSwgKC0yLCAyKSwgKC0zLCAzKV0p"
exec(base64.b64decode(code), globals(), locals())
del code
Now your job is to complete the function check_horizontal_winner
, which checks whether the board has a horizontal winner.
Hint: You may assume that the board is 4 by 4, and you may want to use the get_piece
function we defined in the previous part. The definition of the get_piece
function is above).
def check_horizontal_winner(board):
"""Check whether a player won by *horizontally* connecting four pieces.
Input: board (list of lists of ints).
Output: X_PIECE, O_PIECE, or NO_WINNER.
"""
# YOUR CODE HERE
return NO_WINNER
Here we'll implement the logic to run the game. To help you, we've implemented some functions. You should NOT edit these functions, and you don't need to understand how they work; just what arguments they take and return.
The functions:
player_symbol
:
player_symbol
takes in either X_PIECE
or O_PIECE
and returns the corresponding string 'X'
or 'O'
. We use it for printing more easily.get_input
get_input
takes in a variable next_player
which is either X_PIECE
or O_PIECE
, and prompts the user to choose a column for their next turn.int
then it will print a message and ask for them to try again.def player_symbol(player_id):
"""Given a player, returns the symbol of that player.
Input: player_id (X_PIECE or O_PIECE)
Output: (X_PIECE or O_PIECE)
"""
# Do not modify this function.
if player_id == X_PIECE:
return 'X'
elif player_id == O_PIECE:
return 'O'
assert False, f"No player with id {player_id}"
def get_input(current_player):
"""Gets input (a move) from the current player.
Input: current_player (X_PIECE or O_PIECE)
Output: column (int)
"""
# Do not modify this function.
#
# You are not expected to understand how this function works,
# so don't worry if you don't.
player_str = player_symbol(current_player)
column = None
while column is None:
print(f"It is player {player_str}'s turn.")
column_str = input(f"Choose the column to place a piece (enter an int): ")
try:
column = int(column_str)
except:
print("That was not an integer, please try again")
print(f"Player {player_str} chose {column}")
return column
run_game
, which takes two input variables:¶board
which is the current state of a gamenext_player
which is either X_PIECE
or O_PIECE
This function uses a while
loop to repeatedly:
get_input
If there is no winner, the process should repeat until there is a winner.
Your job is to complete this function by filling in the blanks _________
from IPython.display import clear_output
# This helper function takes in a player, and returns the opposite player
def other_player(current_player):
"""Given the current player, returns the other player
Input: current_player (X_PIECE or O_PIECE)
Output: (X_PIECE or O_PIECE)
"""
if current_player == X_PIECE:
return O_PIECE
elif current_player == O_PIECE:
return X_PIECE
### REPLACE blank spaces like this below: _________
def run_game(board, current_player):
winner = NO_WINNER
while winner == _________: # YOUR CODE HERE
# get the next input from the next player
print_board(board)
column = get_input(current_player)
_________(board, column, current_player). # YOUR CODE HERE
clear_output(wait=True)
winner = _________(board) # YOUR CODE HERE
current_player = _________ # YOUR CODE HERE
# Because we exited the while loop, we know that there is a winner.
print_board(board)
player_str = player_symbol(winner)
print(f"Player {winner} won the game!")
def start_new_game():
board = []
for i in range(4):
board += [0] * 4
run_game(board, X_PIECE)
start_new_game()