// L-System KCL // Zoo Corporation ⓒ 2024 // Comparators fn cond(@bools) { return fn(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 = a, b = b)) } fn Gte(a, b) { return Not(Lt(a = a, b = 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, q = state.currentLength * state.factor) } fn Lt2(@state) { return setLength(state, q = state.currentLength / state.factor) } fn Add(@state) { return setAngle(state, q = rem(state.currentAngle - state.angle, divisor = 360)) } fn Sub(@state) { return setAngle(state, q = rem(state.currentAngle + state.angle, divisor = 360)) } // Only necessary to get around recursion limitations... fn F(@state, F) { return if Lt(a = state.depth, b = state.depthMax) { stateNext = state |> setDepth(%, q = state.depth + 1) // Produce // Note:if you need [ and ], just save state to a variable. stateNext |> F(%, F = F) |> Sub(%) |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F) |> Sub(%) |> F(%, F = F) |> setDepth(%, q = stateNext.depth - 1) } else { // Pass onto the next instruction state |> setSketch(%, q = 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, }, axioms = fn(@q) { result = q |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F) return result.q })