generated from Code-Institute-Org/python-essentials-template
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrun.py
337 lines (265 loc) · 9 KB
/
run.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# IMPORTS
from random import sample
import sys
import time
# VARIABLES
# Initialize hidden and guess boards for the various sizes
# HIDDEN_BOARD: Contains hidden ship locations
HIDDEN_BOARD_SMALL = [[" " for _ in range(4)] for _ in range(4)]
HIDDEN_BOARD_MEDIUM = [[" " for _ in range(6)] for _ in range(6)]
HIDDEN_BOARD_LARGE = [[" " for _ in range(8)] for _ in range(8)]
# GUESS_BOARD: Contains player's guesses (hits and misses)
GUESS_BOARD_SMALL = [[" " for _ in range(4)] for _ in range(4)]
GUESS_BOARD_MEDIUM = [[" " for _ in range(6)] for _ in range(6)]
GUESS_BOARD_LARGE = [[" " for _ in range(8)] for _ in range(8)]
# BOARD_SIZES_DICT: Maps size keys (s, m, l) to hidden/guess boards
BOARD_SIZES_DICT = {
"s": {
"HIDDEN_BOARD": HIDDEN_BOARD_SMALL,
"GUESS_BOARD": GUESS_BOARD_SMALL
},
"m": {
"HIDDEN_BOARD": HIDDEN_BOARD_MEDIUM,
"GUESS_BOARD": GUESS_BOARD_MEDIUM
},
"l": {
"HIDDEN_BOARD": HIDDEN_BOARD_LARGE,
"GUESS_BOARD": GUESS_BOARD_LARGE
}
}
# BOARD_COORDINATES: Maps letter coords to index values
BOARD_COORDINATES = {
"A": 0,
"B": 1,
"C": 2,
"D": 3,
"E": 4,
"F": 5,
"G": 6,
"H": 7}
# NUM_SHIPS: Constant for number of ships in game
NUM_SHIPS = 5
# Game Introduction
def print_fast(ltr):
"""
Creates a fast typing effect
"""
for letter in ltr:
sys.stdout.write(letter)
sys.stdout.flush()
time.sleep(0.05)
def print_slow(ltr):
"""
Creates a slow typing effect.
"""
for letter in ltr:
sys.stdout.write(letter)
sys.stdout.flush()
time.sleep(0.1)
def intro():
"""
This is the game introduction.
"""
print("""\
\033[92m
____ _ _ _ _ _
| _ \ | | | | | | | | (_)
| |_) | __ _| |_| |_| | ___ ___| |__ _ _ __ ___
| _ < / _` | __| __| |/ _ \/ __| '_ \| | '_ \/ __|
| |_) | (_| | |_| |_| | __/\__ \ | | | | |_) \__ |
|____/ \__,_|\__|\__|_|\___||___/_| |_|_| .__/|___/
| |
|_|
\033[0m
""")
print_slow("Welcome to battleships!\n")
# Mechanics
def show_board(board: list) -> None:
"""
Prints the game board to the console.
Parameters:
- board: a 2D list (game board).
"""
board_scale = len(board[0])
# Generate column headers (A, B, C, etc.) based on board_scale
column_headers = " "
column_headers += " ".join([chr(i) for i in range(65, 65 + board_scale)])
print(column_headers)
# Print horizontal line
print(" +{0}".format("-+" * board_scale))
# Print board rows with row numbers
for i, row in enumerate(board):
print("{0}|{1}|".format(i + 1, "|".join(row)))
# Print another horizontal line
print(" +{0}".format("-+" * board_scale))
def show_boards(guess_board, hidden_board):
"""
Prints the player's guess board and the hidden board to the console.
Parameters:
- guess_board: a 2D list (player's guess board).
- hidden_board: a 2D list (hidden board with ship locations).
"""
show_board(guess_board)
def create_ship(board) -> None:
"""
Randomly places 5 ships on the game board.
Parameters:
- board: a 2D list (game board).
"""
board_scale_x = len(board[0])
board_scale_y = len(board)
# Generate ship coordinates by sampling
# unique (x, y) positions from the board.
ship_coords = sample(
[
(x, y)
for x in range(0, board_scale_x)
for y in range(0, board_scale_y)
],
NUM_SHIPS,
)
# Loop through the ship coordinates
for ship_row, ship_column in ship_coords:
board[ship_row][ship_column] = "S"
def get_board_coordinates(hidden_board) -> tuple:
"""
Prompts the user to input the coordinates of a ship on the game board.
Returns:
- a tuple containing the row and column indices of the ship.
"""
while True:
try:
row = input(f"Choose ROW 1-{len(hidden_board)}:\n")
row = row.strip().upper()
print("You chose ROW: %s" % row)
# Validate row input
# Valid input is an integer between 1 and the length of the board.
if not (row.isdigit() and 1 <= int(row) <= len(hidden_board)):
raise ValueError("Invalid input. "
"Please enter a valid row number.")
row = int(row) - 1
break
except ValueError as e:
print(e)
while True:
try:
column_range = chr(64 + len(hidden_board[0]))
column_prompt = f"Choose COLUMN A-{column_range}: "
column = input(column_prompt)
column = column.strip().upper()
print(f"You chose COLUMN: {column}")
# Validate column input
if not (
len(column) == 1 and
("A" <= column <= chr(64 + len(hidden_board[0])))
):
raise ValueError(
"Invalid input. "
"Please enter a valid column letter."
)
column = ord(column) - 65
break
except ValueError as e:
print(e)
return row, column
def count_hits(board: list) -> int:
"""
Returns the number of hits on the guess board
Parameters:
- board: a 2D list representing the guess board.
Returns:
- an integer representing the amount of "H"
characters on the board.
"""
return sum(1 for row in board for column in row if column == "H")
def reset_game_state(board_size):
"""
Resets the game state for a new game
Parameters:
- board_size: a string as the board size
("s", "m", or "l").
Returns:
- a tuple containing the hidden_board, guess_board,
TURNS_LEFT, and hit_count variables.
"""
if board_size not in BOARD_SIZES_DICT:
raise ValueError(f"Invalid board size: {board_size}")
board_scale = len(BOARD_SIZES_DICT[board_size]["HIDDEN_BOARD"])
# Create new boards using list comprehensions
hidden_board = [[" "] * board_scale for _ in range(board_scale)]
guess_board = [[" "] * board_scale for _ in range(board_scale)]
TURNS_LEFT = 10
hit_count = 0
return hidden_board, guess_board, TURNS_LEFT, hit_count
def setup_game():
"""
Sets up the game by initializing variables,
prompting user for board size,
and resetting the hidden and guess boards.
Returns:
- a tuple containing the hidden_board, guess_board,
and TURNS_LEFT variables.
"""
# Prompt user for board size and validate the input
board_size = (
input("Please enter the board size (s, m, l):\n")
.lower()
.strip()
)
while board_size not in ["s", "m", "l"]:
board_size = (
input("Invalid board size."
"Please enter again (s, m, l):\n")
.lower()
.strip()
)
# Get the board and board scale based on the board size
hidden_board = BOARD_SIZES_DICT[board_size]["HIDDEN_BOARD"]
guess_board = BOARD_SIZES_DICT[board_size]["GUESS_BOARD"]
# Reset boards and turns left
hidden_board, guess_board, TURNS_LEFT, _ = reset_game_state(board_size)
# Randomly place 5 ships on the hidden board
create_ship(hidden_board)
return hidden_board, guess_board, TURNS_LEFT
# Loop
if __name__ == "__main__":
play_again = "yes"
while play_again.lower() == "yes":
# Call the intro function here before prompting the user
intro()
# Setup game and initialize variables
hidden_board, guess_board, TURNS_LEFT = setup_game()
hit_count = 0
# Main game loop
while TURNS_LEFT > 0:
show_boards(guess_board, hidden_board)
print("Your turn! Guess a battleship location.")
# Get player's guess and validate input
row, column = get_board_coordinates(hidden_board)
# Process the player's guess
if guess_board[row][column] in ["H", "M"]:
print("This coordinate has already been targeted. "
"Choose another!")
elif hidden_board[row][column] == "S":
print("HIT!")
guess_board[row][column] = "H"
hit_count += 1
TURNS_LEFT -= 1
# Check win condition
if hit_count == NUM_SHIPS:
print("You win!")
break
else:
print("MISS!")
guess_board[row][column] = "M"
TURNS_LEFT -= 1
# Display remaining turns
print(f"You have {TURNS_LEFT} turns left.")
# If player runs out of turns, end game and show results
if TURNS_LEFT == 0:
print("You ran out of turns.")
print("Total Hits: " + str(hit_count))
# Prompt user to play again or exit
play_again = (
input("Do you want to play again? (Yes or No):\n").lower().strip()
)