# Lab 1 Solution

``"""Lab 1: Solution"""``
``from collections import Counter``
``import random``

``def get_positions(current_board, position_marker):``
``    """Helper fcn to get all locations on board of particular marker``
``       value, specified in position_marker.``
``    """``
``    return [key for (key, value) in current_board.items() if value == position_marker]``

``def visualize_board(game_board):``
``    """Helper function to visualize current state of board, to help check``
``       steps and conclusion of game.``
``    """``
``    print("Current board:")``
``    print(f"""{game_board["top-L"]} | {game_board["top-M"]} | {game_board["top-R"]}""")``
``    print(f"""{game_board["mid-L"]} | {game_board["mid-M"]} | {game_board["mid-R"]}""")``
``    print(f"""{game_board["low-L"]} | {game_board["low-M"]} | {game_board["low-R"]}""")``
``    print()``

``def end_game(game_board, marker, verbose=True):``
``    """Helper function to identify if there's a winner/tie based on current``
``       state of board or not.``
``    """``
``    # --- Step 1: List all positions of given player on board:``
``    player_positions = get_positions(game_board, marker)``
``    # --- Step 2: Parse positions to identify locations and directions:``
``    locations_positions = [x.split('-') for x in player_positions]``
``    locations = [l for [l, d] in locations_positions]``
``    directions = [d for [l, d] in locations_positions]``
``    # --- Step 3: Get counts of positions and locations, to help identify a``
``    #             potential winner:``
``    locations_dict = {v: k for (k, v) in Counter(locations).items()}``
``    directions_dict = {v: k for (k, v) in Counter(directions).items()}``
``    # --- Step 4: Check if end of game, based on stopping criteria:``
``    #             - no more empty locations OR``
``    #             - all 3 end in 'L'/'M'/'R'``
``    #             - all different 'top'/'mid'/'low' and 'L'/'M'/'R'``
``    if ((3 in locations_dict.keys()) | (3 in directions_dict.keys()) | (len(``
``            set(player_positions).intersection(``
``                    set(['top-R', 'mid-M', 'low-L']))) == len(``
``            set(player_positions).intersection(``
``                    set(['top-L', 'mid-M', 'low-R']))) == 3)):``
``        if verbose:``
``            print(f"{marker} is winner")``
``        return True``
``    elif not get_positions(game_board, " "):``
``        if verbose:``
``            print("tie")``
``        return True``
``    else:``
``        return False``

``if __name__ == '__main__':``
``    random.seed(2019)``
``    # --- Start with empty board:``
``    board = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',``
``             'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',``
``             'low-L': ' ', 'low-M': ' ', 'low-R': ' '``
``            }``
``    visualize_board(board)``
``    player_marker = "X"``
``    # --- Let each player take turns placing Xs and Os on board, until``
``    #     one is the winner or there's a tie:``
``    while not end_game(board, player_marker, verbose=True):``
``        for player_marker in {"X", "O"}:``
``            selected_position = random.choice(``
``                get_positions(board, position_marker=' '))``
``            board[selected_position] = player_marker``
``            visualize_board(board)``
``            if end_game(board, player_marker, verbose=False):``
``                break``