// L-System KCL // Zoo Corporation ⓒ 2024 // Comparators fn cond = (bools) => { return (a, b) => { x = min(max(-1, a-b), 1) + 1 return bools[x] } } fn Not = (b) => { return if b { false } else { true } } fn And = (a, b) => { return if a { if b { true } else { false } } else { false }} fn Or = (a, b) => { return if a { true } else { if b { true } else { false }}} Eq = cond([false, true, false]) Lt = cond([true, false, false]) Gt = cond([false, false, true]) fn Lte = (a, b) => { return Not(Gt(a, b)) } fn Gte = (a, b) => { return Not(Lt(a, b)) } // L-system // Note: it was most concise to encode productions directly in axioms. // Change them as you need. deg = pi()*2 / 360 fn setSketch = (state, q) => { return { depthMax: state.depthMax, depth: state.depth + 1, currentLength: state.currentLength, factor: state.factor, currentAngle: state.currentAngle, angle: state.angle, q } } fn setDepth = (state, q) => { return { depthMax: state.depthMax, depth: q, currentLength: state.currentLength, factor: state.factor, currentAngle: state.currentAngle, angle: state.angle, q: state.q } } fn setAngle = (state, q) => { return { depthMax: state.depthMax, depth: state.depth, currentLength: state.currentLength, factor: state.factor, currentAngle: q, angle: state.angle, q: state.q } } fn setLength = (state, q) => { return { depthMax: state.depthMax, depth: state.depth, currentLength: q, factor: state.factor, currentAngle: state.currentAngle, angle: state.angle, q: state.q } } fn Gt2 = (state) => { return setLength(state, state.currentLength * state.factor) } fn Lt2 = (state) => { return setLength(state, state.currentLength / state.factor) } fn Add = (state) => { return setAngle(state, rem(int(state.currentAngle - state.angle), divisor = 360)) } fn Sub = (state) => { return setAngle(state, rem(int(state.currentAngle + state.angle), divisor = 360)) } // Only necessary to get around recursion limitations... fn F = (state, F) => { return if Lt(state.depth, state.depthMax) { stateNext = state |> setDepth(%, state.depth + 1) // Produce // Note:if you need [ and ], just save state to a variable. stateNext |> F(%, F) |> Sub(%) |> F(%, F) |> Add(%) |> Add(%) |> F(%, F) |> Sub(%) |> F(%, F) |> setDepth(%, stateNext.depth - 1) } else { // Pass onto the next instruction state |> setSketch(%, angledLine(state.q, angle = state.currentAngle, length = state.currentLength)) } } fn LSystem = (args, axioms) => { myThing = startSketchOn(XY) |> startProfileAt([0, 0], %) return axioms({ depthMax: args.iterations, depth: 0, currentLength: 1.0, factor: args.factor, currentAngle: 0, angle: args.angle, q = myThing, }) } LSystem({ iterations: 1, factor: 1.36, angle: 60, }, (q) => { result = q |> F(%, F) |> Add(%) |> Add(%) |> F(%, F) |> Add(%) |> Add(%) |> F(%, F) return result.q })