~kylep/visual-cell-lang

8a9e54befb8c459df9c337d38445172ffb6354ee — Kyle Perik 1 year, 7 months ago eff38cb
Update snake example in readme
2 files changed, 98 insertions(+), 73 deletions(-)

M README.md
A examples/snake.json
M README.md => README.md +97 -73
@@ 66,125 66,149 @@ This will start the server, then you can connect at http://localhost:8080

## Example

TODO: Update this for the new lang

Let's breakdown an example of a basic snake game.

To start, we begin with an empty object in `codebox.js`
To start, we begin with the name of our cell

```js
snakeGame: {}
```
snake
```

Then define the outputs, which are always single letters (for the gui).
Then define the inputs and outputs, which are always single letters (for the gui), separated by ` -> `.

```js
outputs: ['p', 'c'],
```
snake
d i -> p c
```

At this point, your program will save, but it won't do anything.

Code boxes can do nothing by themselves, and require a layer on top to give
inputs and handle outputs for the code boxes to do anything. Here we define a rough
protocol which if followed, will produce the desired result.

`p` and `c` are both vector outputs which represent `pixel` and `clear` respectively.
For this cell, we require two inputs
- `d` is a vector representing the direction (ultimately coming from the `keyboard -> wasdDir`)
- `i` can be anything, it just keeps time for the game (`tick` plugged in here)

For outputs, `p` and `c` are both vectors which represent `pixel` and `clear` respectively.
These can be routed to a `screen` box which will display the `p`s and clear the `c`s

Now for the initial data.
```js
data: {
  direction: new Vec(1, 0),
  tail: [new Vec(0, 0)],
},
Because the snake cell must keep track of it's given direction and tail, we need to initialize
some data. Program initialization takes place directly after the input/output definition.

```
 Here we record 2 keys, direction and tail.
`direction` being cached input from `d` to keep the snake going a single direction.
`tail` records each vector within the tail as it moves.
Each starts with a value to initialize the starting postion and direction of the snake.
#1 int #0 int vec
#direction kep

#tail arr
#0 int #0 int vec
#tail que
```

This creates a vector (1, 0) and saves it under the key `direction`. This serves as the default direction of
the snake.

Then we initialize an array under the key `tail`, and push a single vector (0, 0) onto that array.
This serves as the starting point for the snake's position.

Finally we get to the input handlers. When inputs are recieved, cells automatically run the function
that matches the name of the input.

Finally we get to the input handlers, start with an empty object.
First we'll define the input handler for `d`.

```js
inputs: {}
```
def d:
  val #direction kep
```

We'll add two inputs:
- `d` is a vector representing the direction (ultimately coming from the `keyboard -> wasdDir`)
- `i` can be anything, it just keeps time for the game (`tick` plugged in here)
This simply records the given value as a vector to replace the current direction.

The final input handler is what should run on "tick" which controls most of the logic of the cell
as it represents time moving forward 1 frame.

Now we'll add a handler for each input, starting with `d`.
We start with a function declaration:

```
def i:
```

```js
d ({ value, data }) {
  data.direction = value;
},
First, we evaluate the new head by getting the last value of the tail,
and adding the direction vector.

```
  #tail lst #direction get vecadd
```
For this one, we're just caching the value whenever we get a new
direction update.

On tick (`i`) is where all the work is done. As you can see, it's still
fairly simple.
Next, we want to output that vector to be printed. But because we want to keep this
value for later, we duplicate it first.

```js
i ({ value, out, data: { tail, direction } }) {
  const head = tail[0].add(direction);
  tail.unshift(out.p(head));
  if (tail.length > 10) {
    out.c(tail.pop());
  }
},
```
  dup #p out
```

Then we can queue the value onto the tail array.

First a new head is generated, by adding the direction to the last head.
```js
const head = tail[0].add(direction);
```
  #tail que
```

The new head has been output and registered, now we must check to see if the oldest
tail needs to be popped off. For this we must check the length of the tail.

The new head is then emited out to `p` for printing, and then also saved as the new
first element of `tail` with `unshift`.
```
  #tail len equ #10 int
```

If it equals 10, then the first value on the stack will be `true`, otherwise `false`.
We can use this boolean to conditionally jump to a nested function which removes the
last tail.

```
tail.unshift(out.p(head));
  #pop jcn
```

The final bit first checks to see if the tail is longer than it's max limit,
if so it will pop off the end of the tail, and emit that output value to `c` to clear.
Then the declaration for pop, note that this function must be nested 2 spaces within
the other function, otherwise it won't be found.

```
if (tail.length > 10) {
  out.c(tail.pop());
}
def pop:
  #tail pop #c out
```

This simply pops the last tail and outputs that to be cleared on the screen.

Now that's it, the snake game box is complete, here's the full snippet.

```js
snakeGame: {
  outputs: ['p', 'c'],
  data: {
    direction: new Vec(1, 0),
    tail: [new Vec(0, 0)],
  },
  inputs: {
    d ({ value, data }) {
      data.direction = value;
    },
    i ({ value, out, data: { tail, direction } }) {
      const head = tail[0].add(direction);
      tail.unshift(out.p(head));
      if (tail.length > 10) {
        out.c(tail.pop());
      }
    },
  },
}
```
snake
d i -> p c

#0 int #1 int vec
#direction kep

#tail arr
#0 int #1 int vec
#tail que

def d:
  val #direction kep

def i:
  #direction get #tail lst vecadd
  dup #tail que
  #p out
  #11 int #tail len equ #pop jcn
  def pop:
    #tail pop #c out
```

![snakeexample](docs/snake_example.png)

You can load the snake example in by copying and pasting the json from this example (or others) with the "Load Program" button.

[snake.json](examples/snake.json)

## Credits

### Fonts used

A examples/snake.json => examples/snake.json +1 -0
@@ 0,0 1,1 @@
{"boxes":[{"width":5,"height":3,"inputs":{},"outputs":["t"],"clicked":false,"label":"","pos":{"x":16,"y":10},"type":"tick","js":true,"data":{}},{"width":5,"height":3,"inputs":{"d":{"codes":["val","#direction","kep"],"branches":{}},"i":{"codes":["#tail","lst","#direction","get","vecadd","dup","#p","out","#tail","que","#tail","len","equ","#10","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#c","out"],"branches":{}}}}},"outputs":["p","c"],"clicked":false,"label":"","pos":{"x":13,"y":16},"type":"snake3","init":{"codes":["#1","int","#0","int","vec","#direction","kep","#tail","arr","#0","int","#0","int","vec","#tail","que"],"branches":{"d":{"codes":["val","#direction","kep"],"branches":{}},"i":{"codes":["#tail","lst","#direction","get","vecadd","dup","#p","out","#tail","que","#tail","len","equ","#10","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#c","out"],"branches":{}}}}}},"code":"snake3\nd i -> p c\n\n#1 int #0 int vec\n#direction kep\n\n#tail arr\n#0 int #0 int vec\n#tail que\n\ndef d:\n  val #direction kep\n  \n\ndef i:\n  #tail lst #direction get vecadd\n  dup #p out\n  #tail que\n  #tail len equ #10\n  #pop jcn\n  def pop:\n    #tail pop #c out\n  ","js":false,"data":{"direction":{"x":1,"y":0},"tail":[{"x":106,"y":0}]},"triggered":false,"failed":false},{"width":5,"height":3,"inputs":{},"outputs":["c"],"clicked":false,"label":"","pos":{"x":8,"y":5},"type":"keyboard","js":true,"data":{}},{"width":5,"height":3,"inputs":{},"outputs":["v"],"clicked":false,"label":"","pos":{"x":9,"y":10},"type":"wasdDir2","data":{},"js":true,"triggered":false},{"width":20,"height":20,"inputs":{},"outputs":[],"clicked":false,"label":"","pos":{"x":5,"y":22},"type":"screen","js":true,"data":{},"triggered":false}],"connections":[{"startOutput":"t","endInput":"i","start":{"x":18.5,"y":13},"end":{"x":16.333333333333332,"y":16},"startBoxIndex":0,"endBoxIndex":1},{"startOutput":"c","endInput":"c","start":{"x":10.5,"y":8},"end":{"x":11.5,"y":10},"startBoxIndex":2,"endBoxIndex":3},{"startOutput":"v","endInput":"d","start":{"x":11.5,"y":13},"end":{"x":14.666666666666666,"y":16},"startBoxIndex":3,"endBoxIndex":1},{"startOutput":"p","endInput":"p","start":{"x":14.666666666666666,"y":19},"end":{"x":11.666666666666666,"y":22},"startBoxIndex":1,"endBoxIndex":4},{"startOutput":"c","endInput":"c","start":{"x":16.333333333333332,"y":19},"end":{"x":18.333333333333332,"y":22},"startBoxIndex":1,"endBoxIndex":4}],"customDefinitions":{"test":{"init":{"codes":["#0","int","#counter","kep","#sin","arr","#0.000","flt","#sin","que","#0.309","flt","#sin","que","#0.588","flt","#sin","que","#0.809","flt","#sin","que","#0.951","flt","#sin","que","#1.000","flt","#sin","que","#0.951","flt","#sin","que","#0.809","flt","#sin","que","#0.588","flt","#sin","que","#0.309","flt","#sin","que","#0.000","flt","#sin","que","#-0.309","flt","#sin","que","#-0.588","flt","#sin","que","#-0.809","flt","#sin","que","#-0.951","flt","#sin","que","#-1.000","flt","#sin","que","#-0.951","flt","#sin","que","#-0.809","flt","#sin","que","#-0.588","flt","#sin","que","#-0.309","flt","#sin","que"],"branches":{"i":{"codes":["#counter","get","#.1","flt","add","#20","int","mod","dup","#counter","kep","dup","#sinat","jmp","swp","#5","int","add","#sinat","jmp","vec","#20","int","vecmul","#p","out"],"branches":{"sinat":{"codes":["dup","dup","#1","int","add","flr","#20","int","mod","#sin","at","swp","#1","int","mod","mul","swp","dup","flr","#20","int","mod","#sin","at","swp","#1","int","mod","#1","int","swp","sub","mul","add"],"branches":{}}}}}},"inputs":{"i":{"codes":["#counter","get","#.1","flt","add","#20","int","mod","dup","#counter","kep","dup","#sinat","jmp","swp","#5","int","add","#sinat","jmp","vec","#20","int","vecmul","#p","out"],"branches":{"sinat":{"codes":["dup","dup","#1","int","add","flr","#20","int","mod","#sin","at","swp","#1","int","mod","mul","swp","dup","flr","#20","int","mod","#sin","at","swp","#1","int","mod","#1","int","swp","sub","mul","add"],"branches":{}}}}},"outputs":["p"],"code":"test\ni -> p\n\n#0 int #counter kep\n\n#sin arr #0.000 flt #sin que #0.309 flt #sin que #0.588 flt #sin que #0.809 flt #sin que #0.951 flt #sin que #1.000 flt #sin que #0.951 flt #sin que #0.809 flt #sin que #0.588 flt #sin que #0.309 flt #sin que #0.000 flt #sin que #-0.309 flt #sin que #-0.588 flt #sin que #-0.809 flt #sin que #-0.951 flt #sin que #-1.000 flt #sin que #-0.951 flt #sin que #-0.809 flt #sin que #-0.588 flt #sin que #-0.309 flt #sin que\n\ndef i:\n  #counter get\n  #.1 flt add\n  #20 int mod\n  dup #counter kep\n  dup #sinat jmp\n  swp #5 int add\n  #sinat jmp\n  vec\n  #20 int\n  vecmul\n  #p out\n  \n  def sinat:\n    dup dup\n    #1 int add\n    flr #20 int mod\n    #sin at\n    swp #1 int mod mul\n    \n    swp dup\n    flr #20 int mod\n    #sin at\n    swp #1 int mod\n    #1 int swp sub mul\n    add\n  \n"},"delay":{"init":{"codes":["#tail","arr","#30","int","#number","kep"],"branches":{"v":{"codes":["val","#tail","que","#tail","len","#number","get","gth","#pop","jcn","#tail","len","#number","get","gth","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#v","out"],"branches":{}}}},"n":{"codes":["val","#number","kep"],"branches":{}}}},"inputs":{"v":{"codes":["val","#tail","que","#tail","len","#number","get","gth","#pop","jcn","#tail","len","#number","get","gth","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#v","out"],"branches":{}}}},"n":{"codes":["val","#number","kep"],"branches":{}}},"outputs":["v"],"code":"delay\nv n -> v\n\n#tail arr\n#30 int #number kep\n\ndef v:\n  val #tail que\n  #tail len #number get gth\n  #pop jcn\n  #tail len #number get gth\n  #pop jcn\n  def pop:\n    #tail pop #v out\n  \n\ndef n:\n  val #number kep"},"walkCircle":{"init":{"codes":["#0","int","#counter","kep","#sin","arr","#0.000","flt","#sin","que","#0.309","flt","#sin","que","#0.588","flt","#sin","que","#0.809","flt","#sin","que","#0.951","flt","#sin","que","#1.000","flt","#sin","que","#0.951","flt","#sin","que","#0.809","flt","#sin","que","#0.588","flt","#sin","que","#0.309","flt","#sin","que","#0.000","flt","#sin","que","#-0.309","flt","#sin","que","#-0.588","flt","#sin","que","#-0.809","flt","#sin","que","#-0.951","flt","#sin","que","#-1.000","flt","#sin","que","#-0.951","flt","#sin","que","#-0.809","flt","#sin","que","#-0.588","flt","#sin","que","#-0.309","flt","#sin","que"],"branches":{"i":{"codes":["#counter","get","#.1","flt","add","#20","int","mod","dup","#counter","kep","dup","#sinat","jmp","swp","#5","int","add","#sinat","jmp","vec","#20","int","vecmul","#p","out"],"branches":{"sinat":{"codes":["dup","dup","#1","int","add","flr","#20","int","mod","#sin","at","swp","#1","int","mod","mul","swp","dup","flr","#20","int","mod","#sin","at","swp","#1","int","mod","#1","int","swp","sub","mul","add"],"branches":{}}}}}},"inputs":{"i":{"codes":["#counter","get","#.1","flt","add","#20","int","mod","dup","#counter","kep","dup","#sinat","jmp","swp","#5","int","add","#sinat","jmp","vec","#20","int","vecmul","#p","out"],"branches":{"sinat":{"codes":["dup","dup","#1","int","add","flr","#20","int","mod","#sin","at","swp","#1","int","mod","mul","swp","dup","flr","#20","int","mod","#sin","at","swp","#1","int","mod","#1","int","swp","sub","mul","add"],"branches":{}}}}},"outputs":["p"],"code":"walkCircle\ni -> p\n\n#0 int #counter kep\n\n#sin arr #0.000 flt #sin que #0.309 flt #sin que #0.588 flt #sin que #0.809 flt #sin que #0.951 flt #sin que #1.000 flt #sin que #0.951 flt #sin que #0.809 flt #sin que #0.588 flt #sin que #0.309 flt #sin que #0.000 flt #sin que #-0.309 flt #sin que #-0.588 flt #sin que #-0.809 flt #sin que #-0.951 flt #sin que #-1.000 flt #sin que #-0.951 flt #sin que #-0.809 flt #sin que #-0.588 flt #sin que #-0.309 flt #sin que\n\ndef i:\n  #counter get\n  #.1 flt add\n  #20 int mod\n  dup #counter kep\n  dup #sinat jmp\n  swp #5 int add\n  #sinat jmp\n  vec\n  #20 int\n  vecmul\n  #p out\n  \n  def sinat:\n    dup dup\n    #1 int add\n    flr #20 int mod\n    #sin at\n    swp #1 int mod mul\n    \n    swp dup\n    flr #20 int mod\n    #sin at\n    swp #1 int mod\n    #1 int swp sub mul\n    add"},"snake":{"init":{"codes":["#0","int","#1","int","vec","#direction","kep","#tail","arr","#0","int","#1","int","vec","#tail","que"],"branches":{"d":{"codes":["val","#direction","kep"],"branches":{}},"i":{"codes":["#direction","get","#tail","lst","vecadd","dup","#tail","que","#p","out","#11","int","#tail","len","equ","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#c","out"],"branches":{}}}}}},"inputs":{"d":{"codes":["val","#direction","kep"],"branches":{}},"i":{"codes":["#direction","get","#tail","lst","vecadd","dup","#tail","que","#p","out","#11","int","#tail","len","equ","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#c","out"],"branches":{}}}}},"outputs":["p","c"],"code":"snake\nd i -> p c\n\n#0 int #1 int vec\n#direction kep\n\n#tail arr\n#0 int #1 int vec\n#tail que\n\ndef d:\n  val #direction kep\n\ndef i:\n  #direction get #tail lst vecadd\n  dup #tail que\n  #p out\n  #11 int #tail len equ #pop jcn\n  def pop:\n    #tail pop #c out"},"snake2":{"init":{"codes":[],"branches":{}},"inputs":{"v":"","i":""},"outputs":["p","c"],"code":"snake2\nv i -> p c"},"snake3":{"init":{"codes":["#1","int","#0","int","vec","#direction","kep","#tail","arr","#0","int","#0","int","vec","#tail","que"],"branches":{"d":{"codes":["val","#direction","kep"],"branches":{}},"i":{"codes":["#tail","lst","#direction","get","vecadd","dup","#p","out","#tail","que","#tail","len","equ","#10","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#c","out"],"branches":{}}}}}},"inputs":{"d":{"codes":["val","#direction","kep"],"branches":{}},"i":{"codes":["#tail","lst","#direction","get","vecadd","dup","#p","out","#tail","que","#tail","len","equ","#10","#pop","jcn"],"branches":{"pop":{"codes":["#tail","pop","#c","out"],"branches":{}}}}},"outputs":["p","c"],"code":"snake3\nd i -> p c\n\n#1 int #0 int vec\n#direction kep\n\n#tail arr\n#0 int #0 int vec\n#tail que\n\ndef d:\n  val #direction kep\n  \n\ndef i:\n  #tail lst #direction get vecadd\n  dup #p out\n  #tail que\n  #tail len equ #10\n  #pop jcn\n  def pop:\n    #tail pop #c out\n  "}}}