This project was created to provide a simple yet engaging experience for those seeking a quick distraction through a classic, retro-inspired game. It is designed for individuals who enjoy nostalgic, old-school games and are looking for a fun and accessible way to pass the time. The target audience includes casual gamers, fans of classic strategy games like Battleship, and anyone who appreciates the charm of retro-style graphics and gameplay. Whether you're looking to take a break from your day or relive the joy of a traditional board game in a digital format, this project offers a delightful way to do so.
- Flowchart
- Game Flow
- Technologies used
- Testing
- Bugs
- Validator testing
- Deployment
- Credits
- Acknowledgements
The Battleship game is a classic two-player strategy game where the objective is to sink all of the opponent's ships. In this Python implementation, the player competes against the computer. The game proceeds through the following steps:
-
The game begins with a welcome screen displaying the title of the game.
-
The player is prompted to enter their name. The input is validated to ensure it meets specific criteria:
- The username must have more than three characters.
- It must contain only letters, with no numbers or special characters.
- If the input is invalid, an error message is displayed, and the player is prompted to enter a valid name.
-
The player is then asked to choose the size of the grid on which the game will be played. The grid size can range from 3x3 to 8x8.
-
Based on the selected grid size, a certain number of ships are placed randomly on both the player’s and the computer’s grids.
-
The player's grid is displayed, revealing the locations of their ships (S).
-
The computer's grid is also displayed, but with the ships hidden, represented by ~ (water).
-
The game enters a loop where the player and the computer take turns to attack each other’s grid by selecting coordinates.
-
The player is prompted to enter the row and column numbers for their attack.
-
If the selected coordinate has already been chosen, the player is informed and asked to choose a different coordinate.
-
The game checks whether the player's attack hits a ship on the computer's grid:
-
The updated computer grid is then displayed with hidden ships.
-
-
After the player's turn, the game checks if all of the computer's ships have been sunk.
-
If all ships are hit, the player wins, and the game congratulates the player before ending the loop.
-
The computer randomly selects a coordinate on the player's grid to attack.
-
The game checks whether the computer's attack hits a ship on the player's grid:
-
Hit: The grid is updated to mark the hit with an X, and a message is displayed informing the player of the hit.
-
Miss: The grid is updated to mark the miss with an O, and a message is displayed informing the player of the miss.
-
-
The updated player's grid is then displayed with the locations of ships revealed.
-
Once the game loop ends (either due to a player win or loss), the player is asked if they want to play again.
-
If the player chooses to play again (Y), the game restarts from the beginning with a new grid setup.
-
If the player chooses not to play again (N), the game displays a farewell message and exits.
Upon exiting, the game displays a message thanking the player for playing.
Tool/Service | Purpose |
---|---|
Python | Used to write and create the application |
Heroku | Used to deploy and host the application |
GitHub | Used to store the code, files and documentation |
Gitpod | IDE used for creating the application |
Git | Used for version control |
Code:WOF Style checker | Used for formatting Python code according to PEP 8 (Style Guide for Python Code) and PEP 257 (Docstring Conventions). |
Lucidcharts | Used for creating a flowchart |
ASCII Art Archive | Used to get ASCII art images for SEA, EXPLOSION, BOAT and TITLE |
Colorama | Used to add color to font and background, improving overall visual appeal to the game |
File "/workspace/PP3-battlefield/run.py", line 4, in __init__
self.grid = [['-' for _ in range(size)] for _ in range(size)]
^^^^^^^^^^^
TypeError: 'str' object cannot be interpreted as an integer
- Fixed by adding
int()
to the function
$ python3 run.py
Please enter your name:
Art
Hi Art, enter grid size (e.g., 5 for a 5x5 grid):
3
Traceback (most recent call last):
File "/workspace/PP3-battlefield/run.py", line 54, in <module>
main()
File "/workspace/PP3-battlefield/run.py", line 43, in main
player_grid.place_ships()
TypeError: Grid.place_ships() takes 0 positional arguments but 1 was given
- Fixed by adding
self
as a parameter inplace_ships()
function. This parameter is necessary for it to access the Grid instance and check if the cell is empty inself[row][col]
Traceback (most recent call last):
File "/workspace/PP3-battlefield/run.py", line 54, in <module>
main()
File "/workspace/PP3-battlefield/run.py", line 43, in main
player_grid.place_ships()
File "/workspace/PP3-battlefield/run.py", line 28, in place_ships
if self[row][col] == "-": # Checks if hte cell is empty ("-")
~~~~^^^^^
TypeError: 'Grid' object is not subscriptable
"This error occurs because of a mistake in how you're trying to access the grid within the place_ships method. Specifically, the line if self[row][col] == "-" is trying to use the Grid object itself as if it were a list, but self refers to the entire Grid object, not just the grid attribute inside it." - Fernando Vilela
gitpod /workspace/PP3-battlefield (main) $ python3 run.py
File "/workspace/PP3-battlefield/run.py", line 148
break
^^^^^
SyntaxError: 'break' outside loop
-
Solved indentation issue by moving the if statement into the while loop
# Check for victory condition (all ships hit) if all(cell != 'S' for row in computer_grid.grid for cell in row): print(f"\nCongratulations {user_name}, you've sunk all the computer's ships!") break
- Solved by changing the favicon href to an external href to the image itself in the project's Github repository.
- The solution was found by Code Institute's tutors John and Rebecca
<link rel="icon" type="image/svg+xml" href="https://raw.githubusercontent.com/arthur-vilela/PP3-battlefield/main/assets/favicon/favicon.ico"/>
The code in run.py
was run in Code Institute's Python Linter showing no errors found.
-
Solution for the positional argument bug was found in this answer on StackOverflow
-
Solution for the
TypeError: 'Grid' object is not subscriptable
bug was given by developer Fernando Vilela -
Explanation and examples for enumerate function used on the grid was taken from this GeeksforGeeks tutorial.
-
Line of code used to clear the terminal after every round and when the game is restarted was taken from this StackOverflow answer. The idea for it was given by my mentor Alan Bushell.
import os os.system('cls||clear')
-
The function
time.sleep()
was found and explained in this Code Institute post. -
Solution for the missing favicon bug was found by Code Institute's tutors John and Rebecca.
- Navigate to Heroku and log in to your account.
- Click on the
New
button and selectCreate New App
. - Provide a unique name for your application and choose your preferred region.
- Click on the
Create app
button.
- After creating the app, go to the
Settings
tab. - Under
Config Vars
, click theReveal Config Vars
button. - Add a new variable:
- KEY:
PORT
- VALUE:
8000
- KEY:
- Click the
Add
button to save the configuration.
- In the
Settings
tab, scroll down to theBuildpacks
section. - Click on
Add buildpack
and select Python. - Add another buildpack and select Node.js.
- Ensure that the buildpacks are in this order: Python first, followed by Node.js.
- Click the
Save changes
button.
- Navigate to the
Deploy
tab. - Under
Deployment method
, select GitHub. - Connect your GitHub account if it's not already connected.
- Search for your repository and select it.
- Click
Connect
to link the repository to Heroku.
-
Automatic Deploys:
- Enable automatic deploys to allow Heroku to rebuild and deploy your app every time you push changes to the selected branch.
- Choose the branch you want to deploy and click
Enable Automatic Deploys
.
-
Manual Deploys:
- To deploy manually, scroll down to the
Manual Deploy
section. - Select the branch you want to deploy and click
Deploy Branch
.
- To deploy manually, scroll down to the
- Once the deployment is complete, click on the
Open App
button at the top of the page to view your live application.
The deployment terminal is set to 80 columns by 24 rows. That means that each line of text needs to be 80 characters or less otherwise it will be wrapped onto a second line.
- My mentor Alan Bushell for great counseling and positive reinforcement
- My wife Kyra Sendler for user testing and encouragement