Credit

Sliding Puzzle © 2023 by Oli Solomons is licensed under CC BY-SA 4.0

I programmed this game, but all credit for the concept and the level design goes to Dmitry Kamenetsky, who posed these questions on the puzzling stackexchange (e.g. Sliding crosses in a 5x5 grid). (this stackexchange user content is also licensed under CC BY-SA 4.0)

How to play

The goal is to move pieces (the circles) into specific spots - the goal for each level is displayed at the top of the screen. However, you can't just move the pieces anywhere you want; the only move you're allowed to make is to slide a piece in a direction, and it will keep going until it hits a wall or another piece.

Controls

Click and drag to move a piece, or touch and drag on a touchscreen.

There are also keyboard controls:

  • press tab to cycle through the pieces, selecting each one in turn (or click on a piece to select it).
  • use arrow keys or WASD to move the selected piece.
  • after completing a level, press space to continue.

About the Code

Github link: https://github.com/olisolomons/sliding-puzzle

I made this game in clojurescript (shadow-cljs), using the quil library for graphics, which is a wrapper for p5.js.

I think it turned out pretty well, despite not having any music/sound and only 4 levels!

To compile it from source on Linux, install node.js and npm, then in the source directory run npm install. You should now have shadow-cljs installed. Run npx shadow-cljs start to start a server and npx shadow-cljs compile app to compile the clojurescript to javascript - the game should now be hosted at localhost:8000. Remember to stop the server afterwards with npx shadow-cljs stop.

Quil has functionality for passing around an immutable state value and event functions that can return altered versions of the state. I used clojure multimethods to dispatch a different set of draw/update/event functions depending on the scene being rendered. Each scene is organised into a different file, with the logic for the actual main game being stored in src/main/sliding_puzzle/game.cljs. The different levels are stored in src/main/sliding_puzzle/levels.cljs.

All the animations are hand-coded with easing functions.

StatusReleased
PlatformsHTML5
Rating
Rated 4.0 out of 5 stars
(1 total ratings)
Authorolisolomons
GenrePuzzle
Tagsclojure, Minimalist

Download

Download
sliding-puzzle-source-code.zip 28 kB

Comments

Log in with itch.io to leave a comment.

(1 edit)

I'm a bit late, but I hope you'll see this comment....

When I saw you used ClojureScript and Quil, it inspired me to make my own game for Spring Lisp Game Jam 2024.

I took a look at your code, and there are some nice concepts I didn't know before, e.g. using multimethods for handling different screens — I'll be using them too.

----

Since you seem experienced with Quil, maybe you can help me with the problem I'm having, and it is a situation you didn't have in your own game. Is it possible to register multiple key-presses with one long press-and-hold of a key? Currently no matter how long I hold some key, it is the same as a single short press.

Here I tried to explain it in a bit more detail: https://github.com/quil/quil/issues/413

Thank you in advance!

(1 edit)

Hello, it's great to see I've inspired a game! I'm not super experienced with Quil, but I think I can help - I don't think Quil has the exact functionality you're looking for, but you can still make it work. For your use-case, I'd change the keypress function to modify the game state to record that the key is pressed, and add a key-released function to record that it is no longer pressed, and do the check-and-move code inside the game's update function using the info recorded in the game state. Does that make sense? Good luck with the game jam, and feel free to ask if you have any more questions!

Edit: actually if you only need the most recently pressed key, you could probably ignore the stuff I said about recording key presses in the state and just use q/key-pressed? and q/key-as-keyword inside the update function instead of inside the key-pressed function.

(1 edit)

Thanks for the idea about "q/key-pressed? and q/key-as-keyword inside the update function" — I've just tried it and I can make it work!

The only problem I need to work-around is the frame rate. If the frame rate is too high (and even 30 fps is), then even a short key press will be counted multiple times. On the other hand, if the frame rate is too low (and even 10 fps can be), then a (very) short key press will not be recognized at all.

(1 edit) (+1)

Quil doesn't give you very much of this out-of-the-box, it's up to you to find a way to make your player move how you want them to move. For example, I made a player that moves quite jerkily here, with some "long key press" functionality similar to how you were looking for: http://www.quil.info/sketches/show/926b90ca28f03e9511165d337bb7ed6089f07381d1264.... I did this by adding a :last-move-time key into the state to prevent it from moving after it has just moved, so you don't need to mess around with frame rate. I also added the moving functionality into both update and key-press functions, just in case a key press was very very short and didn't get picked up by the update function.

Or you could look at my sliding puzzle code to get some ideas about how to animate the motion - I add a key into the :animations map in the state, then draw piece positions using lerp (linear interpolation) and the current time to get the current position. I remove finished animations in the update function.

This was a very fun game. It even got me thinking about the math behind the solutions, but I didn't get too far, I don't know if there is a solution other than brute force (which can be reduced a bit by symmetries).


You could also introduce fixed obstacles (or just more balls), or dynamic obstacles that change state as balls move. I think it's hard to come up with good maps, you may want to write a computational tool that tries to solve the map for you so that you can find maps that have nice solutions. Are you interested in something like that to extend the game further?

Thanks for playing! That's an interesting thought - I feel like a non-brute-force algorithm is possible, and I have the outline of an aglorithm in my head (for the "get 1 of the 3 pieces into a given position" problem), but it has too many corner cases...

I like your map ideas, and I might take it further!