-- Leo's gemini proxy

-- Connecting to gemi.dev:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Building Minesweeper for Gemini

2023-01-08 | #cgi #games | @Acidus


Over vacation I built a complete Minesweeper game on my capsule. I implemented flags, chording, different difficulties, and even custom games. You can play it here!


Play MineSweeper

"Minesweeper (video game)" via Gemipedia


Why write another game?


I had a lot of fun building Where in the World, a geography game in Gemini last fall. This was the first game I had written just for fun in 20+ years.


🗺 Where In the World? A geography game


The constraints of Gemini created some challenges that were fun to solve:

How to help the user correctly select from a list of 200+ available countries.

How to maintain state

How to draw graphics in a text-first protocol like Gemini


I knew I wanted to try make another game, and started thinking about different options in the back of my mind when I had a few moments between life and work. I was thinking about more traditional games and an idea that kept coming up was Battleship.


Battleship via Gemipedia.


I liked a traditional board game like Battleship for a few reasons:

The simple grid, both because it would be easy to draw on a single screen and the "row, column" format was a clean and simple way to get input from the user.

The game logic was relatively simple.

I think the game would be fun as the map is slowly revealed.


However as I thought about it more I ran into some issues:

Having the user initially place their ships would be complicated and clumsy. Since the player must do this to setup the game before the start, it would make the initial experience pretty painful.

Battleship is a 2 player game! Even once I solved how to have 2 humans play each-other, each player would have wait for the other, and Gemini isn't really suited for auto-updating or "push"-style events.

If I made it a player-vs-computer game, I would need to create a computer player to play against you, and at least for now that didn't sound fun to do. It would be easy to end up with a computer player that was either too good, or randomly made obviously stupid moves, both of which wouldn't be fun for the player.


Taking ideas from the good parts and bad parts, I decided I needed a game that:

Used a simple grid

Didn't require lots of input from the user to setup the game

Didn't have a 2nd player, human or otherwise


Which lead me to think of Minesweeper!

Minesweeper via Gemipedia


Minesweeper is actually one of the first games I made as a teenager, written in TI-BASIC on a graphing calculator, instead of paying attention in school. Fundamentally, you have a 2D matrix, representing all the tiles of the game. You place mines at random coordinates, then, for all the tiles without a mine, you fill it with the count of mines on adjacent tiles. With some clever bitmasking you can use the same matrix to also keep track of track what tiles have been revealed, or have flags.


Graphics

The first version of the game looked something like this:


Flags: 6 Total Mines: 10

  ABCDEFGHIJKLMNO
A            112★ A
B   111      1★2★ B
C  12·1      1121 C
D  1·21           D
E  222        111 E
F 12★1     1111★. F
G ★211     1..... G
H 11      12..... H
I         1...... I
  ABCDEFGHIJKLMNO

The '*' is a flag, and '.' is an area you still need to explore. This is really similar to how my our TI-BASIC game looked, since that used text characters and didn't have access to the extended ASCII characters. While a promising start, I wasn't a fan of this. The board was too dense. Characters are taller than they are wide, so the board felt cramped and it was hard to moves your eyes up to figure out the column you wanted to select.


Luckily, I solved this be accident when I started to use emoji. I knew emoji could create richer graphics since there is an emoji for a flag, and for a bomb, and even blocks and other things. But the challenge is some emoji have a "screen width" of more than 1 character. This messed up the columns as your can see below:


Flags: 6 Total Mines: 10

  ABCDEFGHIJKLMNO
A            112🚩 A
B   111      1🚩2🚩 B
C  12·1      1121 C
D  1·21           D
E  222        111 E
F 12🚩1     1111🚩. F
G 🚩211     1..... G
H 11      12..... H
I         1...... I
  ABCDEFGHIJKLMNO

The solution was to make columns 2 characters wide, with some blank space, so the emoji would fit, but it also solved the "cramped" and "dense" feeling of the board:


  A B C D E F G H I J K L M N O
a         1 🚩1       1 · · · ·  a
b         1 1 1   1 1 2 1 1 · ·  b
c       1 1 1     1 🚩1   1 · ·  c
d       1 🚩2 1 1 1 1 1   1 · ·  d
e 1 1   1 1 2 🚩1         1 1 1  e
f 🚩2 2 1 1 2 2 2                f
g · · · · · · · 1       1 1 1    g
h · · · · · · · 2 1     1 · 1    h
i · · · · · · · 🚩1     1 · 1    i
  A B C D E F G H I J K L M N O

Other fun stuff


Just as with Where in the World, I store game state in the query string, instead of storing it on the backend and requiring a client-side side certificate. This create the "feature/bug" that you can simply use the back button to "undo" a move. Since the input method is as precise as a mouse, sometimes you select the wrong tile, so being able to "undo" something is actually helpful. The game state is a binary blob representing the size of the board, the start time, and the state of all the tiles. This can be quite large, so I gzip compress it, base64 encoded it, which I keep in the path. Overall this worked well, though there was an edge case with vanilla base64 that lead to some issues that I @mozz helped me work around:

CGI Variable "PATH_INFO" incorrectly removing runs of slash characters causing errors in CGI scripts

To speed up the game, I implemented a feature used in other version of minesweeper, chording, where you can uncover other tiles more quickly. This really helps.

I put a cheat code in the game too! Something happens.

Entering coordinates can be a little clunky, so based on @skyjake's feedback, I switched to a system where rows and columns use different letter cases, so you can enter them in either other.

In both my work, and in personal projects, I've repeatedly learned that the final 5-10% of the work is really what makes the project. Adding things like an elapsed timer, a remaining tiles status line, and a progress percentage


Final thoughts, and my next game?


As a whole, I think my Gemini version of Minesweeper turned out just OK. So while I'm playing minesweeper, especially at night before I go to bed, its not as exciting to me as I would have hoped. That could just be me. I hope you all like it.


The reason I feel this implementation isn't excellent all comes down to the "think-move-look" loop. Minesweeper is a pretty fast game. A typical game involves dozens and dozens of moves. Often as you uncover more of the board, you immediately see several tiles that you need to click or where you want to put flags. Only now you have to do the tedious process of making multiple moves really quickly to implement those moves. That's the bottleneck. In short minesweeper has a low "thinking to moves" ratio.


This leads me to think that a game with a higher "thinking to moves" ratio would be better suited for Gemini. And the board game that comes to mind that has a high "thinking to moves" ratio is chess. Specifically chess against a computer opponent. I'm not sure when I'll do this, but I think that will be my next game.


Of course, I really don't want to implement a chess engine, but there are open source chess engines of various skills. Even better these chess engines are decoupled from the user interface. This means I can write a Gemini interface which displays the board and gets the user's input for their move, and pass it to the chess engine for the computer to make a move!


Universal Chess Interface via Gemipedia


Can you think of another game I should build? Drop me an email or ping me on Station

-- Response ended

-- Page fetched on Tue May 21 13:11:50 2024