I have been working on a 2-player battleship game in Python. The game asked you to guess a row and column from a 5x5 game board before checking those coordinates to see if you have correctly guessed the ships location.
I have been working on this game for quite a while (since I'm fairly new to programming in general) and I've finally created a game that works bug-free (at least I haven't spotted any).
My question is simply whether there is anything in the code below that can be improved upon? Does the code make sense to you? Would you change anything and why?
from random import randint
game_board = []
player_one = {
"name": "Player 1",
"wins": 0,
"lose": 0
}
player_two = {
"name": "Player 2",
"wins": 0,
"lose": 0
}
# Building our 5 x 5 board
def build_game_board(board):
for item in range(5):
board.append(["O"] * 5)
def show_board(board):
print("Find and sink the ship!")
for row in board:
print(" ".join(row))
# Defining ships locations
def load_game(board):
print("WELCOME TO BATTLESHIP!")
del board[:]
build_game_board(board)
show_board(board)
ship_col = randint(1, len(board))
ship_row = randint(1, len(board[0]))
return {
'ship_col': ship_col,
'ship_row': ship_row,
}
ship_points = load_game(game_board)
# Players will alternate turns.
def player_turns(total_turns):
if total_turns % 2 == 0:
total_turns += 1
return player_one
else:
return player_two
# Allows new game to start
def play_again():
global ship_points
answer = input("Would you like to play again? ")
if answer == "yes" or answer == "y":
ship_points = load_game(game_board)
else:
print("Thanks for playing!")
exit()
# What will be done with players guesses
def input_check(ship_row, ship_col, player, board):
guess_col = 0
guess_row = 0
while True:
try:
guess_row = int(input("Guess Row:")) - 1
guess_col = int(input("Guess Col:")) - 1
except ValueError:
print("Enter a number only: ")
continue
else:
break
match = guess_row == ship_row - 1 and guess_col == ship_col - 1
not_on_game_board = (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4)
if match:
player["wins"] += 1
print("Congratulations! You sunk my battleship!")
print('The current match score is %d : %d (Player1 : Player2)' % (player_one["wins"], player_two["wins"]))
print("Thanks for playing!")
play_again()
elif not match:
if not_on_game_board:
print("Oops, that's not even in the ocean.")
elif board[guess_row][guess_col] == "X" or board[guess_row][guess_col] == "Y":
print("You guessed that one already.")
else:
print("You missed my battleship!")
if player == player_one:
board[guess_row][guess_col] = "X"
else:
board[guess_row][guess_col] = "Y"
show_board(game_board)
else:
return 0
def main():
begin = input('Type \'start\' to begin: ')
while (begin != str('start')):
begin = input('Type \'start\' to begin: ')
for games in range(3):
for turns in range(6):
if player_turns(turns) == player_one:
# print(ship_points)
print("Player One")
input_check(
ship_points['ship_row'],
ship_points['ship_col'],
player_one, game_board
)
elif player_turns(turns) == player_two:
print("Player Two")
input_check(
ship_points['ship_row'],
ship_points['ship_col'],
player_two, game_board
)
if turns == 5:
print("The number of turns has ended.")
print('The current match score is %d : %d (Player1 : Player2)' % (player_one["wins"], player_two["wins"]))
play_again()
if __name__ == "__main__":
main()
1 Answer 1
General
In
build_game_board()
you shouldn't useitem
in thefor
-loop. Instead, use an underscore:for _ in range(5): # something
This is common in loops where you don't need to access / modify each value. You can shorten
player_turns()
(which I would calltake_turns()
):def player_turns(total_turns): if total_turns % 2 == 0: total_turns += 1 return player_one return player_two
You should indicate which options the user has, like this:
POSITIVE = ("yes", "y") NEGATIVE = ("no", "n") while True: answer = input("Play again (y(es) / n(o)? ").lower() if answer in POSITIVE: # something here elif answer in NEGATIVE: # something else here
In
input_check()
(bad name), you use anif
/elif
/else
construct, even though it seems there is no way theelse
block would ever be reached.
Style issues
According to PEP-8, if you need to represent single quotation marks in strings, you should encase the string with double quotation marks:
begin = input("Type 'start' to begin: ") begin = input('Type "start" to begin:')
... instead of using backslashes:
begin = input('Type \'start\' to begin: ') begin = input("Type \"start\" to begin: ")
You may want to add more whitespace to the program, which essentially visually groups together certain aspects of the game, thereby improving the user experience:
print() # Blank line before program starts call a function() get input print() # Blank line before either result if statement then print result 1 else then print result 2 # Etc.
You may want to color the board. You might use
curses
, ANSI escape codes, orcolorama
.Here's an example of using ANSI escape codes:
colors = { "reset":"033円[00m", "red":"033円[91m", "green":"033円[92m", "yellow":"033円[93m", "blue":"033円[94m", "pink":"033円[95m", "cyan":"033円[96m" } # Other stuff happens here... # When the board is printed, first print an ANSI color code print(colors["yellow"]) print(<board>) print(colors["reset"])