Added battleship files

This commit is contained in:
2025-11-07 11:22:04 +03:00
parent a11b2df651
commit 6d98d7d446
38 changed files with 1826 additions and 0 deletions

View File

@@ -0,0 +1,371 @@
"""This module is a battleship game"""
import os
import re
import string # Corrected import order (see point 14)
import random
import gspread
from google.oauth2.service_account import Credentials
SCOPE = [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive"
]
CREDS = Credentials.from_service_account_file('creds.json')
SCOPED_CREDS = CREDS.with_scopes(SCOPE)
GSPREAD_CLIENT = gspread.authorize(SCOPED_CREDS)
SHEET = GSPREAD_CLIENT.open('battleship_scores').sheet1
def center_text(text):
"""
Function to center text in the console
"""
console_width = os.get_terminal_size().columns
text_length = len(re.sub(r'\x1b\[[0-9;]*m', '', text))
padding = (console_width - text_length) // 2
return " " * padding + text + " " * padding
def pause():
"""
Function to pause and clear the screen
"""
input("\n" + Bcolors.OKCYAN + center_text("Press Enter to continue...") +
Bcolors.ENDC)
os.system('cls' if os.name == 'nt' else 'clear')
class Bcolors:
# pylint: disable=too-few-public-methods
"""
Colors for console output
"""
HEADER = '\033[95m'
OKBLUE = '\033[34m'
OKCYAN = '\033[96m'
OKGREEN = '\033[32m'
WARNING = '\033[93m'
RED = '\033[31m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
def welcome_message():
"""
Function to display the welcome message with colors
"""
print(Bcolors.HEADER +
Bcolors.BOLD +
center_text("Welcome to Battleships!") +
Bcolors.ENDC)
print("\n" + Bcolors.BOLD +
center_text("Welcome to my simple battleships game!") +
Bcolors.ENDC)
print("\n" + Bcolors.BOLD +
center_text("The aim of the game is to hit your opponents ships" +
" in the least trys possible!") +
Bcolors.ENDC)
print("\n" + Bcolors.BOLD +
center_text("Just select a gameboard size between a 5x5 grid and a" +
" 9x9 grid!") +
Bcolors.ENDC)
print("\n" + Bcolors.BOLD +
center_text("Then enter the co-ordinates of where you want to" +
" shoot when prompted!") +
Bcolors.ENDC)
def display_high_scores():
"""
Function to display top 5 high scores
"""
print("\n" + Bcolors.HEADER + center_text("Current High Scores") +
Bcolors.ENDC)
print("\n" + Bcolors.OKCYAN + center_text("Top 5 Lowest Misses:") +
Bcolors.ENDC)
scores = SHEET.get_all_values()
sorted_scores = scores[1:]
sorted_scores.sort(key=lambda x: int(x[1]))
for i in range(1, 6):
if i <= len(sorted_scores):
print(center_text(f"{i}. {sorted_scores[i-1][0]}: {
sorted_scores[i-1][1]}"))
else:
print(f"{i}. N/A")
def get_board_size():
"""
Function to get valid board size input
"""
while True:
try:
size = int(input("Choose board size (5-9): "))
if 5 <= size <= 9:
return size
print("Invalid size. Please enter a number between 5 and 9")
except ValueError:
print("Invalid input. Please enter a number.")
def create_boards(size):
"""
Function to create and initialize boards
"""
player_board = [['O' for _ in range(size)] for _ in range(size)]
computer_board = [['O' for _ in range(size)] for _ in range(size)]
return player_board, computer_board
def place_ships(board, num_ships):
"""
Function to place ships randomly
"""
ship_locations = []
for _ in range(num_ships):
while True:
row = random.randint(0, len(board) - 1)
col = random.randint(0, len(board[0]) - 1)
if board[row][col] == 'O':
board[row][col] = 'S'
ship_locations.append((row, col))
break
return ship_locations
def display_boards(player_board, computer_board):
"""
Function to display both boards side by side with colors and spacing
"""
board_size = len(player_board)
header_spacing = board_size - 3 - max(0, board_size - 6)
print("\n" + center_text(Bcolors.RED + "Player Board " +
" "*header_spacing +
Bcolors.ENDC + " | " +
Bcolors.RED +
" Computer Board" +
Bcolors.ENDC))
print("\n" + center_text(Bcolors.OKCYAN + " " +
" ".join([str(i) for i in range(
1, board_size + 1)]) +
" " + Bcolors.ENDC +
" |" +
" " + Bcolors.OKCYAN +
" ".join([str(i) for i in range(
1, board_size + 1)]) +
" " +
Bcolors.ENDC))
letters = list(string.ascii_uppercase[:board_size])
for i in range(board_size):
player_row = []
computer_row = []
for j in range(board_size):
if player_board[i][j] == 'X':
player_row.append(Bcolors.RED +
Bcolors.BOLD +
'X' +
Bcolors.ENDC)
elif player_board[i][j] == 'S':
player_row.append(Bcolors.OKBLUE +
Bcolors.BOLD +
'S' +
Bcolors.ENDC)
elif player_board[i][j] == 'M':
player_row.append(Bcolors.OKGREEN +
Bcolors.BOLD +
'M' +
Bcolors.ENDC)
else:
player_row.append(player_board[i][j])
if computer_board[i][j] == 'X':
computer_row.append(Bcolors.RED +
Bcolors.BOLD +
'X' +
Bcolors.ENDC)
elif computer_board[i][j] == 'M':
computer_row.append(Bcolors.OKGREEN +
Bcolors.BOLD +
'M' +
Bcolors.ENDC)
else:
computer_row.append('O')
player_row_str = ' '.join(player_row)
computer_row_str = ' '.join(computer_row)
row_str = f"{Bcolors.OKCYAN}{letters[i]: <2} {Bcolors.ENDC}{
player_row_str: <{len(player_row_str) + 2}} | {
Bcolors.OKCYAN}{
letters[i]: <2}{
Bcolors.ENDC} {
computer_row_str: <{len(computer_row_str) + 2}}"
print(center_text(row_str))
def get_target(board):
"""
Function to get valid target coordinates
"""
while True:
try:
row_letter = input(f"Enter row (A-{chr(ord('A') + len(board) - 1)}). ").upper()
row = string.ascii_uppercase.index(row_letter.upper())
col = int(input(f"Enter column (1-{len(board)}). ")) - 1
if 0 <= row < len(board) and 0 <= col < len(board[0]):
return row, col
print("Invalid coordinates. Please enter numbers within the" +
" board size.")
except ValueError:
print("Invalid input. Please enter letters for Rows and numbers" +
" for columns.")
def player_turn(player_board, computer_board, computer_ships, misses):
"""
Function to handle player's turn
"""
print(Bcolors.OKBLUE + "\nYour turn:" + Bcolors.ENDC)
display_boards(player_board, computer_board)
while True:
row, col = get_target(computer_board)
if computer_board[row][col] == 'M' or computer_board[row][col] == 'X':
print(Bcolors.WARNING +
"You already tried that target. Choose another one.\n" +
Bcolors.ENDC)
else:
if (row, col) in computer_ships:
computer_board[row][col] = 'X'
computer_ships.remove((row, col))
print(Bcolors.OKGREEN +
"Hit! Target: " +
chr(ord('A') + row) +
" " +
str(col + 1) +
Bcolors.ENDC)
else:
computer_board[row][col] = 'M'
print(Bcolors.RED +
"Miss! Target: " +
chr(ord('A') + row) +
" " +
str(col + 1) +
Bcolors.ENDC)
misses += 1
print(Bcolors.OKCYAN +
"\nMisses: " +
Bcolors.ENDC +
str(misses))
break
return computer_board, computer_ships, misses
def computer_turn(player_board, player_ships, misses):
"""
Function to handle computer's turn
"""
print(Bcolors.OKCYAN + "\nComputer's turn:" + Bcolors.ENDC)
while True:
row = random.randint(0, len(player_board) - 1)
col = random.randint(0, len(player_board[0]) - 1)
if player_board[row][col] == 'M' or player_board[row][col] == 'X':
continue
if (row, col) in player_ships:
player_board[row][col] = 'X'
player_ships.remove((row, col))
print(Bcolors.OKGREEN +
"Computer hit! Target: " +
chr(ord('A') + row) +
" " +
str(col + 1) +
Bcolors.ENDC)
break
player_board[row][col] = 'M'
print(Bcolors.RED +
"Computer missed! Target: " +
chr(ord('A') + row) +
" " +
str(col + 1) +
Bcolors.ENDC)
misses += 1
break
pause()
return player_board, player_ships, misses
def play_game():
"""
Function to handle the game loop
"""
while True:
os.system('cl' if os.name == 'nt' else 'clear')
welcome_message()
display_high_scores()
board_size = get_board_size()
pause()
player_board, computer_board = create_boards(board_size)
player_ships = place_ships(player_board, 5)
computer_ships = place_ships(computer_board, 5)
player_misses = 0
computer_misses = 0
while player_ships and computer_ships:
computer_board, computer_ships, player_misses = player_turn(
player_board,
computer_board,
computer_ships,
player_misses)
if not computer_ships:
print(Bcolors.OKGREEN + "\nCongratulations! You win!" +
Bcolors.ENDC)
save_to_high_scores(player_misses)
break
player_board, player_ships, computer_misses = computer_turn(
player_board,
player_ships,
computer_misses)
if not player_ships:
print(Bcolors.RED + "\nYou lose! Better luck next time." +
Bcolors.ENDC)
break
print("\nFinal Score:")
print(f"Player: {player_misses}")
print(f"Computer: {computer_misses}")
while True:
play_again = input("\nPlay again? (y/n): ").lower()
if play_again in ('y', 'n'):
os.system('cls' if os.name == 'nt' else 'clear')
break
print("Invalid input. Please enter 'y' or 'n'.")
if play_again == 'n':
print("Goodbye!")
break
def save_to_high_scores(misses):
"""
Function to handle saving scores to the spreadsheet
"""
while True:
save_score = input("Do you want to save your score to the high " +
"scores? (y/n): ")
if save_score.lower() == 'y':
name = input("Enter your name: ")
SHEET.append_row([name, misses])
os.system('cls' if os.name == 'nt' else 'clear')
print("Score saved successfully!")
display_high_scores()
break
if save_score.lower() == 'n':
os.system('cls' if os.name == 'nt' else 'clear')
print("Score not saved.")
display_high_scores()
break
print("Invalid input. Please enter 'y' or 'n'.")
if __name__ == "__main__":
play_game()