Battleship game in README.md

4 min read • November 7, 2022

Some time ago, while I was browsing for GitHub profile customization ideas, I stumbled across the profile of @JonathanGin52, who has an interactive Connect 4 Game in GitHub README.md. I liked the idea and wanted to make something similar.

First, check out the short video below to see it in action, or play it on my profile!

Everything works by using a few components

  • GitHub Actions - to run the code when someone interacts with README.md
  • Python script - to take care of game logic and updating README with new values
  • Database (MongoDB) - to store all the data (statistics, coordinates, etc.)
  • README.md file - game’s GUI

Board representation

To represent the board, I created this bitboard to represent each table cell by a different number. When someone makes a move, I can easily find its location. It’s also easy to generate ships with this method. I can choose one random number and then go horizontally or vertically to get the rest of the ship.

Note the extra numbers on the right. All of these numbers are treated as incorrect. This way Python script knows when the row ends.
+---------------------------------------+
| 0  | 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
+---------------------------------------+

GitHub Actions

Whenever an issue with the prefix battleship|action|location is opened, it triggers the GitHub Actions workflow. The title of the issue and the user’s username are passed as environment variables to a Python script, which then splits the issue title every | and decides if it should create a new game or make a move based on action.

Creating a new game

When a new game has to get created, we need to make a blank board with ships placed randomly. To do it, we call the create_game() function that calls the place_ships() function, which generates a ship by choosing one random place on board and then generating the rest of it horizontally or vertically (example below).

+-------------------------------+
|   |   |   |   |   | - |   |   |
|   |   |   |   |   | - |   |   |
|   |   |   |   |   | - |   |   |
| - | - | - | - | - | • | - | - |
|   |   |   |   |   | - |   |   |
|   |   |   |   |   | - |   |   |
|   |   |   |   |   | - |   |   |
+-------------------------------+

Database

Now we have to store ships’ location somewhere. We could place them in a plain text file, but then everyone could see where the ships are, so we have to hide them elsewhere. That’s when a proper database comes in handy. I used MongoDB for this as it fits my needs.

Modifying the README

Time to change our board visually by updating the README file. We can do it using the same method we would use to modify a text file. First, we read the file line by line and save content to a variable. We can then modify the specific lines we want. To create an empty table cell, I used a blank image with a link by using this format: [![](image link)](link that creates issue).

Committing, pushing, and closing the issue

The last step is to commit and push everything to GitHub. We can do it with GitHub Actions with a few commands (see battleships.yml > Commit and push). Then to keep everything clean, we should close the issue by using peter-evans/close-issue@v2.

Playing the game

The process is the same as creating a new game. Instead, we have to check if the location shot has the ship or not by using our database and modifying this location in README with either a white or red mark image.

Statistics

  • The statistics under the game title were made with shields.io.
  • A leaderboard is made by storing all users with their statistics and sorting the database by shots hit.

SHARE: