# Logo programs abstract turtle movements on a 2D canvas # # See Part 1. # # The `Logo` class an its subclasses represent a Logo program that follow the # # ~~~raw # Prog ::= Inst* ; class LogoProg # Inst ::= FD distance ; class LogoForward # Inst ::= RT angle ; class LogoRight # Inst ::= REPEAT number [Prog] ; class LogoRepeat # ~~~ # # Distance is in the canvas units (pixel). Angle is in degree. # To move backwards, use FD with a negative number. # To turn left, use RT with a negative number. # # The class `LogoWriter` and the function `logo` provide a fluent API to instantiate logo programs. module logo # Logo instruction base class. abstract class Logo end # Common class of all simple actions class LogoSimple super Logo end # Move forward (or backwards) class LogoForward super LogoSimple # Distance in canvas unit to move forwards (or backwards if negative) var distance: Int redef fun to_s do return "FD {distance}" end # Rotate right (or left) class LogoRight super LogoSimple # Angle in degree to rotate right (or left if negative) var angle: Int redef fun to_s do return "RT {angle}" end # Common class of all composite actions class LogoComplex super Logo end # A sequence of Logo instructions class LogoProg super LogoComplex # All the instructions in the sequence var logos = new Array[Logo] redef fun to_s do # TODO end end # Repeat a sequence of logo instructions class LogoRepeat super LogoComplex # The number of time the sequence should be repeated var number: Int # The instructions to repeat var body = new LogoProg redef fun to_s do # TODO end end # Fluent API to create Logo programs. # # This just stores and manages the various nested REPEAT instructions of a full logo program. class LogoWriter # The stacked REPEAT context (in fact, the first one is the main program) var stack = new Array[LogoProg] init do stack.add new LogoProg end # The full program fun main: LogoProg do return stack.first # Add a new instruction. # # You should use the specific instruction method instead fun add(logo: Logo): LogoWriter do stack.last.logos.add logo return self end # Add a new `FD distance` instruction. fun fd(distance: Int): LogoWriter do return add(new LogoForward(distance)) end # Add a new `FD angle` instruction. fun rt(angle: Int): LogoWriter do return add(new LogoRight(angle)) end # Add a new `REPEAT number` instruction and stack it. # # This means that the following add will be done. # To finish the `REPEAT` instruction, call `fini`. fun repeat(number: Int): LogoWriter do var rpt = new LogoRepeat(number) add(rpt) stack.push(rpt.body) return self end # Close the latest `REPEAT` block (unkstack it). fun fini: LogoWriter do stack.pop return self end end # A new empty LogoWriter # # This is used to have a nice fluent API fun logo: LogoWriter do return new LogoWriter # A Logo program that draws a star fun logo_star: LogoProg do return logo.repeat(5).fd(50).rt(144).fini.main # A logo program that draws a home fun logo_home: LogoProg do return logo.repeat(4).fd(50).rt(90).fini.fd(50).rt(-135).fd(35).rt(-90).fd(35).rt(225).main print logo_star print logo_home