We give you the main function, and basic board setup.You have to write the brains inside the box!As always, attempt to program the functions in the order we give them.Do not attempt to program the second funtion until the first one is passing, or the third until the second is passing, etc.Dots and boxes is a classic mathy game. To see how to play, read this diagram left to right, row by row:
Usage: ksquares.py """ from typing import List, TextIO, Tuple, Callable import docopt # type: ignore class Box: """This class exists primarily to override the [] operator""" def __init__( self, l: bool = False, r: bool = False, u: bool = False, d: bool = False, owner: str = " ", ) -> None: """ Purpose: Initializes a box False - unmarked, True - marked Parameters: Each side as a bool, player-owner Input: None Prints: Nothing Returns: None Modifies: Creates a box instance, with members: left, right, up, down, owner Calls: basic python Tests: 01_class_box.py Usage: >>> a_box = Box(True, True, True, False, "C") >>> a_box.left True >>> a_box.down False >>> a_box.owner 'C' """ pass def __getitem__(self, key: str) -> bool: """ Purpose: Overloads get bracket operator [] for Box Parameters: key (direction) as L, R, U, or D Input: None Prints: Nothing Returns: bool (the relevant side of the box) Modifies: Nothing Calls: Basic python Tests: 01_class_box.py Usage: >>> a_box = Box(True, True, True, False, "C") >>> a_box["R"] True """ pass def __setitem__(self, key: str, value: bool) -> None: """ Purpose: Overloads set bracket operator [] for Box Parameters: key (direction) as L, R, U, or D, bool to set side as Input: None Prints: Nothing Returns: None Modifies: Instance of a Box Calls: Basic python Tests: 01_class_box.py Usage: >>> a_box = Box(True, True, True, False, "C") >>> a_box["R"] True >>> a_box["R"] = False >>> a_box["R"] False """ pass class Player: def __init__(self, name: str, human: bool = True, score: int = 0) -> None: """ Purpose: Initializes an instance of a player Parameters: name as string, bool for human or computer, int to keep track of score Input: None Prints: Nothing Returns: None Modifies: Creates an instance of a player, with members: name, human, score Calls: Basic python Tests: 02_class_player.py Usage: >>> your_player = Player('h', human=True) >>> your_player.name 'h' >>> your_player.human True """ pass Board = List[List[Box]] def build_board(config: List[str]) -> Board: """ Purpose: Build the initial board state as a List of List of Boxes Parameters: config string, List of strings, one line per element Input: None Prints: None Returns: a Board, a matrix describing the game state, a List[List[Box]] Modifies: None Calls: None Tests: We give you this one. Usage: >>> board: Board = build_board(['1 1', '1 1 1 1']) """ board: Board = [] rows, cols = map(int, config[0].split()) incnt = 1 for irow in range(rows): rowList: List[Box] = [] for icol in range(cols): box: List[int] = list(map(int, config[incnt].split())) incnt += 1 l, r, u, d = map(bool, box) rowList.append(Box(l, r, u, d)) board.append(rowList) return board class Game: def __init__(self, board: Board, player1: Player, player2: Player) -> None: """ Purpose: Initializes an instance of a Game Parameters: the pre-build board, two Player instances Input: None Prints: Nothing Returns: None Modifies: Creates a Game instance, with some class members: board player1 player2 turn starting at 0 rows cols Calls: Basic python Tests: 03_class_game.py Usage: >>> test_board = [[Box(True, False, True, True), Box(False, False, False, True)], [Box(False, False, True, True), Box(False, True, True, True)]] >>> a_game = Game(test_board, Player("S"), Player("T")) >>> a_game.board == test_board True >>> a_game.player1.name == "S" True >>> a_game.turn == 0 True >>> a_game.rows == 2 and a_game.cols == 2 True """ pass def __str__(self) -> str: """ Purpose: Displays the current game-state Parameters: self, which can access the Board in the Game instance Input: None Prints: None (this function is for printing though...) Returns: The board with lines representing the moves made thusfar (see usage) completed squares should indicate which player completed them Modifies: None Calls: None Tests: 04_print_game.py Usage: >>> test_board = [[Box(True, False, True, True, "S"), Box(False, False, False, True)], [Box(False, False, True, True), Box(False, True, True, True, "T")]] >>> a_game = Game(test_board, Player("S"), Player("T")) >>> a_game.__str__() '\\n o---o o\\n | S \\n o---o---o\\n T |\\n o---o---o' """ pass def box_complete(self, row: int, col: int) -> bool: """ Purpose: Checks if a given square is completed, (left, right, up, down are all marked True) Parameters: the board, a row, and a column. The row/col indicating position of the square Input: None Prints: None Returns: True if the square is complete, else False Modifies: None Calls: None Tests: 06_box_complete.py Usage: >>> test_board = [[Box(True, True, True, True), Box(False, False, False, True)], [Box(False, False, True, True), Box(False, True, True, True)]] >>> a_game = Game(test_board, Player("S"), Player("T")) >>> a_game.box_complete(0, 0) True >>> a_game.box_complete(1, 0) False """ pass def player_move(self, player: Player, row: int, col: int, direction: str) -> bool: """ Purpose: Modifies game when player makes a move Parameters: The board, the player making the move, the move as row/col/dir Input: None Prints: None Returns: True if player completes a square, otherwise False, and False when the game is over. Modifies: board (updated according to move), player score Calls: basic python, is_game_on, box_complete Tests: 08_player_move.py Usage: >>> test_board = [[Box(True, True, True, True), Box(True, False, False, True)], [Box(False, False, True, True), Box(False, True, True, True)]] >>> a_game = Game(test_board, Player("S"), Player("T")) >>> a_game.player_move(a_game.player1, 0, 1, "R") False >>> a_game.player1.score == 0 True >>> a_game.player_move(a_game.player1, 0, 1, "U") True >>> a_game.player1.score == 1 True """ pass def is_game_on(self) -> bool: """ Purpose: Determines if the current game-state is still ongoing Parameters: self, which can access the Board Input: None Prints: None Returns: True if the game is over (no more moves can be played) else False Modifies: None Calls: None Tests: 07_is_game_on.py Usage: >>> test_board1 = [[Box(False, True, True, True), Box(True, False, False, False)], [Box(False, False, True, False), Box(False, False, False, False)]] >>> testG1 = Game(test_board1, Player(name="S", score=0), Player(name="T", score=0)) >>> testG1.is_game_on() True >>> test_board2 = [[Box(True, True, True, True, owner="S"), Box(True, True, True, True, owner="S")], [Box(True, True, True, True, owner="S"), Box(True, True, True, True, owner="T")]] >>> testG2 = Game(test_board2, Player(name="S", score=3), Player(name="T", score=1)) >>> testG2.is_game_on() False """ pass def evaluate_move(self, row: int, col: int, direction: str) -> int: """ Purpose: evaluates square of move, and potentially impacted neighbor higher return value = worse move Parameters: row, col, dir for move Input: None Prints: Nothing Returns: -1 -> a square is now complete 0 -> leaves 1 walls completed 1 -> leaves 2 wall completed 2 -> leaves 3 walls completed 3 -> the move is illegal Modifies: Nothing Calls: Basic python Tests: 09_evaluate_move.py Usage: >>> test_board = [[Box(False, True, True, True), Box(True, False, False, False)], [Box(False, False, True, True), Box(False, False, False, False)]] >>> testG = Game(test_board, Player(name="S"), Player(name="T")) >>> testG.evaluate_move(0, 0, "L") -1 >>> testG.evaluate_move(0, 1, "R") 1 >>> testG.evaluate_move(1, 1, "R") 0 >>> testG.evaluate_move(1, 1, "L") 2 >>> testG.evaluate_move(0, 0, "U") 3 """ pass def get_computer_move(self) -> Tuple[int, int, str]: """ Purpose: Computer AI, evaluate all moves to pick "best", with ties broken by lowest row -> lowest col -> LRUD order Parameters: self, which has access to Game and its internals Input: None Prints: Nothing Returns: Move to complete a square, or the 'worst case' from either affected square if it can't complete a square Modifies: Nothing Calls: evaluate_move, basic python Tests: 10_get_computer_move.py Usage: >>> test_board = [[Box(True, False, True, True), Box(False, False, False, True)], [Box(False, False, True, True), Box(False, True, True, True)]] >>> testG = Game(test_board, Player(name="S"), Player(name="T")) >>> row, col, direction = testG.get_computer_move() >>> row 0 >>> col 0 >>> direction 'R' """ pass def validate_move(self, row: int, col: int, direction: str) -> bool: """ Purpose: Checks move is on the board, and not taken already Parameters: move as row, col, dir, self has access to Game Input: None Prints: Nothing Returns: a bool, True if valid, False if not Modifies: Nothing Calls: basic Python Tests: 05_validate_move.py Usage: >>> test_board = [[Box(False, False, True, True), Box(False, True, True, True)], [Box(True, True, True, True), Box(True, False, True, False)]] >>> testG = Game(test_board, Player("S"), Player("T")) >>> testG.validate_move(0, 0, "L") True >>> testG.validate_move(0, 0, "D") False """ pass def main() -> None: """ Purpose: Main driver Parameters: None Input: Yes, file-based and stdio based Prints: Yes Returns: None Modifies: All kinds of stuff! Calls: All your functions, basic python Tests: We give this one to you """ args = docopt.docopt(__doc__) with open(args[""]) as fhand: config: List[str] = fhand.readlines() board: Board = build_board(config) num_human_players: int = -1 player1_name: str = "" player2_name: str = "" while num_human_players 1 or num_human_players > 2: num_human_players = int(input("How many humans are playing? 1 or 2: ")) while len(player1_name) != 1: player1_name = input("Enter initial of player 1 (one-character): ") player_one: Player = Player(player1_name) while len(player2_name) != 1 or player2_name == player1_name: player2_name = input("Enter a initial of the computer (one-character): ") if num_human_players == 1: player_two: Player = Player(player2_name, human=False) else: player_two = Player(player2_name, human=True) my_game: Game = Game(board, player_one, player_two) print("Starting board state is:") print(my_game) players: List[Player] = [player_one, player_two] get_player_move: Callable[[Player], Tuple[int, int, str]] = lambda player: ( int(input(f"Player {player.name}, enter a row: ")), int(input(f"Player {player.name}, enter a column: ")), input(f"Player {player.name}, enter a direction (L,R,U,D): ").upper(), ) while my_game.is_game_on(): curr_player: Player = players[my_game.turn % 2] extra_turn: bool = True while extra_turn: print(f"\n======== Turn number: {my_game.turn} ========") if curr_player.human: entity_move = get_player_move(curr_player) while not my_game.validate_move(*entity_move): print("\nINVALID MOVE.\n") entity_move = get_player_move(curr_player) else: print("Computer thinking...") entity_move = my_game.get_computer_move() print( f"Player {curr_player.name}'s move was ({entity_move[0]}, {entity_move[1]}, {entity_move[2]}):" ) extra_turn = my_game.player_move(curr_player, *entity_move) print(my_game) my_game.turn += 1 print("\n======== GAME OVER ========") print(f"Player {player1_name} had {player_one.score} points") print(f"Player {player2_name} had {player_two.score} points") if player_one.score > player_two.score: print("Player " + player1_name + " wins!") elif player_one.score player_two.score: print("Player " + player2_name + " wins!") else: print("It's a tie!") if __name__ == '__main__': main()