mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-29 22:21:42 -08:00
Use docstrings
This commit is contained in:
@@ -1,17 +1,14 @@
|
||||
import random
|
||||
import re
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
###################
|
||||
#
|
||||
# static variables
|
||||
#
|
||||
###################
|
||||
BoardType = List[List[Optional[int]]]
|
||||
CoordinateType = Tuple[int, int]
|
||||
|
||||
BOARD_WIDTH = 10
|
||||
BOARD_HEIGHT = 10
|
||||
|
||||
# game ships
|
||||
#
|
||||
|
||||
# data structure keeping track of information
|
||||
# about the ships in the game. for each ship,
|
||||
# the following information is provided:
|
||||
@@ -35,26 +32,21 @@ VALID_MOVES = [
|
||||
[1, 0], # South
|
||||
[1, -1], # South West
|
||||
[0, -1], # West
|
||||
[-1, -1],
|
||||
] # North West
|
||||
[-1, -1], # North West
|
||||
]
|
||||
|
||||
COORD_REGEX = "[ \t]{0,}(-?[0-9]{1,3})[ \t]{0,},[ \t]{0,}(-?[0-9]{1,2})"
|
||||
|
||||
####################
|
||||
#
|
||||
# global variables
|
||||
#
|
||||
####################
|
||||
|
||||
# array of BOARD_HEIGHT arrays, BOARD_WIDTH in length,
|
||||
# representing the human player and computer
|
||||
player_board = []
|
||||
computer_board = []
|
||||
player_board: BoardType = []
|
||||
computer_board: BoardType = []
|
||||
|
||||
# array representing the coordinates
|
||||
# for each ship for player and computer
|
||||
# array is in the same order as SHIPS
|
||||
computer_ship_coords = []
|
||||
computer_ship_coords: List[List[CoordinateType]] = []
|
||||
|
||||
|
||||
####################################
|
||||
@@ -88,10 +80,9 @@ num_player_shots = 7
|
||||
#
|
||||
####################################
|
||||
|
||||
# flag indicating whose turn
|
||||
# it currently is
|
||||
COMPUTER = 0
|
||||
PLAYER = 1
|
||||
# flag indicating whose turn it currently is
|
||||
COMPUTER = False
|
||||
PLAYER = True
|
||||
active_turn = COMPUTER
|
||||
|
||||
####################
|
||||
@@ -108,26 +99,27 @@ random.seed()
|
||||
|
||||
# random_x_y
|
||||
#
|
||||
# generate a valid x,y coordinate on the board
|
||||
# returns: x,y
|
||||
# x: integer between 1 and BOARD_HEIGHT
|
||||
# y: integer between 1 and BOARD WIDTH
|
||||
def random_x_y():
|
||||
|
||||
|
||||
def random_x_y() -> CoordinateType:
|
||||
"""Generate a valid x,y coordinate on the board"""
|
||||
|
||||
x = random.randrange(1, BOARD_WIDTH + 1)
|
||||
y = random.randrange(1, BOARD_HEIGHT + 1)
|
||||
return (x, y)
|
||||
|
||||
|
||||
# input_coord
|
||||
#
|
||||
# ask user for single (x,y) coordinate
|
||||
# validate the coordinates are within the bounds
|
||||
# of the board width and height. mimic the behavior
|
||||
# of the original program which exited with error
|
||||
# messages if coordinates where outside of array bounds.
|
||||
# if input is not numeric, print error out to user and
|
||||
# let them try again.
|
||||
def input_coord():
|
||||
def input_coord() -> CoordinateType:
|
||||
"""
|
||||
Ask user for single (x,y) coordinate
|
||||
|
||||
validate the coordinates are within the bounds
|
||||
of the board width and height. mimic the behavior
|
||||
of the original program which exited with error
|
||||
messages if coordinates where outside of array bounds.
|
||||
if input is not numeric, print error out to user and
|
||||
let them try again.
|
||||
"""
|
||||
match = None
|
||||
while not match:
|
||||
coords = input("? ")
|
||||
@@ -148,25 +140,25 @@ def input_coord():
|
||||
return x, y
|
||||
|
||||
|
||||
# generate_ship_coordinates
|
||||
#
|
||||
# given a ship from the SHIPS array, generate
|
||||
# the coordinates of the ship. the starting point
|
||||
# of the ship's first coordinate is generated randomly.
|
||||
# once the starting coordinates are determined, the
|
||||
# possible directions of the ship, accounting for the
|
||||
# edges of the board, are determined. once possible
|
||||
# directions are found, a direction is randomly
|
||||
# determined and the remaining coordinates are
|
||||
# generated by adding or substraction from the starting
|
||||
# coordinates as determined by direction.
|
||||
#
|
||||
# arguments:
|
||||
# ship - index into the SHIPS array
|
||||
#
|
||||
# returns:
|
||||
# array of sets of coordinates (x,y)
|
||||
def generate_ship_coordinates(ship):
|
||||
def generate_ship_coordinates(ship: int) -> List[CoordinateType]:
|
||||
"""
|
||||
given a ship from the SHIPS array, generate
|
||||
the coordinates of the ship. the starting point
|
||||
of the ship's first coordinate is generated randomly.
|
||||
once the starting coordinates are determined, the
|
||||
possible directions of the ship, accounting for the
|
||||
edges of the board, are determined. once possible
|
||||
directions are found, a direction is randomly
|
||||
determined and the remaining coordinates are
|
||||
generated by adding or substraction from the starting
|
||||
coordinates as determined by direction.
|
||||
|
||||
arguments:
|
||||
ship - index into the SHIPS array
|
||||
|
||||
returns:
|
||||
array of sets of coordinates (x,y)
|
||||
"""
|
||||
# randomly generate starting x,y coordinates
|
||||
start_x, start_y = random_x_y()
|
||||
|
||||
@@ -213,20 +205,13 @@ def generate_ship_coordinates(ship):
|
||||
return coords
|
||||
|
||||
|
||||
# create_blank_board
|
||||
#
|
||||
# helper function to create a game board
|
||||
# that is blank
|
||||
def create_blank_board():
|
||||
return [[None for y in range(BOARD_WIDTH)] for x in range(BOARD_HEIGHT)]
|
||||
def create_blank_board() -> BoardType:
|
||||
"""Create a blank game board"""
|
||||
return [[None for _y in range(BOARD_WIDTH)] for _x in range(BOARD_HEIGHT)]
|
||||
|
||||
|
||||
# print_board
|
||||
#
|
||||
# print out the game board for testing
|
||||
# purposes
|
||||
def print_board(board) -> None:
|
||||
|
||||
def print_board(board: BoardType) -> None:
|
||||
"""Print out the game board for testing purposes"""
|
||||
# print board header (column numbers)
|
||||
print(" ", end="")
|
||||
for z in range(BOARD_WIDTH):
|
||||
@@ -243,27 +228,31 @@ def print_board(board) -> None:
|
||||
print()
|
||||
|
||||
|
||||
# place_ship
|
||||
#
|
||||
# place a ship on a given board. updates
|
||||
# the board's row,column value at the given
|
||||
# coordinates to indicate where a ship is
|
||||
# on the board.
|
||||
#
|
||||
# inputs: board - array of BOARD_HEIGHT by BOARD_WIDTH
|
||||
# coords - array of sets of (x,y) coordinates of each
|
||||
# part of the given ship
|
||||
# ship - integer repreesnting the type of ship (given in SHIPS)
|
||||
def place_ship(board, coords, ship):
|
||||
def place_ship(board: BoardType, coords: List[CoordinateType], ship: int) -> None:
|
||||
"""
|
||||
Place a ship on a given board.
|
||||
|
||||
updates
|
||||
the board's row,column value at the given
|
||||
coordinates to indicate where a ship is
|
||||
on the board.
|
||||
|
||||
inputs: board - array of BOARD_HEIGHT by BOARD_WIDTH
|
||||
coords - array of sets of (x,y) coordinates of each
|
||||
part of the given ship
|
||||
ship - integer representing the type of ship (given in SHIPS)
|
||||
"""
|
||||
for coord in coords:
|
||||
board[coord[0] - 1][coord[1] - 1] = ship
|
||||
|
||||
|
||||
# NOTE: A little quirk that exists here and in the orginal
|
||||
# game: Ships are allowed to cross each other!
|
||||
# For example: 2 destroyers, length 2, one at
|
||||
# [(1,1),(2,2)] and other at [(2,1),(1,2)]
|
||||
def generate_board():
|
||||
def generate_board() -> Tuple[BoardType, List[List[CoordinateType]]]:
|
||||
"""
|
||||
NOTE: A little quirk that exists here and in the orginal
|
||||
game: Ships are allowed to cross each other!
|
||||
For example: 2 destroyers, length 2, one at
|
||||
[(1,1),(2,2)] and other at [(2,1),(1,2)]
|
||||
"""
|
||||
board = create_blank_board()
|
||||
|
||||
ship_coords = []
|
||||
@@ -284,7 +273,9 @@ def generate_board():
|
||||
return board, ship_coords
|
||||
|
||||
|
||||
def execute_shot(turn, board, x, y, current_turn):
|
||||
def execute_shot(
|
||||
turn: bool, board: BoardType, x: int, y: int, current_turn: int
|
||||
) -> int:
|
||||
"""
|
||||
given a board and x, y coordinates,
|
||||
execute a shot. returns True if the shot
|
||||
@@ -298,12 +289,8 @@ def execute_shot(turn, board, x, y, current_turn):
|
||||
return ship_hit
|
||||
|
||||
|
||||
# calculate_shots
|
||||
#
|
||||
# function to examine each board
|
||||
# and determine how many shots remaining
|
||||
def calculate_shots(board):
|
||||
|
||||
def calculate_shots(board: BoardType) -> int:
|
||||
"""Examine each board and determine how many shots remaining"""
|
||||
ships_found = [0 for x in range(len(SHIPS))]
|
||||
for x in range(BOARD_HEIGHT):
|
||||
for y in range(BOARD_WIDTH):
|
||||
@@ -318,19 +305,12 @@ def calculate_shots(board):
|
||||
return shots
|
||||
|
||||
|
||||
# initialize
|
||||
#
|
||||
# function to initialize global variables used
|
||||
# during game play.
|
||||
def initialize_game():
|
||||
|
||||
# initialize the global player and computer
|
||||
# boards
|
||||
def initialize_game() -> None:
|
||||
# initialize the global player and computer boards
|
||||
global player_board
|
||||
player_board = create_blank_board()
|
||||
|
||||
# generate the ships for the computer's
|
||||
# board
|
||||
# generate the ships for the computer's board
|
||||
global computer_board
|
||||
global computer_ship_coords
|
||||
computer_board, computer_ship_coords = generate_board()
|
||||
@@ -355,8 +335,8 @@ def initialize_game():
|
||||
ship_coords.append(list)
|
||||
|
||||
# add ships to the user's board
|
||||
for ship in range(len(SHIPS)):
|
||||
place_ship(player_board, ship_coords[ship], ship)
|
||||
for ship_index in range(len(SHIPS)):
|
||||
place_ship(player_board, ship_coords[ship_index], ship_index)
|
||||
|
||||
# see if the player wants the computer's ship
|
||||
# locations printed out and if the player wants to
|
||||
@@ -366,9 +346,9 @@ def initialize_game():
|
||||
while input_loop:
|
||||
player_start = input("DO YOU WANT TO START? ")
|
||||
if player_start == "WHERE ARE YOUR SHIPS?":
|
||||
for ship in range(len(SHIPS)):
|
||||
print(SHIPS[ship][0])
|
||||
coords = computer_ship_coords[ship]
|
||||
for ship_index in range(len(SHIPS)):
|
||||
print(SHIPS[ship_index][0])
|
||||
coords = computer_ship_coords[ship_index]
|
||||
for coord in coords:
|
||||
x = coord[0]
|
||||
y = coord[1]
|
||||
@@ -384,14 +364,11 @@ def initialize_game():
|
||||
print_computer_shots = True
|
||||
|
||||
global first_turn
|
||||
global second_turn
|
||||
if player_start.lower() != "yes":
|
||||
first_turn = COMPUTER
|
||||
second_turn = PLAYER
|
||||
|
||||
# calculate the initial number of shots for each
|
||||
global num_computer_shots
|
||||
global num_player_shots
|
||||
global num_computer_shots, num_player_shots
|
||||
num_player_shots = calculate_shots(player_board)
|
||||
num_computer_shots = calculate_shots(computer_board)
|
||||
|
||||
@@ -407,31 +384,22 @@ def initialize_game():
|
||||
# forth, replicating the gotos in the original game
|
||||
|
||||
|
||||
# initialize the first_turn function to the
|
||||
# player's turn
|
||||
# initialize the first_turn function to the player's turn
|
||||
first_turn = PLAYER
|
||||
|
||||
|
||||
# initialize the second_turn to the computer's
|
||||
# turn
|
||||
second_turn = COMPUTER
|
||||
def execute_turn(turn: bool, current_turn: int) -> int:
|
||||
global num_computer_shots, num_player_shots
|
||||
|
||||
|
||||
def execute_turn(turn, current_turn):
|
||||
|
||||
global num_computer_shots
|
||||
global num_player_shots
|
||||
|
||||
# print out the number of shots the current
|
||||
# player has
|
||||
# print out the number of shots the current player has
|
||||
board = None
|
||||
num_shots = 0
|
||||
if turn == COMPUTER:
|
||||
print("I HAVE", num_computer_shots, "SHOTS.")
|
||||
print(f"I HAVE {num_computer_shots} SHOTS.")
|
||||
board = player_board
|
||||
num_shots = num_computer_shots
|
||||
else:
|
||||
print("YOU HAVE", num_player_shots, "SHOTS.")
|
||||
print(f"YOU HAVE {num_player_shots} SHOTS.")
|
||||
board = computer_board
|
||||
num_shots = num_player_shots
|
||||
|
||||
@@ -486,34 +454,22 @@ def execute_turn(turn, current_turn):
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# keep track of the turn
|
||||
current_turn = 0
|
||||
|
||||
# initialize the player and computer
|
||||
# boards
|
||||
initialize_game()
|
||||
|
||||
# execute turns until someone wins or we run
|
||||
# out of squares to shoot
|
||||
|
||||
game_over = False
|
||||
while not game_over:
|
||||
|
||||
# increment the turn
|
||||
current_turn = current_turn + 1
|
||||
current_turn += 1
|
||||
|
||||
print("\n")
|
||||
print("TURN", current_turn)
|
||||
|
||||
# print("computer")
|
||||
# print_board(computer_board)
|
||||
# print("player")
|
||||
# print_board(player_board)
|
||||
|
||||
if execute_turn(first_turn, current_turn) == 0:
|
||||
game_over = True
|
||||
continue
|
||||
if execute_turn(second_turn, current_turn) == 0:
|
||||
if (
|
||||
execute_turn(first_turn, current_turn) == 0
|
||||
or execute_turn(not first_turn, current_turn) == 0
|
||||
):
|
||||
game_over = True
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user