Subgrid - Recursive Puzzle Game

Hi everyone, I just released a little puzzle game in which the solutions become the tiles of the next level.

It was actually quite challenging finding a good type to represent a level, as it depends on the prior levels.

The type I came up with was

type alias Game =
    { stage : Stage
    , levels : Dict String (Dict Int SavedStage)
    , ...
    }

type alias Stage =
    { grid : Dict ( Int, Int ) Cell
    , gridSize : Int
    , ...
    }


type alias SavedStage =
    { connections :
        Dict
            RelativePos
            { from : RelativePos
            , originId : Int
            , path : List RelativePos
            }
    , paths : Dict RelativePos { origins : Set Int }
    , grid : Dict RelativePos Cell
    , gridSize : Int
    , level : Level
    }

A single puzzle of a level is a Stage – multiple stages form one level. Once a player solves a stage, I compute everything I need to use it as a tile. In particular, the connections that tells me where the power is flowing and paths that tells me which pixels need to be lit up if power is coming in from a specific direction. Additionally, I also store the original grid, so that I can turn a SavedStage back into a Stage, if the user wants to change their solutions.

Another trick that helped me do fewer mistakes was to introduce a wrapper type for the relative positions:

{-| Comparable wrapper type for (Int,Int) -}
type alias RelativePos =
    ( ( Int, Int ), String )

fromTuple : ( Int, Int ) -> RelativePos
fromTuple pos =
    ( pos, "RelativePos" )

A RelativePos is comparable, so I can use it as keys in a dict. A relative position can be turned into a direction, and a direction can be added to a position. This way, I made sure that I never mix the positions of the puzzle-tiles with the positions of the pixels in a tiles.

Developing a recursive game was quite challenging. I got into a lot of off-by-one errors and state explosion problems. But I also learned a lot. You can check out the source code if you are interested.


Thanks for reading this little post, and I hope you liked the game.

11 Likes

@Lucas_Payr The link you shared doesn’t work but this one does, Subgrid.

1 Like

This is awesome. Thanks for the explanation and sharing the code. :slight_smile:

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.