JamCoders

💾 Download
In [1]:
# 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"
Requirement already satisfied: termcolor in /opt/conda/lib/python3.10/site-packages (1.1.0)
Note: you may need to restart the kernel to use updated packages.

The story so far...

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:

In [2]:
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

3. Check winner

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

  1. check_vertical_winner
  2. check_back_diagonal_winner
  3. check_forward_diagonal_winner
  4. check_winner

You do not need to modify or edit these functions; they are here for your reference.

In [3]:
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).

In [4]:
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

4. The game loop

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:

  • The function 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

  • The function 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.
  • If the user doesn't input an int then it will print a message and ask for them to try again.
In [ ]:
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

4. The game loop

The next step is to complete the function run_game, which takes two input variables:

  • board which is the current state of a game
  • next_player which is either X_PIECE or O_PIECE

This function uses a while loop to repeatedly:

  1. Print the board
  2. Ask the next player to choose their next turn by calling get_input
  3. Update the board with their choice
  4. Clear the output
  5. Check if there is a winner, and if there is, display who won and end the game

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 _________

In [ ]:
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!")

5. A Working Game

Let's put it all together with a function called start_game

First, this function creates a new, empty board

Second, it calls run_game(board, X_PIECE) to start the gameplay with Player X.

In [ ]:
def start_new_game():
    board = []
    for i in range(4):
        board += [0] * 4
    run_game(board, X_PIECE)

start_new_game()