// 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. 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(state.currentAngle - state.angle, divisor = 360)) } fn Sub = (state) => { return setAngle(state, rem(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) |> startProfile(at = [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 })