Skip to content

Battleships game implemented in Python and deployed via a xterm.js terminal. blessed python library used for enhanced terminal output.

Notifications You must be signed in to change notification settings

eoinlarkin/py-battleships

Repository files navigation

py-battleships

game-gif

Overview

py-battleships is an interactive terminal based Battleships game implemented in Python.

The game has a number of features, including:

  • A rich data model with a flexible and modular Board() class to store both game parammeters and game state
  • Usage of the blessed Python library for manipulation and control of the terminal
  • A UX which provides an overview of the current game state and provides clear user feedback to the user on the outcome of each move

Objective

The objective of the game was to develop a rich and fully featured Python application. In developing the game, I carefully considered the user experience, which led to the following user stories:

As a site user:

  • I want a game where the terminal output is dynamic and does not rely on scrolling through terminal output
  • I want a game that is easy to play with clear instructions
  • I want a game with clear visual cues indicating the status of the game and the outcome of each game event

As a site owner:

  • I want to ensure that the terminal interaction is user friendly and does not rely on repeated use of print() statements
  • I want to ensure that the site has a strong visual identity
  • I am less concerned whether the website is responsive; the assumption is that the game will be played from either a desktop or laptop
  • I want to ensure that the underlying code leverages best practices and can be exteneded to other potential projects in the future

Features

The key features of the application are outlined below:

  • Dynamic Terminal Output

    • For the game, the blessed Python library was used to dynamically update the terminal and deliver a richer user experience
    • Within the code the termprint module is used to define the various print statments that generate the output to the terminal
    • The following gif provides an example of this dynamic updating:
      Dynamic Terminal Output: dynamic-terminal-output
  • Data Validation

    • Given the game is terminal based it was important to have robust validation of the user input. This prevents game breaking errors as well as ensuring the user has clear feedback on their input
    • In order to support the validation of the user input, two attributes were defined in the Board() class:
      • active_target_invalid
        Used to record whether a user input is in the format of a valid coordiate (capital letter followed by a number)
      • active_target_previous
        Used to record whether the target selected by the user has already been selected
  • User Friendly Interface

    • Care was taken the ensure that the user interface of the game provides unambiguous information to the user in order to deliver a more immersive experience
    • Instructions are provided at the start of the game:
      Game Instructions: screenshot-instructions
    • Input validation messages are displayed for invalid moves:
      Input Validation: screenshot input validations
    • During the game, the status dashboard provides details of the current status of each ship:
      Status Dashbaord: screenshot-ship-status
    • Depending on whether the user is victorious or defeated, different game over status messages are displayed at the end of the game:
      Victory / Defeat Messages: screenshot-defeat screenshot-victory
  • Robust Data Model

    • The game used Object Orienttated Programming to ensure there is a robust data model that is flexible enough to extend to future projects. Further detail is provided in the Data Model section

Future Features

Having developed the game, there are a number of additional features that could potentially be implemented:

  • Different versions of the Computer AI: At the moment, the computer moves are selected by random; this could be extended so that the computer makes 'smarter' moves immediately after scoring a hit
  • Manual Placement of Ships: Implementing manual placement of user ships would be a significant enhancement to the current version of the game.
  • Game stats on victory / defeat: On defeat or victory a status report could be provided to the user summarising the number of shots, ships sank etc.

Data Model

Within the application, the following python script files are defined:

  • battlehships.py
  • termprint.py
  • layout.py
  • game.py
  • run.py

By defining the functions in a separate module there is a clear spearation between code used to define the game data model, update the terminal and define the game logic. This increase the modularity of the code and makes it easier to extend in future.

The following schematic provides an overview of the application data model:

data-model

Further information on each of the functions is as follows:

battleships.py
This is the most complex module; the entire module is used to define the Board() class. This class contains the relevant attributes and methods to:

  • Define the starting game state
  • Generate the coordinates for the placement of the ships in the game space
  • Generate random targets
  • Validate user targets
  • Record the status of the current target and the outcome of the current move

By sparating the module from the game logic, the overall code complexity is decreased. In addition the portability of the code is improved with potential to use the Board() class in different `battleship games.

termprint.py
The termprint module is the one that is used to update and draw output to the terminal in place. Within this moduke a number of different functions are defined for printing different types of output.

layout.py
This is a simple module containing static strings that are used to create the game board and display game instructions and victory / defeat messages.

game.py
This script contains the game logic and calls the battlehships.py termprint.py and layout.py scripts to run the game. The game logic is as follows:

  • Step 1: Initialise the Board Object
  • Step 2: Draw Terminal Output
  • Step 3: Run Game until victor:
    • Step 3-1-1: Set P1 as Active Player
    • Step 3-1-2: Get P1 Move
    • Step 3-1-3: Check Move and Update Board
    • Step 3-1-4: Check if ship has sunk
    • Step 3-1-5: Check if player victorious
    • Step 3-2-1: Set P2 as Active Player
    • Step 3-2-2: Get P2 Move
    • Step 3-2-3: Check Move and Update Board
    • Step 3-2-4: Check if ship has sunk
    • Step 3-2-5: Check if player victorious
  • Step 4: Print Victory Message:

The game.py file also features two functions; one to check whether a ship has sunk (confirm_ship_sunk()) and another to request user input (user_input_request()). These are compound functions are require methods from both the termprint and battleships modules.

run.py This is a very simple script which simply initialises an instance of the game. Potentially this logic could be integrated with the game.py script, however this was separated as the run.py is the script that intialises the game for the Heroku deployment.


Testing

In testing the application a number of bugs were discovered:


Bug: Shipping Mapping Error When testing the application it was discovered that the function that prints the ship indicators (termprint.printships()) to the board was not printing the ships to the correct locations (e.g. ship was being mapped to cell A1 instead of A2).

Fix: It was discovered that the termprint.printships() was working as intended however there was an error in the value of the attribute for the starting position of each ship. Each ship was being offset by one unit on the grid. This was due to a logic error in the loop that was randomly placing the ships and was fixed by amending the loop.


Bug: Favicon Not Displaying When testing the application was deployed to Heroku, it was discovered that the favicon.ico would not correctly display.

Fix: A number of differnet approaches were tired to resolve this problem. Ultimately the link for the favicon.ico in the GitHub repo was linked to directly in the index.html file.



Bug: Hidden Cursor Not Hidden The blessed library performs functionality to hide the input cursor, however initially this was not working consistently.

Fix: After referencing the documentation, it was noted that this functionality should only be initialised once and should not be nested. As a result this function call termprint.term.hidden_cursor() was moved from individual functions to sit directly in the game.py file.



Bug: Broken Scrolling It was found that mouse scrolling was broken on the webpage in the area of the page where the Terminal window as displayed.

Fix: After some investigation it was determined that each side of the Terminal was being masked with overlaid containers in the xterm.js CSS code. This was corrected by setting each of the containers to the same width..



Bug: Code Logic Errors A number of logic error and reference errors were discovered during the testing process.

Fix: These were resolved through corrections to the code and where necessary referencing the Python documentation for the correct methods to iterate through / access the various classes, and attributes used in the application.


Unfixed Bugs

There are no known bugs present in the final site deployment.


Validator Testing

Each of the Python scripts were validated against PEP8 validation, with the following validator used PEP8 Validator.

For the layout.py file, the PEP8 validator indicated that several lines exceeded the recommended length of 80 characters. However, this file is solely used to store the string constants which define the game boards and instruction text that is printed during the game. It was decided not to modify this file to resolve the validator errors.

No further issues were detected. Results from the validation were as follows:


Deployment

The py-battleship repository was deployed using a xterm.js mock terminal to Herkou.

The repoitory can be deployed as follows:

  • Fork or clone the repository
  • Create a new Heroku application
  • For deployment, the Python and NodeJS buildpacks are required
  • The foowing Config Vars are required:
    • PORT=8000
  • Link the Heroku application to the repository
  • Click Deploy

Development

In developing this application, the following programming languages, tools and libraries were used:

Languages

  • Python
  • HTML
  • CSS
  • JavaScript
  • jQuery

Tools

  • VScode
    All coding was completed in VS Code.
  • Heroku
    Heroku was used for the deployment of the app.
  • node-pty and xterm.js
    These open source libraries were used to generate the web based terminal; these are integrated using a modified version of the CodeInstitute template
  • blessed
    This Python library was used to dynamically update the Terminal window.
  • coolors.co
    Potential site palettes were tested with Coolors.
  • ASCII Art Generator This ASCII generator was used to create the game logo and welcome message
  • gauger.io
    This website was used to generate the favicon using an icon from Font Awesome.
  • Chrome Capture - Screenshots & Gifs This was used to create the animated gif showing the game functionality.
  • https://ecotrust-canada.github.io/
    For generating the formatted table of contents in markdown
  • cdnjs
    cdnjs was used as the reference for the jQuery and xterm libraries.
  • Google Fonts
    Used to provide the custom fonts for the site

Credits & Attributions

Attributions:

Other

  • The CodeInstitue Modules on Python and in particular cloud deployment to Heroku
  • My friends for supporting the testing of the game
  • Jeff Quast for developing the blessed package which made developing this application much easier !

About

Battleships game implemented in Python and deployed via a xterm.js terminal. blessed python library used for enhanced terminal output.

Resources

Stars

Watchers

Forks