avatar deldreth
Walter Melon
App Thumbnail

After playing a mobile game where colored liquids were transferred into different bottles based on topmost color and existing volume. I decided to spend an afternoon to build out a web based version of the game. This gave me a chance to experiment with Ionic's Stencil.js and ended up being a good development excercise.

Game

Premise

The game board consists of a user defined (defaults to 6) bottles arranged in a grid. Each bottle contains four quarter segments of color that can be transferred from one bottle to another by clicking on a bottle and then clicking on another bottle.

Color will only be moved if:

  1. The receiving bottle is empty.
  2. The receiving bottle's top most color is the same as the providing bottle.
  3. The receiving bottle's remaining volume is greater than or equal to the color volume that will be transferred.

The UI should provide:

  1. As close to an ADA compliant color scheme as possible (difficult in games with 8+ colors).
  2. Visual indicator that a bottle is selected.
  3. Visual indicator that a transfer is invalid.
  4. Visual indicator that the game is complete.
  5. An optional mechanism to undo any transfer.
  6. Controls to adjust the game difficulty.
    • Number of colors
    • Number of undoes
  7. Controls to create a new game and reset the current game.
  8. Help control to visually convey how to play the game.
  9. A count of the number of moves.

Tech Stack

Lerna, the repository is a monorepo with the intent of providing separation of the underlying UI components of the game with the container and business logic of the game.

Stencil.js, Ionic's framework for creating and publishing web components. There are two packages within the monorepo: components and game. Both of these packages were scaffolded with Stencil.js. With the components package using the component base and the game package using the app base.

Structure

Bottle Component

The a-bottle web component is the base UI element provided from the components package. It can receive a few props that allows the controlling board to alter its state.
PropertyAttributeDescription
colorscolorsThe list of colors represented as an array
finishedfinishedIndicate a winning state
selectedselectedIndicate that the bottle is selected
warningwarningIndicate that the bottle cannot be targeted
The most important of these props being colors which receives a string encoded JSON that represents the HTML or hex colors contained in the bottle. Rendered top down from left to right.
<a-bottle colors='["#bd93f9", "#ff5555", "#50fa7b", "#ffb86c"]' />

Game Package

The game package contains a Stencil.js application that imports the components package and uses the a-bottle component to create the board, provide instructions, and a set of UI controls.

All of the game logic is housed within the app-board component and a redux slice to handle some of the actions dispatched from the board. This slice is responsible for initializing the board and maintaining the visual state of the game which is then used to render each a-bottle component.

The initial state of the slice. Here selectedIndex and warningIndex are integers that map to which bottle the user has selected and which bottle has an error state due to an incorrect move. The previousStates array contains the previous states of the board. After a move is completed the previous state of the board is pushed onto this array.

{
  "board": [],
  "selectedIndex": null,
  "warningIndex": null,
  "previousStates": [],
  "undos": Number.POSITIVE_INFINITY,
}