Notes on codes, projects and everything

Building problock – my personal experience

A few years ago, I was asked to build a game or simulation (alongside 2048) as a part of a job application. Being very impressed with Explorable Explanations, I implemented Conway’s Game of life with Javascript and jQuery (that was before ES6 became popular). Then I made a very simple grid maker jQuery plugin to dynamically generate a grid of divs. If you check the source code, you may realize I rely on Underscore.js a lot back then.

For the TL;DR folks, this is problock, it is rather unpolished.

Then @ncasenmare made this simulator, and it was quite addictive, but I really wanted it to be more customizable. Coincidentally I designed a DSL-like schema and made a parser for that. Originally the problem was to make something portable so some very light form of logic can be written and stored as plain JSON (or YAML)

It then became a small toy project I named “ruler” (yea, I am pretty bad with naming).

So with the grid maker, and the language, you would have thought I have the good enough combination to get started. I did but it was a lot more difficult than I initially expected. Then the project was scrapped not too long later.

Though I still really wanted to build that.

After that I moved on from jQuery, to backbone.js at work to quickly build prototypes for my research at work, then eventually I moved on to ReactJS so I could lend a hand when the team needed help (I also spent some time reading through AngularJS but the team hated it, also read a bit on Vue but I prefer the syntax of JSX).

Picking up React, and Redux (alongside shiny ES6) was a great experience, while it doesn’t make me like frontend development more, but it made sense. I like how React reminds me of functional programming, and Redux make state management more sensible. Handling events was my biggest complaint with jQuery (while it can be done, but I do find it really painful and tracing it is a nightmare).

Fast forward to earlier this month, when I dropped my unpaid projects, I figured I needed to build something fun before looking for the next job, then I revisited this idea. Then I started drafting roughly how the rules should be written for the blocks, and how should the state of the board stored. I also took some time to read about redux-toolkit, which greatly simplifies the code I needed to write.

Then I began working, but after building the main UI I got stuck and demotivated. While I have ruler (restructured and rewrote a small portion to get it to ES6), “widgetizing” it is hard (partly due to the initial design that used a lot of <code>basic.Context</code> call. Eventually I gave up writing a set of widgets to compose rules, and settle for a textarea as it is right now (also redesigned the evaluation part to simplify the rules).

And after a lot of struggles (and hair-pulling), I made problock (short for programmable block, told you I am bad with naming).

As of now problock is showing a game of life example, where you can click on tiles to flip the status of each of them. Then to advance to the next state, just tap space bar to advance after done clicking them. Not the best UX in this regard, but I do want to improve it (possibly removing key events and replace them with buttons one can click).

As the API for the blocks are still not fixed, the information below may be obsolete not long after this is published.

The context of each rule is the target block itself. For now, each block has a display property, that decides what is shown on the tile. I am planning to support a few different types of display, but currently only text works.

// example block context
let block_context = {display: { type: "TEXT", value: "your value"}};

It also has a definition of neighbours.

// example block context
let block_context = {neighbours: ['TOP_LEFT', 'TOP', 'TOP_RIGHT', 'LEFT', 'RIGHT', 'BOTTOM_LEFT', 'BOTTOM', 'BOTTOM_RIGHT' ]};

As the example is a game of life simulator, each block has at most 8 adjacent neighbours. These placeholders will then be converted actual position of block stored as @neighbours, for instance, for the block at (0, 0)

// example block context
let block_context = {neighbours: ['TOP_LEFT', 'TOP', 'TOP_RIGHT', 'LEFT', 'RIGHT', 'BOTTOM_LEFT', 'BOTTOM', 'BOTTOM_RIGHT' ]};
// during evaluation @neighbours is generated
{
    neighbours: ['TOP_LEFT', 'TOP', 'TOP_RIGHT', 'LEFT', 'RIGHT', 'BOTTOM_LEFT', 'BOTTOM', 'BOTTOM_RIGHT' ],
    "@neighbours": [[0, 1], [1, 0], [1, 1]]
};

Knowing what is made available during evaluation stage, one can then start to write rules as conditions or value evaluation. For instance, to flip the status of tiles from dead to alive, I need to write a condition that says the tile display property is dead.

["condition.Equal",["basic.Field","display"],{"type":"TEXT","value":"DEAD"}]

I don’t really care about the neighbouring tiles when I flip the state, so I just slap a tautology to it so it always evaluate to true.

["boolean.Tautology"]

Being heavily influenced by Lisp, you can write a more complex condition rule with the “DSL” too. For instance, I want to know if a tile is going to be dead when I advance a step (by pressing space bar), it has to then fulfill the following condition (tile is alive, and has either 2 to 3 neighbours).

["boolean.And", ["condition.Equal", ["basic.Field", "display"],
                                    { type: 'TEXT', value: "ALIVE" }],
                ["boolean.Not", ["condition.In", ["array.Length", ["basic.Field", "@neighbours"]],
                                                 [2, 3]]]]

Each of the neighbours needs to fulfill this rule too (neighbour must be alive).

["condition.Equal", ["basic.Field", "display"],
                    { type: 'TEXT', value: "ALIVE" }]

Then for the two conditions above, we can now set the value of display property to dead (death of overpopulation).

["basic.Value", { type: 'TEXT', value: "DEAD" }]

Why so obsessed about ruler, you may ask. One of the main goal of this project is to allow the users to export the configuration (and/or the state) of the board to be shared with his/her friends. While that can be done with a proper backend and generate a shortcode for each configuration, but I still think being able to export and import raw configuration is nice. People may be able to generate some sort of documentation, or tutorial for a given set of configuration. If done right it can be a very gentle introduction to programming.

Being the first revision, there are quite a number of things I still don’t quite like about (besides the horrible code as I wanted a quick prototype). The first one being the value of display property. It would be nice if I can somewhat simplify the value, besides being able to display different types of data. Perhaps make every property a rule?

// instead of
{display: {type: 'TEXT', value: 'foo'}}
// do this
{display: ['string.Value', 'foo']}
// then we can do this
{display: ['emoji.Value', '&amp;amp;#x1f63a;']}

Perhaps I can also set multiple properties when condition is met?

Perhaps I can adapt blockly to generate rules?

Possibilities are endless, will definitely revisit this again in the future. However, for now, enjoy.

leave your comment

name is required

email is required

have a blog?

This blog uses scripts to assist and automate comment moderation, and the author of this blog post does not hold responsibility in the content of posted comments. Please note that activities such as flaming, ungrounded accusations as well as spamming will not be entertained.

Click to change color scheme