I have been working on a 2-player battleship game and have finally got it working, bug free.
I'm posting this here to ask you what you think of it. Are there any changes that could be made to improve the performance/general layout of the code?
If you come across any issues with the code itself, (maybe a bug yet to be found) then I'd be grateful if you could let me know.
The game is a fairly simple console-based battleship game, where the players take it in turns to sink a mutual ship that is defined by an x and y coordinate on a 5x5 game board.
from random import randint
game_board = []
player_one = {
"name": "Player 1",
"wins": 0,
}
player_two = {
"name": "Player 2",
"wins": 0,
}
colors = {
"reset":"033円[00m",
"red":"033円[91m",
"blue":"033円[94m",
"cyan":"033円[96m",
}
# Building our 5 x 5 board
def build_game_board(board):
for item in range(5):
board.append(["O"] * 5)
def show_board(board):
for row in board:
print(" ".join(row))
# Defining ships locations
def load_game(board):
print("WELCOME TO BATTLESHIP!")
print("Find and sink the ship!")
del board[:]
build_game_board(board)
print(colors['blue'])
show_board(board)
print(colors['reset'])
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
return player_two
# Allows new game to start
def play_again():
positive = ["yes", "y"]
negative = ["no", "n"]
global ship_points
while True:
answer = input("Play again? [Y(es) / N(o)]: ").lower().strip()
if answer in positive:
ship_points = load_game(game_board)
main()
break
elif answer in negative:
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"
print(colors['cyan'])
show_board(game_board)
print(colors['reset'])
else:
return 0
begin = input("Type 'start' to begin: ")
while (begin != str('start')):
begin = input("Type 'start' to begin: ")
def main():
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("This game is a draw.")
print(colors['red'])
show_board(game_board)
print(colors['reset'])
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
Overall clean and easy to read. Here are nits and optimizations that I have:
In your
load_game()
function, there is no need to dodel board[:]
if you're recreating the board. You can simply callbuild_game_board()
and rewrite it as such:def build_game_board(): board = [['0' for i in range(5)] for j in range(5)]
You can rewrite
show_board()
like so (a minor nit, takes advantage of list comprehension):def show_board(board): print([" ".join(row) for row in board].join("\n"))
If you're always going to be playing on a 5x5 board, consider storing that as a variable.
SIZE = 5 .... ship_col = randint(1, SIZE)
What's the point of this?
if match: ... elif not match: ... else: return 0
Why not?
if match: ... else: ...
You can relocate this into the
if __name__ == 'main':
chunk:begin = input("Type 'start' to begin: ") while (begin != str('start')): begin = input("Type 'start' to begin: ")
Try to avoid global variables. In your case, you could've declared all of them in the main program and passed them to their respective functions. (If you do this, then the
build_game_board()
function I have above won't work, but you can easily rewrite it).