This fall, I started building a puzzle app called Logike. Itās a game that focuses on building logic skills, and from a programming and design perspective, itās alsoĀ the most challenging project Iāve ever brought to fruition. Thereās a lot to talk about, so I broke it down into a few partsĀ š
TLDR: If you just want to try Logike, you canĀ here!
The story
With few exceptions, most of the memories from when I was very young are faint at best. One such exception relates to when I was in Kindergarten. We had a lot of āfree playā time, as you do when youāre 5 years old, and during that time we could chose from a whole bunch of different activities. Actual examples include: making necklaces with beads,Ā taking apart old broken motherboards using pliers and hammers, or in the more educational department,Ā puzzle games to develop logic skills.
My favourite game involved placing coloured shapes on a grid in order to satisfy a logical conditions on the supplied cards. Theyād start out really easy and get progressively more difficult, to the point where they were no longer feasible for the average 5 year old.Ā It was a lot like Sudoku, but the difference was that this game mixed and matched and layered many different andĀ nuancedĀ types of logic. Sudoku games can be solved with the same algorithm each time, whereas the one to solve this game was far more complex and varied.
Fast forward twenty years and Iām looking for a project idea to help me learn front-end. I donāt remember what made me think of the puzzle game I played as a kid, but it popped into my mind and I went with it! No-one seemed to have digitized the game, and I realized that through code there were ways to take itĀ even further.
What it looks like
There are two major things that the app lets you do: solve puzzles, andĀ buildĀ them. Lets start with the part where the fun happens!
SOLVING PUZZLES
Solving puzzles is pretty straightforward: each puzzle consists of a set of logical conditions, and itās up to you to move coloured blocks onto the board so that all of the conditions will beĀ true.
However, the conditions can become quiteĀ complexā¦
Or downrightĀ difficult, like this oneā¦
Instead of telling you where specificĀ entitiesĀ (the coloured shapes in this case) need to be, this difficult puzzle only tells you about entityĀ properties(colours, shapes)Ā that could apply to a slew of different entities!
For now, the logical conditions are:
- Some entity orĀ propertyĀ is here.
- Some entity or propertyĀ is not here.
- Some entity or propertyĀ could be here.
- Some entity or property is/isnāt/could beĀ hereĀ relative toĀ some other entity orĀ property.
Additionally, the grids for the logical conditions can also beĀ smallerĀ than the puzzle board itself, meaning that a 2Ć2 condition could theoretically apply to one of 4 places of a 3Ć3 board.
BUILDING PUZZLES
As for the puzzle builder,Ā itās a lot less mature than the rest of Logike, but functionally it does what it needs to. Initially, I wrote all the puzzles by hand in one massive JavaScript class. It was great for prototyping, but it wasnāt ideal for production, so I refactored all of the puzzles into JSON files. This is whatĀ oneĀ logical condition looks like in JSON now:
Imagine writing dozens of chunks of code like this by hand, and trying to visualize a puzzle with them. It just isnāt pleasant, so I made a GUI (Graphical User Interface) that writes the JSON for you!Ā š
I talked about entities and properties a bit earlier, but itās really in the builder that they start to shine! ByĀ abstractingĀ the different parts of the puzzles above, I realized thatĀ the code I was writing could be applied to far more than just coloured shapes.
In the first part of the builder, you can chose a different set of entities than the classic shapes, and you get to chose the size of the puzzle as well! Technically, thereās no maximum size for the puzzle, but itās currently limited to a 5Ć5 grid until I smooth out the design to accommodate larger ones.
The most important part of the builder is the part that writes the logical conditions. Each one is comprised of aĀ selectorĀ (the entity or property youāre referring to in the logical condition) and a grid filled with conditions. The tool lets you visually build each grid, and see the puzzle as it will appear when someoneās trying to solve it.
When youāre done, you come up with a clever name, rank the difficulty of the puzzle, and the download the resulting JSON. Thereās currently no user accounts, or database to deal with storing user-generated puzzles, but this is a good first step.Ā A teacher could technically build a bunch of puzzles and send them to their students, who can load them up on the puzzle selection screen.
Under the hood
In the past, I would go into a programming project head-first, and start coding immediately. While this would be great for my short term motivation (features being built, andĀ fast), in the long run it led to depressingly messy code, and made for unsustainable projects.Ā Logike was the first project where I actually took some time to work on the architecture, and boy did that pay off!
This planning allowed me to build the app in the most efficient way possible, given my current skill level. It also made it possible to shrink my puzzle files down to sizesĀ measurable in bytes!
The whole thing is built in React, so itās a mix ofĀ HTML,Ā CSS, andĀ JavaScript.Ā Additionally, anything that isnāt part of the core application logic isĀ JSON. All of this lives on a freeĀ HerokuĀ server, at least for now.
As far as technologies go,Ā thereās not much fancy programming witchcraft going on, but that doesnāt mean that the project itself is simple.Ā There were a bunch ofĀ technical challengesĀ that had very little to do with the tech used,Ā the biggest one was making the code sufficiently generic.
I could have taken a bunch of shortcuts and just hard-coded everything based on the coloured shapes and left it at that, but then Iād be missing out on the chance to make a much more powerful too. So I ended up with a bunch of classes like this one:
// an Entity is the main element that is manipulated in the puzzle. // it has properties, a name based on the properties, // a common name which may differ from the name, and an image // ex: red square, potato, JK Rowling class Entity { constructor(commonName, properties, img) { this.properties = properties; // an array; this.name = Object.values(properties.map((property) => { return property.name } )).join("-"); this.commonName = commonName; // for display purposes ONLY this.img = img; } } export default Entity;
With all this abstraction, consistent and meaningful naming becomes super important, and at a certain pointĀ collisionsĀ can occur between your appās logic and the programming languageās reserved keywords and pattern names.
- EntitiesĀ could have been calledĀ objects, butĀ
Object
Ā is a pretty important keyword thatās part of JavaScript.
- PropertiesĀ could have been calledĀ parameters, orĀ attributes, but parameters are found in JavaScript functions, and attributes are found in HTML tags. Technically, in React,Ā
props
Ā stands for properties, but no-one writes it out the long way, even in their code, so this was the safer option.
- SelectorsĀ are used in CSS, but at least they behave the exact same way in Logikeās logical conditions, and it wasnāt a reserved keyword.
The second biggest challenge was validating the pure logic found in the puzzles.
This is a bit of code that validates whether an individual logic cell in the logical condition is being respected.
// returns false if the selector is found in a place it's not supposed to be. Otherwise returns true const validateLogicCell = (selector, ansCell, logicCell) => { var matchesSelector = false; // checks to see if the answer matches the selector if (selector === ansCell) { matchesSelector = true; } else if (selectorIsPartial(selector, entities) && ansCell.includes(selector) ) { matchesSelector = true; } var selectorCanBeHere = false; if (logicCell == null || logicCell === "empty") { selectorCanBeHere = true; } var selectorIsHere = false; if (logicCell === true) { selectorIsHere = true; } if ((matchesSelector && (selectorCanBeHere || selectorIsHere)) // matches selector in specific cell, therefore the cell needs to contain true or null || (!matchesSelector && (!selectorIsHere || typeof logicCell === "string"))) // doesn't match selector, therefore the cell must contain false or another selector { return true; } else { return false; } };
Does your head hurt?Ā š
Validating that a blue circle is in the top-right cell is easy. Validating thatĀ andĀ every other thing Iāve mentioned is a whole other story, and likely makes a terrifying looking flowchart!
How to try it
The puzzle app lives atĀ logike.confusedretriever.comĀ and eventually at logike.app once I figure out how SSL works.
It works on desktop or mobile, though thereās some features that are restricted in the puzzle builder on iOS for the moment.
Let me know what you think, and if you make some cool puzzles be sure to share them with me!Ā š
Whatās next
What Iāve made so far is just the tip of the iceberg. I see a lot of potential with Logike, so Iād like to keep developing it.
Hereās the current to-do list, more or less in order:
- Puzzle Builder design improvements
- enableĀ editing logical conditions
- enable reordering logical conditions
- Persistent save state after end of browser session (accounts + database?, Cookie?)
- Ability toĀ share puzzles without downloading/uploading.
- JSON V2 (remove ALL duplicate data and add IDs to entities and properties instead)
- more robust entity validation (unique names that arenāt based on properties)
- Creating new puzzles
- Tweaking old puzzles
- improving entity set images
- Fixing nasty iOS bugs
- Fixing toast jitters
- Improve test suite
- Validation improvements (duplicate entities, more robust property selection)
- Puzzle builder validation (to giveĀ feedback preventing impossible puzzles)
- Ghost images to fix sizing issues
- Design improvements toĀ support large puzzles
- Shuffle-able logical conditions
- OnboardingĀ flow
- Entity set builder
- URLs that lead to specific parts of the app (builder, specific puzzles, etc)
- logike.appĀ SSL
- ā¦
For now Iām taking a bit of a break from the puzzle app to work on Compass, but I plan on alternating between the two projects until I feel like Logike is pretty mature.
Phew!Ā šĀ That was a lot!
Thanks for taking the time to give this a read, and Iāll keep posting updates here whenever I start chipping away at the next next Logike releaseĀ š
Until then, keep being awesome!Ā š