How do I write minesweeper game in OCaml?

I am at the point where using ctypes I can create a Gtk4 window and listen to the events I need.

I could have a separate widget for each minefield, or draw everything on Gtk4 canvas.

I prefer to use canvas for this exercise and draw all the game elements using cairo library.

I am an OCaml noob with a history of frustrations, so I wonder what would be the least frustrating way to write a simple engine for the game?

I need mouse over and mouse click detections for the game elements and I could use the events to handle that. But how do I represent in OCaml the structure representing the state of the game?

I need something for the board dimensions, minefields, mine states and flags.

I did not read yet about the data structures or objects in OCaml. I only know hashes and lists.

As someone else who is an experienced developer but a far from experienced ocaml developer I would make three suggestions.

  1. Do take the time to read through the “Learn” section on ocaml.org and maybe download a couple of the free books for reference too.
  2. Start figuring out your data structures and state-change operations in a separate project.
  3. Iterate with really small changes and keep the code compiling.

The second point lets you easily switch back and fore between your user-interface and backend code when you get stuck on one of them. I find this helps me maintain enthusiasm for my “hobby” projects.

You can implement your backend multiple times too, thanks to Ocaml’s flexibility - as objects, procedural modules or functional code. I’d start with whatever approach is most familiar to you.

In terms of data-structures Array has a make_matrix function which feels like an obvious way to represent a grid of cells that might be covered, open or flagged. Then to track where your mines are a Map or HashTbl depending whether you want an immutable/functional data-structure or something updatable. You can play around with both quite easily in “utop”.

In terms of testing your backend code, “Alcotest” isn’t too hard to use, but you will have to write some comparison functions for your custom types. For this project I would be tempted by “expect”/“cram” tests though. These do simple text-diffs from printing out data structures. Both approaches are well supported by dune if you are using that.

For my own comfort, I’d probably write some “show_board” function anyway to print out cells as “.” or “1” or “F” etc. Once you have that, you might as well use it to test against as expected output.

And… once you have something to print the current minesweeper board, it isn’t much effort to accept a string like “FA9” to place a flag on a particular point and actually make it playable (although not pretty). Meanwhile, as you firm up the interface to your backend code you can start wiring up parts of your Gtk code.

The final point is something that seems to work for me, I don’t know whether you’ll find is useful or not. While you are changing your data-structures, the compiler will guide you very nicely towards all the places that need to be updated for your change. BUT making a bunch of changes at once will lead to a large number of errors that can be difficult to understand. So, the most helpful thing I’ve found is to make changes smaller than I normally would. A change so small it seems trivial, and then maybe a bit smaller than that. Add new field to a record, propagate through the code, check all errors have cleared, move on to the next change. This (plus committing frequently) leaves me feeling very comfortable in the state of my code as I think about my next change.

HTH and happy hacking

P.S. - impressed that you’ve started with C bindings. Not something I’ve tinkered with yet.

1 Like

I started with C bindings because I have similar projects in another language. Having it done in OCaml gives me a chance to compare it to the concrete example in another language. It makes less comparing apples and oranges.

I think that by going with gtk and devising C bindings you are likely making your life harder than it could be.

For example you could simply use these bindings to SDL or even the venerable graphics library. See for example this recent remake of boulder dash made by Andreas Rossberg. There is also this recently announced ocaml-elm-playground that could boot you faster into making the game rather than the infrastructure.

Personally I would likely simply go with a webpage with js_of_ocaml and brr. Here is a simple howto to get you started (more examples including how to use canvas here).

Regarding game structures perhaps you can find inspiration in the aformentioned boulder dash remake or in this 2048 remake.

3 Likes

I do not need the complete bindings for the whole of Gtk4 library. I have enough for my needs already. But thank you for other suggestions.

Ocaml-elm-playground looks particularly interesting.

concerning the game data structures, I think you will find this article interesting

http://decapode314.free.fr/re/tut/ocaml-re-tut.html

You didn’t mention your background in functional programming per se. In addition to what everybody else has suggested so far, I would start by thinking about whether you want to make your core data structures purely applicative or imperative. Certainly when interacting with the C bindings for UI, you will need mutation, but you get to choose where you want to draw the line elsewhere anywhere in the spectrum. A game like this is good way to either explore the standard library or develop your own structures to learn more about patterns that work well or do not work well in OCaml.

You could also try out @dbuenzli’s React library to see how the FRP style works with Gtk. (Full disclosure: I am not familiar with Gtk and I don’t know whether this would result in an impedance mismatch.) I also seem to remember there being a talk on YouTube about this but couldn’t find it with a quick search.

EDIT: Found a (rehosted?) version here: https://www.youtube.com/watch?v=0-tVf9BFTMY.

If you want to pursue the FRP way there is a terminal based breakout game in react’s test suite which you can compile with ocamlfind ocamlopt -linkpkg -package unix,react breakout.ml

I am a big fan of Elm language for front end Web. So one of the experiments will involve Elm architecture.

Not sure if it helps, but it could be interesting to look at the code for another OCaml implementation of minesweeper.

1 Like

Slight progress.

But why I can not use the same arguments as the field names?

We can type

let imp_resize width height =
    my_model := {!my_model with width=width; height=height} ;
    ()

Or even

let imp_resize width height =
    my_model := {!my_model with width; height} ;
    ()

What are you trying to do (and which error is displayed) ?

Ah i see it now!

My editor was rewriting my attempt to your second version. And silly me, I thought it was an error.

This is a WIP game engine for OCaml. It includes a project generator, and outputs to both native with SDL and js_of_ocaml.

The js_of_ocaml output is bundled in a single html file.

There is also a nice asset handling feature where you can add an asset in a folder and you can access it as an OCaml value. It is bundled in the executable and html file.

The big missing features are that the sound support is partial (you can’t stop a sound for instance) and there is no support for savefiles.

3 Likes

There is minesweeper example in the js_of_ocaml repo:

3 Likes

Yes, this is a commonly used technique and can make your code more readable. Just to save you further headaches, similar punning techniques can apply to labeled function arguments and custom binding operators.

I’m somewhat surprised your editor was so aggressive about rewriting this way though, since the duplicated syntax is valid. In fact, I’ve had the opposite experience with ocamlformat rewriting my let bindings to remove punning and duplicate the RHS.

2 Likes

Using a C bindings doesn’t always force you to use some imperative style programming.
In sdl2, for example, you don’t need to use callbacks, so if you want to adopt a functional style, you can pass your functional state through all the three main parts of the program. Event processing, update of the state, and display. The complete result could even be seen as purelly functional, and deterministic. The user input can be seen as a discrete input list of events, and the display function can be seen as a pure function, which transforms the input state into a result image. If you decide to display at a fixed fps (frames par seconds), the update function can be made to update the state at a fixed number of milliseconds, and if you use integers for calculations, you can get a deterministic result.
If you see an unexpected behavior while testing, and if you log user inputs in a list, we can reproduce it while providing the same inputs again in a non-interactive way, and the result can be a list of images.

let img_list, final_state =
  let initial_state = initialise_state () in
  List.fold_left (fun (imgs, state) event ->
    let state = process_event state event in
    let state = update state in
    let img = render_state state in
    (img::imgs, state)
  ) ([], initial_state) events_list

The three values state, event_list and img_list can be functional, as long as the three functions in the loop. The result can be seen as a nice functional “Model-View-Controler” pattern, for functional programming adepts.


If the UI library provides callbacks, references can be used in a very localised way.
And with javascript backends, it even helps a lot to create fixed fps rates.


Writing everything in a functional way is often quite chalenging though.
And it often looks like a mind teaser puzzle.

While writing this shmup I was not able to figure out how to filter the player bullets and the enemies in a functional way. These are 2 lists, and every elements of each list have to be compared in pairs (which is a cartesian-product comparision of the elements, while preserving the initial structure of the input lists with no duplications). I have only been able to do it several days ago, with the help of claude-3-sonnet, which provided me this tower-defense for study, where there is also a list of enemies and a list of towers.

For this problem, 2 nested for loops (or 2 nested List.iter), with mutable fields (or a list ref) is much easier to do. This is where we like this programming language to be impure, so that we can use the imperative style as a rescue solution, before to solve these kind of functional puzzles.