Battleship solitaire is a Japanese-style logic puzzle in which one deduces the positions of ships based on the number in each row and column, the number of each length of ship, and some basic rules. This is a Next.js rendition of that puzzle meant to automatically solve any* puzzle you throw at it.
*Cannot solve hardmode puzzles like those on lukerissacher.com, see about
This repository served primarily as a vessel through which I learned React.js. This was a logic puzzle that I did extensively in elementary school. The idea of creating a tool to automatically solve these simple puzzles seemed like a great small project, and thus this repository was born. It's grown to become my largest project, with full unit testing (on the main logic files) and thousands of lines of code. I've refactored many, many times, including switching from CRA to Next, migrating to TypeScript, and more.
Although this tool can solve any puzzle that can be completed through pure logic, some websites like lukerissacher.com can also create puzzles that can only be solved with guess-and-check. Initially this was a planned feature, but I've since limited the scope of this project so I could move on to new plans. This tool can still help with these puzzles, but it is not designed for them and will require a lot of manual input.
There are only a few rules to this game:
- Ships cannot touch, even diagonally.
- There cannot be more ships in a row/column than is specified at the top/side.
- The number of ships of each length must match that specified by the puzzle.
- There are only horizontal/vertical ships. They cannot be diagonal.
Deploying a local server is extremely simple. Install Node.js, then run these commands:
npm install -g pnpm@latest-10 # pnpm is like npm, but much faster
pnpm i # install dependencies
pnpm build # compile the project
pnpm start # run the serverYour new web server should now be accessible at localhost:3000.
💡 Tip: for a development server, use
pnpm devinstead to auto-reload after changes.
If you would like to contribute to the project, you are more than welcome, so long as you follow our Code of Conduct. Here are a couple commands to get you started:
pnpm dev # start a development server
pnpm lint # lint your code with ESLint
pnpm test # run unit tests on your codeIf you use Visual Studio Code, we also recommend the ESLint extension.
It catches styling errors as you code, drastically speeding up development compared to only using
pnpm lint. Additionally, you can enable ESLint as a formatter through its settings menu (Eslint
> Format: Enable).
Boards can be exported to base 64 through the Board.export function. Exported boards can be imported
via Board.from, which returns a new Board with the imported data. Here is each property exported with
the number of bits it uses:
| property | number of bits | type |
|---|---|---|
| width | 5 | number |
| height | 5 | number |
| solveData | 1 | boolean |
| colCounts | a = ceil(log2(width)) + 1 |
number[] |
| rowCounts | b = ceil(log2(height)) + 1 |
number[] |
| runs | 8 + max(a, b) * numRuns * 2 |
number[] |
| state | 6 to width * height * 5 |
see below |
Note: colCounts, rowCounts, and runs are only present if solveData is true.
Note: the runs property is in the format (length of ship, count), both taking the same number of bits.
The state property is a bit more complicated. Normal squares are in the format (pinned: 1b, type:
4b). For sequences of unknown squares or water, .export adds 11111 to denote unknown squares and
11110 to denote sequences of water. It then appends one less than the number of squares in the sequence
in ceil(log2(width * height + 1)) bits.
The logical Board.ts function returns the export as is, but exports
on the website undergo one last step. To ensure URL compatibility, characters like +, /, and = are
replaced with safe counterparts. + is replaced with -, / is replaced with _, and = is removed
entirely. On import, these replacements are reversed and equals signs are dynamically reintroduced (only
on the website, Board.ts does not support these exports without modification).
For more details, view the .export method directly in Board.ts