|(require furtle)||package: furtle|
"It’s TurtleF all the way down!" – the killer cyborg from planet Rech-tangular
furtle is a small Typed Racket library that lets you create turtle geometry in a mostly functional way.
The recomended way to create graphics with this library is to write expressions that result in a (-> turtle turtle), aka TurtleF, and then composing them with two primitive composers - turtles and repeat. However, all the primitive geometry functions along with functions that create and draws turtles are exposed, so if you need to customize the process of turtle drawing, you can directly use those as well. Lets dive into an example.
We want to create a drawing of a fibonacci tree of depth 14. Here’s the way to proceed.
(require furtle) (: fib-tree (-> Real TurtleF)) (define (fib-tree depth) (if (>= depth 1) (turtles (t< fd 15) (t< lt 15) (fib-tree (- depth 1)) (t< rt 30) (fib-tree (- depth 1)) (t< lt 15) (t< bk 15)) (turtles)))
The function fib-tree is called recursively to create the lower depth trees. There’s a differentiation between how we call a turtle primitive such as fd and our own function fib-tree. This is because, the fd function can double down as a one that takes a turtle in its second argument and return the new turtle. But, in it’s (t< fd n) form, it simply returns a TurtleF which on giving a concrete turtle will create a new turtle. The weird t< is simply a macro on top of curry library function. A (t< fn-name arg1 arg2 ...) actually gets transformed into (λ ([t : turtle]) : turtle (fn-name arg1 arg2 ... t)). If you do not want to use this form, there are longer forms of the primitives which does the same operation but does not require the extra (t< ...) form. However, it is preferable to use the longer names [(forward 100) instead of (t< fd 100)] as they are clearer and also work in an untyped module. As an example, the above function can be re-written as:
(require furtle) (: fib-tree (-> Real TurtleF)) (define (fib-tree depth) (if (>= depth 1) (turtles (forward 15) (left 15) (fib-tree (- depth 1)) (right 30) (fib-tree (- depth 1)) (left 15) (back 15)) (turtles)))
The thing to notice is that this is not interactive as in a typical Logo software. The drawing is created at the end of running the program - which is inconvenient but currently that is how it is.
Now, this definition of fib-tree does not draw anything - it merely creates a a specification of sorts, that when passed to draw or show! function, will draw the final scene.
Here’s how we do that -
(show! (fib-tree 10))
This will open a new window with the drawing and a red triangular turtle indicator. As fib-tree is another TurtleF, we can use it to further compose new drawing spec.
(draw tf [ #:height height #:width width #:pen-width line-width #:pen-color pen-width #:background-color background-color]) → (Instance Bitmap%) tf : TurtleF height : integer? = 800 width : integer? = 800 line-width : integer? = 1 pen-width : string? = "black" background-color : string? = "orange"