Peg solitaire game in Clojure
I made another silly little Clojure game, it’s the peg solitaire game with 33 holes. Making simple games like this is a fun way to learn a new language, I think.
The game mechanics follows the version of the game in the book BASIC Computer Games, but there its called “High I-Q” for some reason. Here’s a short animation showing how the game is played:
You select pegs and holes by entering the row number first (1-7) and then the column number (1-7). So to move the piece at row 6 column 4, you enter 64. To move the piece to row 4 column 4, you enter 44.
The code is on GitLab. Run it with
clj -M peg-solitaire.clj
Takeaways:
- 1. Clear the console with
(println "\033[H\033[2J")
. - 2.
map-index
is likemap
but you also get the index of the current item. - 3. Simplify nested expressions with
->>
and->
. - 4. Access and change non-trivial data structures with
get-in
andupdate-in
. - 5. A
loop
withrecur
can remove the need for atoms.
1: It was surprisingly difficult to find out how to clear the console in
Clojure. After a long search I settled on this weird thing which does
work (for me): (println "\033[H\033[2J")
. I wonder how portable it is,
though.
2: map
is very useful but this time I also needed to know the index of
the current item being processed and map
just doesn’t provide it.
Thankfully, map
has a siebling called map-indexed
that does just
that.
3: The first version of this game had a lot of nested expressions which
were hard to read. I tried to fix that with let
, which did simplify
things to an extent, but it was still quite messy. Then I figured out
how to use ->
and ->>
and readability improved significantly.
4: I’m using a vector of vectors to represent the game board, i.e. a
“matrix”. A matrix felt like a natural choice but it took me a while
to figure out that I should access and change its values with get-in
and update-in
.
5: My initial instinct was to store the game board in an atom since I
would have to update it after every move the player makes. But by using
loop
and recur
, I can set the board to its initial state in the
beginning of the loop
and then rebind it to the new board state after
the player’s move.