Sun
cloud cloud cloud cloud cloudcloud cloud cloud cloud cloudcloud cloud cloud cloud cloudcloud cloud cloud cloud cloud

Zandgall.com

SAND!

and fish and reeds and water and clouds and

A JavaScript port for easy access

s: sand, w: water, a: air, x: stone, 1: seed, e: fish egg

ctrl: single place, up/down arrow: change place size

Sand Engine

The above is a port of the C program doing essentially the same thing out of the box, with one key difference.

The desktop C version of this programs comes with a single C file, and several rulesets. The C file is simply an engine, with the rulesets being written in custom scripting language.

The scripting language can define elements by giving a color, and listing tags of the element. These tags can then be used in rules to describe how elements with specified tags act. In order to simplify the rulewriting process, you can make shorthands for terms. Look through the following sections to get an idea of the syntax and how these rules work.

Elements

An element is defined as shown on the right. First, pick a color in hex. If you want the user to be able to draw the element to the canvas, you can add a single character to the end to denote a key the user can press to select it. The lines following the element start with a '-' and have strings that denote 'tags' of this element. These tags can be selected in rules and used to have elements interact with eachother.

Here we've defined a tan element with the keybind "s", it is tagged as "sand", "solid", "fallable", and "pileable". The solid tag can be used to make sure nothing falls through it. The fallable tag can be used to make sure it falls straight down, and pileable can be used to make elements form piles rather than pillars.

#f2d994: s
- "sand"
- "solid"
- "fallable"
- "pileable"

Symbols

Symbols can be used in rule definitions in order to make rules more coherent. They can be defined by typing any character not including "#", "*" or " ". You assign it to an element tag, color, or reference, by adding a '=>' before a string containing the tag you want to use in shorthand.

In this example, we add shorthand for "fallable", "passthrough", "solid", and "pileable" elements with the characters "f", "0", "s" and "p", and the color "#ff0000" with "r", and the reference (0, -1) with "^" which you can see being used in rules later on.

f => "fallable"
0 => "passthrough"
s => "solid"
p => "pileable"

r => #ff0000

^ => (0, -1)
\ => (1, 1)
/ => (-1, -1)

Rules

Rules are initialized with the "rule:" phrase. They can include 3 flags in any order at any point in the line, "x", "y", and a "num%". The flags 'x' and 'y' tell the engine that the rule can be mirrored horizontally and/or vertically ("x" and "y" respectively). Say you want to select the pattern a b c in your rule, but would also want the same rule flipped to select c b a and perform the same action (also flipped) on it, you would just specify 'x'. The "num%" flag will make it so there's only a "num%" chance of it happening any given execution. This can be used to feign slowness or friction in certain rules.

The rules themselves are defined in two 5 by 5 series of character seperated by whitespaces. There must be a two character seperator in the 3rd row between the two 5x5 sides. I always put "=>" here, but the engine technically doesn't check which two characters you use. The first 5x5 set is the pattern selector. The engine will look for this pattern of elements in the world. Entries can be colors, tags, previously defined shorthand, or '*'. The '*' character will select anything.

The second 5x5 body is how the engine responds when it finds the pattern in the first block. In this block, the "*" character means "unchanged". A color means it will simply set that element in the selected pattern to that color. An element tag will select a random element with that tag, and place it there. And references, which will set it to an element in the pattern, using coordinates in relation to it. For example, if the response element in the middle is "(1, 1)", it will set itself to the element diagonally down and to the right.

The rule on the right uses the symbols previously defined to search the whole screen for a "pileable" element, that sits on top of a "solid" element, and has a "passthrough" element down and to the right, and it ignores all other elements in the 5x5 scanning area. It's mirror horizontally, and so this rule will work to the left as well. Recall that '\' was defined as a reference that points down 1 and right 1, and / as a reference that points up 1, and left 1. In this rule's response, the pileable element gets set to whatever was in the bottom right, i.e. the passthrough element. And the passthrough element gets set to whatever was up and left from it, i.e. the pileable element. The passthrough and pileable elements are effectively swapped, and it appears as the pileable element sliding off the solid element.

rule: x
* * * * *    * * * * *
* * * * *    * * * * *
* * p * * => * * \ * *
* * s 0 *    * * * / *
* * * * *    * * * * *

A visual representation can be seen here. The engine searches for the image on the left, where all white are ignored spaces, the tan is a sand element which has the tag "pileable", the grey is a stone element which has the tag "solid", and the blue is an air element which has the property "passthrough". The engine recognizes this as satisfying the rule, and swaps the sand and air.

Sand

I will now run you through the Sand ruleset.

In this first chunk, we define air, as a blue passthrough element with the keybind 'a'. Sand as a tan solid, fallable, and pileable element with the keybind 's'. Stone as a grey solid and fallable element with the keybind 'x', and water, a blue fallable, pileable, liquid element with the keybind 'w'.

#9bd7e8: a
- "air"
- "passthrough"

#f2d994: s
- "sand"
- "solid"
- "fallable"
- "pileable"

#808080: x
- "stone"
- "solid"
- "fallable"

#0080ff: w
- "water"
- "fallable"
- "pileable"
- "liquid"

In this second section, we define 2 rules. Before we do so however, we create a few symbols to make the rules a bit more coherent. Ones for fallable, passthrough, solid, and pileable elements, as well as ones for references 1 tile down, 1 tile up, 1 tile down and right, and 1 tile up and left.

This first rule defines how "fallable" elements behave. If they notice a passthrough element 1 tile below them, they swap positions with it, appearing as the tile falling.

This second rule defines how "pileable" elements behave. We went over with this in the previous section, but it tells "pileable" elements to look for spaces diagonally down-right if there's a solid tile directly below, and swap with that space if it's a passthrough element. This rule is also mirrored horizontally so that pilable elements will search down to the left as well.

f => "fallable"
0 => "passthrough"
s => "solid"
p => "pileable"

v => (0, 1)
^ => (0, -1)
\ => (1, 1)
/ => (-1, -1)

rule:
* * * * *    * * * * *
* * * * *    * * * * *
* * f * * => * * v * *
* * 0 * *    * * ^ * *
* * * * *    * * * * *

rule: x
* * * * *    * * * * *
* * * * *    * * * * *
* * p * * => * * \ * *
* * s 0 *    * * * / *
* * * * *    * * * * *

In this third section, symbols are defined for "liquid" elements, along with a reference one tile to the right, and a reference one tile to the left.

First we create a rule that allows liquid to slide across other liquids. If a liquid is on top of another liquid, and there is a passthrough element to the right, it will swap places with that passthrough element. This rule is mirrors horizontally so that liquid can slide leftwards as well.

Second, we create a rule that allows liquid to slide across solids, similarly to liquids, if there's a passthrough element to the right, or to the left due to horizontal mirroring.

Finally, we create a rule that allows fallables to fall through liquid. It's identical to the original fallable rule, with the only difference being the 20% rule chance. This means that every frame, there's only a 20% chance that any fallable in liquid will fall. This causes the appearance of fallables falling slower in water than they fall in air.

l => "liquid"
> => (1, 0)
< => (-1, 0)

rule: x
* * * * *    * * * * *
* * * * *    * * * * *
* * l 0 * => * * > < *
* * l * *    * * * * *
* * * * *    * * * * *

rule: x
* * * * *    * * * * *
* * * * *    * * * * *
* * l 0 * => * * > < *
* * s * *    * * * * *
* * * * *    * * * * *

rule: 20%
* * * * *    * * * * *
* * * * *    * * * * *
* * f * * => * * v * *
* * l * *    * * ^ * *
* * * * *    * * * * *