Skip to content

Instantly share code, notes, and snippets.

@X140Yu
Created December 4, 2015 17:28
Show Gist options
  • Save X140Yu/e1767db4677f32d6e4d2 to your computer and use it in GitHub Desktop.
Save X140Yu/e1767db4677f32d6e4d2 to your computer and use it in GitHub Desktop.
# play the battleship game
import sys
import random
def is_valid_int(integer):
"""
checks to see if number represents a valid integer
@number: a string that might represent an integer
@returns: true if the string represents an integer
"""
integer = integer.strip()
if len(integer) == 0:
return False
else:
return (integer.isdigit() or #only digits
#or a negative sign followed by digits
(integer.startswith('-') and integer[1:].isdigit()))
def create_board(width, height):
"""
create the play board
@width: width of the board which is int
@height: height of the board, int
@returns: list of list characters, represents the board
"""
board = []
for board_row in range(height):
board.append(["*"] * width)
return board
def get_seed_input():
"""
get user's seed input
@returns: seed number, should be an int
"""
# get the seed
seed = " "
while not is_valid_int(seed):
seed = input("Enter the seed: ")
# change it to int
seed = int(seed)
return seed
def get_width_and_height_input():
"""
get user's width and height input
@returns: widht and height, both int
"""
# get the width
width = " "
while not width.isdigit():
width = input("Enter the width of the board: ")
# change it to int
width = int(width)
# get the height
height = " "
while not height.isdigit():
height = input("Enter the height of the board: ")
# change it to int
height = int(height)
return (width, height)
def is_valid_ai_level(ai_level):
"""
check the AI Level input
@ai_level: a character represents the AI's level
@returns: true if the level is right
"""
if ai_level == "1":
return True
elif ai_level == "2":
return True
elif ai_level == "3":
return True
else:
return False
def get_ai_level():
"""
get user's AI levle input
@returns: AI's level, which is an int
"""
ai_level = ""
while not is_valid_ai_level(ai_level):
ai_level = input("Choose your AI.\n1. Random\n2. Smart\n3. Cheater\n Your choice: ")
ai_level = int(ai_level)
return ai_level
def check_minus_location(line):
"""
if user put the ship with minus point
@line: a line of strings
@returns: None
"""
# if number less than 0, there is a problem
for character in line:
if character == '-':
print("Error %s is placed outside of the board." % line[0])
print("Terminating game.")
sys.exit(0)
def change_line_to_one_ship_list(line):
"""
change a line to a ship list
@line: a line of strings
@returns: a list, represents a ship location info
like ["P", "0", "1", "2", "3"]
"""
ship_location = list(line)
# remove the space and "\n"
ship_location = list(filter(lambda x: x != " " and x != "\n", ship_location))
return ship_location
def check_reserved_symbols(name_of_the_ship):
"""
check if use the reserved symbols
@name_of_the_ship: symbol, a character
@returns: None
"""
# if use the reserved symbols
if name_of_the_ship in ["x", "X", "o", "O", "*"]:
print("You should not use the reserved symbols.")
print("Terminating game.")
sys.exit(0)
def check_file_content(board_file_name, width, height):
"""
check the user's input file is right or not
@board_file_name: file's name, string
@width: the board's width, int
@height: the board's height, int
@returns: the user ships's locations, should be a list
"""
# open the file
try:
board_file = open(board_file_name)
except:
# open file failed
print("File cannot open.")
print("Terminating game.")
sys.exit(0)
# list for symbols eg.'['P', 'A']'
# check duplicate
ship_names = []
# a board to check if user put the ship at the same place
board = create_board(width, height)
# the user ships's locations
user_location_list = []
# iterate the file with line
for line in board_file:
# if user put the ship with minus point
check_minus_location(line)
# change a line to a ship list
ship_location = change_line_to_one_ship_list(line)
# the name of the ship
name_of_the_ship = ship_location[0]
# the two points of the ship
first_point_x = int(ship_location[1])
first_point_y = int(ship_location[2])
second_point_x = int(ship_location[3])
second_point_y = int(ship_location[4])
# check if use the reserved symbols
check_reserved_symbols(name_of_the_ship)
# check outside the board
if first_point_x >= height or second_point_x >= height or first_point_y >= width or second_point_y >= width:
print("Error %s is placed outside of the board." % line[0])
print("Terminating game.")
sys.exit(0)
# if has duplicate names
if name_of_the_ship in ship_names:
print("Error symbol %s is already in use." % name_of_the_ship)
print("Terminating game")
sys.exit(0)
# put the name in list
ship_names.append(name_of_the_ship)
# if user place diagonal ship
if first_point_x != second_point_x and first_point_y != second_point_y:
print("Ships cannot be placed diagonally.")
print("Terminating game.")
sys.exit(0)
user_location_list.append(ship_location)
# check if user put the ship on another ship
# horizontal
if first_point_x == second_point_x:
# first_point_y should less than second_point_y
if first_point_y > second_point_y:
temp = first_point_y
first_point_y = second_point_y
second_point_y = temp
for y in range(first_point_y, second_point_y + 1):
if board[first_point_x][y] != "*":
print("There is already a ship at location %d, %d." % (first_point_x, y))
print("Terminating game.")
sys.exit(0)
board[first_point_x][y] = name_of_the_ship
# vertical
else:
if first_point_x > second_point_x:
temp = first_point_x
first_point_x = second_point_x
second_point_x = temp
for x in range(first_point_x, second_point_x + 1):
if board[x][first_point_y] != "*":
print("There is already a ship at location %d, %d." % (x, first_point_y))
print("Terminating game.")
sys.exit(0)
board[x][first_point_y] = name_of_the_ship
return user_location_list
def draw_user_board(user_location_list, user_board):
"""
draw user's board
@user_location_list: a list with user's location
@user_board: the user's board
@returns: None
"""
for ship_location in user_location_list:
# the name of the ship
name_of_the_ship = ship_location[0]
# the two points of the ship
first_point_x = int(ship_location[1])
first_point_y = int(ship_location[2])
second_point_x = int(ship_location[3])
second_point_y = int(ship_location[4])
# horizontal
if first_point_x == second_point_x:
# first_point_y should less than second_point_y
if first_point_y > second_point_y:
temp = first_point_y
first_point_y = second_point_y
second_point_y = temp
for y in range(first_point_y, second_point_y + 1):
user_board[first_point_x][y] = name_of_the_ship
# vertical
else:
if first_point_x > second_point_x:
temp = first_point_x
first_point_x = second_point_x
second_point_x = temp
for x in range(first_point_x, second_point_x + 1):
user_board[x][first_point_y] = name_of_the_ship
def get_ship_length(ship_location):
"""
get the ship length with ship_location
@ship_location: a list
@returns: ship's length, int
"""
# the name of the ship
name_of_the_ship = ship_location[0]
# the two points of the ship
first_point_x = int(ship_location[1])
first_point_y = int(ship_location[2])
second_point_x = int(ship_location[3])
second_point_y = int(ship_location[4])
length = 0
if first_point_x == second_point_x:
length = abs(first_point_y - second_point_y)
else:
length = abs(first_point_x - second_point_x)
length += 1
return length
def can_draw_on_the_ai_board(ai_board, direction, row, col, ship_length):
"""
check if point can draw on the ai_board
@ai_board: board of the AI
@direction: direction of the ship, 'horz' or 'vert'
@row: int, row number
@col: int, col number
@ship_length: int, length of the ship
"""
# ai_board is a list of list, copy it not changing it
ai_temp_board = [x[:] for x in ai_board]
# the first time
if row == " ":
return False
if direction == 'horz':
for i in range(col, col + ship_length):
if ai_temp_board[row][i] != '*':
return False
else:
ai_temp_board[row][i] = "-"
else:
for i in range(row, row + ship_length):
if ai_temp_board[i][col] != '*':
return False
else:
ai_temp_board[i][col] = "-"
return True
def draw_ai_real_board(user_location_list, ai_board):
"""
draw AI's board
@user_location_list: a list with user's location
@ai_board: the AI's board
@returns: None
"""
width = len(ai_board[0])
height = len(ai_board)
# names should in order
user_location_list = sorted(user_location_list, key = lambda x: x[0])
messages = []
for ship_location in user_location_list:
direction = ''
row = " "
col = " "
ship_length = get_ship_length(ship_location)
ship_name = ship_location[0]
while not can_draw_on_the_ai_board(ai_board, direction, row, col, ship_length):
direction = random.choice(['vert', 'horz'])
if direction == 'horz':
row = random.randint(0, height - 1)
col = random.randint(0, width - ship_length)
else:
row = random.randint(0, height - ship_length)
col = random.randint(0, width - 1)
if direction == 'horz':
for i in range(col, col + ship_length):
ai_board[row][i] = ship_name
print("Placing ship from %d,%d to %d,%d." % (row, col, row, col + ship_length - 1))
else:
for i in range(row, row + ship_length):
ai_board[i][col] = ship_name
print("Placing ship from %d,%d to %d,%d." % (row, col, row + ship_length - 1, col))
def print_board(board):
"""
print the board
@board: list of list characters
@returns: None
"""
width = len(board[0])
height = len(board)
# to fit the test
print(" ", end="")
row_index = 0
for num in range(width):
print ((' %d' % row_index), end="")
row_index += 1
print("")
col_index = 0
for row in board:
print(('%d ' % col_index) + " ".join(row))
col_index += 1
def print_both_boards(ai_board_blank, user_board):
"""
print both the boards
@ai_board_blank: the ai board showing to user
@user_board: user's board
both list of list
"""
width = len(ai_board_blank[0])
height = len(ai_board_blank)
# print AI's board
print("Scanning Board")
print_board(ai_board_blank)
# print user's board
print("My Board")
print_board(user_board)
def check_wins_with_print(ai_board, user_board):
"""
check who wins with print info
@ai_board: AI's board
@user_board: user's board
@returns: true if someone wins
"""
# user wins
# change ai_board to a list
ai_sums = sum(ai_board, [])
if set(ai_sums) == set(['*', 'X']) or set(ai_sums) == set(['X']):
print("You win!")
return True
# AI wins
user_sums = sum(user_board, [])
if set(user_sums) == set(['X']) or set(user_sums) == set(['*', 'X']) or set(user_sums) == set(['*', 'X', 'O']):
print("The AI wins.")
return True
return False
def check_wins_without_print(ai_board, user_board):
"""
check who wins without print info
@ai_board: AI's board
@user_board: user's board
@returns: true if someone wins
"""
# user wins
# change ai_board to a list
ai_sums = sum(ai_board, [])
if set(ai_sums) == set(['*', 'X']) or set(ai_sums) == set(['X']):
return True
# AI wins
user_sums = sum(user_board, [])
if set(user_sums) == set(['X']) or set(user_sums) == set(['*', 'X']) or set(user_sums) == set(['*', 'X', 'O']):
return True
return False
def is_valid_user_guess_point(user_guess_string, ai_board):
"""
check if the user guess point is right
@user_guess_string: user's guess string
@ai_board: AI's board
@returns: Ture if the string is right
"""
width = len(ai_board[0])
height = len(ai_board)
guess = user_guess_string.split()
if len(guess) != 2:
return False
# unwrap
(row, col) = guess
if not row.isdigit() or not col.isdigit():
return False
# change to int
row = int(row)
col = int(col)
# out the board
if col >= width or row >= height:
return False
if ai_board[row][col] == '*' or ai_board[row][col] != '.':
return True
return False
def get_user_guess(ai_board):
"""
get user's input
@returns: row and col both int
"""
user_guess_point = ''
while not is_valid_user_guess_point(user_guess_point, ai_board):
user_guess_point = input("Enter row and column to fire on separated by a space: ")
(row, col) = user_guess_point.split()
row = int(row)
col = int(col)
return (row, col)
def draw_point_on_ai_board(guess_point, ai_board_blank, ai_board):
"""
put the point on the ai_board_blank
@guess_point: the guess point, (int, int)
@ai_board_blank: the blank AI board
@ai_board: AI's real board
@returns: None
"""
(row, col) = guess_point
symbol = ai_board[row][col]
# missed
if symbol == '*':
ai_board_blank[row][col] = 'O'
print("Miss!")
else: # hit!
ai_board_blank[row][col] = 'X'
sunk_name = ai_board[row][col]
ai_board[row][col] = 'X'
symbols = sum(ai_board, [])
if not sunk_name in symbols:
print("You sunk my %s" % sunk_name)
else:
print("Hit!")
def draw_point_on_user_board(point, user_board):
"""
put the point on the user's board
@point: the guess point
@user_board: the user's board
@returns: true if the AI hit a ship
"""
row = point[0]
col = point[1]
symbol = user_board[row][col]
if symbol == '*':
# missed
user_board[row][col] = 'O'
print("Miss!")
return False
else:
# hit
sunk_symbol = user_board[row][col]
user_board[row][col] = 'X'
symbols = sum(user_board, [])
if not sunk_symbol in symbols:
print("You sunk my %s" % sunk_symbol)
return True
else:
print("Hit!")
return True
def create_ai_random_list(width, height):
"""
create AI's random list
@width: width of the board
@height: height of the board
@returns: the created list
"""
random_list = []
for row in range(height):
for col in range(width):
random_list.append([row, col])
return random_list
def level_one_ai_turn(random_ai_list, user_board):
"""
level one AI plays the game
@random_ai_list: the rest of the random list
@user_board: user's board
@returns: None
"""
ai_guess_point = random.choice(random_ai_list)
random_ai_list.remove(ai_guess_point)
print("The AI fires at location (%d, %d)" % (ai_guess_point[0], ai_guess_point[1]))
draw_point_on_user_board(ai_guess_point, user_board)
def level_two_ai_turn(random_ai_list, destory_list, user_board):
"""
level Two AI plays the game
@random_ai_list: the rest of the random list
@destory_list: the destory list
@user_board: user's board
@returns: None
"""
if len(destory_list) > 0:
# destory mode
ai_guess_point = destory_list[0]
else:
# hunt mode
ai_guess_point = random.choice(random_ai_list)
if ai_guess_point in destory_list:
destory_list.remove(ai_guess_point)
if ai_guess_point in random_ai_list:
random_ai_list.remove(ai_guess_point)
print("The AI fires at location (%d, %d)" % (ai_guess_point[0], ai_guess_point[1]))
if draw_point_on_user_board(ai_guess_point, user_board) == True:
#add point to destory_list
width = len(user_board[0])
height = len(user_board)
row = ai_guess_point[0]
col = ai_guess_point[1]
# up
new_row = row - 1
new_col = col
if new_row >= 0 and user_board[new_row][new_col] != 'O' and user_board[new_row][new_col] != 'X':
if not [new_row, new_col] in destory_list:
destory_list.append([new_row, new_col])
# below
new_row = row + 1
new_col = col
if new_row < height and user_board[new_row][new_col] != 'O' and user_board[new_row][new_col] != 'X':
if not [new_row, new_col] in destory_list:
destory_list.append([new_row, new_col])
# left
new_row = row
new_col = col - 1
if new_col >= 0 and user_board[new_row][new_col] != 'O' and user_board[new_row][new_col] != 'X':
if not [new_row, new_col] in destory_list:
destory_list.append([new_row, new_col])
# right
new_row = row
new_col = col + 1
if new_col < width and user_board[new_row][new_col] != 'O' and user_board[new_row][new_col] != 'X':
if not [new_row, new_col] in destory_list:
destory_list.append([new_row, new_col])
def level_three_ai_turn(user_board):
"""
level three AI plays the game
@user_board: user's board
@returns: None
"""
width = len(user_board[0])
height = len(user_board)
for x in range(height):
for y in range(width):
symbol = user_board[x][y]
if symbol != '*' and symbol != 'X':
print("The AI fires at location (%d, %d)" % (x, y))
draw_point_on_user_board([x, y], user_board)
return
def play_game():
"""
play the battleship game
"""
# -------- get user's input
# get the seed
seed = get_seed_input()
# get the width and height
(width, height) = get_width_and_height_input()
# get the file name
board_file_name = input("Enter the name of the file containing your ship placements: ")
# get the AI level
ai_level = get_ai_level()
# -------- game's setup and check the file contnet
# Seed the random number generator with the provided seed
random.seed(seed)
# create the blank AI board
ai_board_blank = create_board(width, height)
# Construct the user's board
user_board = create_board(width, height)
# Construct the AI's board
ai_board = create_board(width, height)
# check if the file content is right
user_location_list = check_file_content(board_file_name, width, height)
# --------- file's checked, draw the board of user
# draw the user's board
draw_user_board(user_location_list, user_board)
# draw the AI's real board
draw_ai_real_board(user_location_list, ai_board)
# --------- random the seed to decide who is the first
who_is_the_first = random.randint(0, 1)
# if user's the first, should print the boards info first to fit the test
if who_is_the_first == 0:
print_both_boards(ai_board_blank, user_board)
# Construct a random list for AI level 1 and 2
random_ai_list = create_ai_random_list(width, height)
# Construct the destory list for AI level 2 destory mode
destory_list = []
while not check_wins_with_print(ai_board, user_board):
# ------- user's turn
if who_is_the_first == 0:
# get the user's guess point
guess_point = get_user_guess(ai_board)
# change AI's board
draw_point_on_ai_board(guess_point, ai_board_blank, ai_board)
# print if needed to fit the test
if check_wins_without_print(ai_board, user_board) == True:
print_both_boards(ai_board_blank, user_board)
who_is_the_first = 1
else:
# ------- AI's turn
if ai_level == 1:
level_one_ai_turn(random_ai_list, user_board)
elif ai_level == 2:
level_two_ai_turn(random_ai_list, destory_list, user_board)
else:
level_three_ai_turn(user_board)
print_both_boards(ai_board_blank, user_board)
who_is_the_first = 0
if __name__ == '__main__':
play_game()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment