Skip to content

[TodeSplat] Documentation

Luke Wilson edited this page Aug 23, 2020 · 1 revision

NOTE: I don't use the TodeSplat language anymore.
Nowadays, I use the SpaceTode language instead.

This page is only here for legacy purposes.
TodeSplat is still active on this old branch.
You can try out the old version at todesplat.sandpond.cool.

Element

The most important part of TodeSplat is the element expression. It defines a new element:

element Sand {}

Properties

You can give your element properties. Space them out on different lines:

element Sand {
    colour "yellow"
    meaningOfLife 42
}

Some properties are in-built and affect things about the element, like colour.
These are all the in-built properties:

  • colour
  • emissive (emissive colour of the element)
  • opacity
  • precise (if true, the dropper tool will only place one atom of the element at a time)
  • floor (if true, the dropper tool will place the atom on the floor instead of dropping it from the air)
  • hidden (if true, the element will not appear in the menu
  • category (determines which menu category to appear in)
  • pour (if true, holding down the mouse button will continue to pour more atoms, default is true)
  • default (if true, this element will be picked by the dropper when you load the page)

Data

Atoms of the element can carry data.
Use the data keyword to shows what data the atom holds, and its default value.

element Sand {
    colour "yellow"
    data isWet false
    data temperature 15
}

Rules

You can give your element rules by using the rule keyword:

element Sand {
   
    colour "yellow"
   
    rule {
        @ => _
        _    @
    }

    rule {
        @ => _
        x    x
    }

}

An element's rules show it how to act in the SandPond world.
It checks its surroundings to see if it matches the left-hand-side of the rule (the inputs).
If it matches, it changes it to look like the right-hand-side of the rule (the outputs).
Rules are checked in order. The first rule to match is the one that gets used.

Diagram

A rule's diagram shows how things are arranged.
Let's look at a rule more closely:

rule {
    @ => _
    _    @
}

Inputs:
The @ symbol shows where the element is.
The _ symbol checks for an empty space.
In other words, the rule checks if there is an empty space below the element.

Outputs:
The @ symbol shows where to put the element.
The _ symbol shows where to put an empty space.
In other words, the rule moves the element down, leaving an empty space behind.

Inputs

Inputs are the characters you write on the left-hand-side of a rule diagram to check an element's surroundings.
There are some in-built inputs that you can use straight away:

  • @ This atom.
  • _ An empty space.
  • # A non-empty space.
  • . Any space.
  • x Not a space (ie: the edge of the universe).
  • * Anything.

You can also make your own input characters by using the following keywords:

  • given
  • select
  • vote (not currently implemented)
  • check (not currently implemented)

Outputs

Outputs are the characters you write on the right-hand-side of a rule diagram to say what to do when a rule has been matched.
Some are built-in already:

  • @ Place this atom in the space.
  • _ Empty the space.
  • . Do nothing.

You can make your own output characters with the following keywords:

  • change
  • keep

Symmetries

You can add a symmetries label to a rule to make it randomly choose a way of reflecting itself.

rule y {
    @ => _
    _    @
}

The above rule has a y symmetry. It will randomly reflect itself in the y-axis.
In other words, it might fall down, or it might fall up.

The reflections label can be any combination of x, y and z.
eg: xz
eg: xyz

Given

All given inputs must be true for a rule to be chosen.

given W (element) => element == Water

rule {
    W => _
    @    @
}

If there is a water atom above me, delete it.

Change

change outputs say what atom to put in a space.

change W () => new Water()

rule {
    @ => @
    _    W
}

This makes a water atom and places it below.

Keep

keep outputs don't do anything. They just leave that space how it is.

keep n

rule {
    @ => n
}

This does nothing...

Keeps can still have a function like usual.

keep n () => print("I'm doing nothing!")

rule {
    @ => n
}

Select

select inputs save data that can be used in an output that uses the same character.

given W (element) => element == Water
select W (atom) => atom
change W (selected) => selected

rule {
    @ => W
    W    @
}

This selects a water atom below, and swaps places with it.

Check (status: not currently implemented)

All check inputs must be true for a rule to be chosen. They happen after all other input checks. Also, they don't get cached like givens, so you can be sure that they will always run. Useful for non-deterministic checks or, like when you want to include some random chance. Also useful for checks with side-effects, like displaying to the UI.

given W (element) => element == Water
check W () => Math.random() < 0.5 

rule {
    W => _
    @    @
}

If there is a water element above me, do a random check that passes 50% of the time, and delete the water.

Vote (status: not currently implemented)

vote inputs increase a counter for every character that is true for all its votes. You can check the number of votes in a check.

vote f (element) => element == Fire
check f (votes) => votes > 2
change F () => new Fire()

rule {
     f      .
    f@f => .F.
     f      .
}

If there are more than 2 fire atoms, turn myself into fire.

Chance

You can add a number label to say the chance of a rule happening:

rule 0.5 {
    @ => _
    _    @
}

The above rule only happens 50% of the time.

Point of View

By default, the rule diagram is positioned as if you are looking from the front.
You can give the rule a label to make the diagram represent another point of view.

rule top {
    @ => _
    _    @
}

The above rule's diagram is shown from a bird's eye view instead of from the front.
Valid points of view:

  • front (default)
  • top
  • side

Actions

Use the action keyword to give actions to an element.
Elements always try to do every action. This is different to rules: Elements only do the first rule that matches.

element Dropper {
    
    change S () => new Sand()
    
    // Drop some sand below me
    action {
        @ => @
        _    S
    }
    
    // Afterwards... move into space
    rule xyz { @_ => _@ }
}

Extend (status: not currently implemented)

Inputs and outputs can extend other events to combine them together.

input S extends #

This extends the in-built # input that checks that there is an atom in the space.

Ruleset

Elements can copy another element's rules (and actions).

element Snow {
    colour "white"
    change W () => new Water()
    rule 0.01 { @ => W }
    ruleset Sand
}

This snow element melts 1% of the time. The rest of the time, it behaves like Sand.