require 'RMagick' module Krunimir # Prostredi pro zkompilovaneho Krunimira class Environment WIDTH = 701 HEIGHT = 701 # Inicializuje hlavnim telem zelvy. def initialize(turtle_body) @turtle_body = turtle_body @pos_x = WIDTH / 2 @pos_y = HEIGHT / 2 @angle_deg = 0 @pen_size = 0 color(0, 0, 0) @image = Magick::ImageList.new @image.new_image(WIDTH, HEIGHT) @context = Magick::Draw.new end # Zapocne kresleni (cely beh zelvy). def draw(draws) if draws > 0 @draws = draws else @draws = nil end instance_eval &@turtle_body end # Ulozi vysledny PNG obrazek do souboru. def save_to(filename) @context.draw @image @image.write filename end private # Zelviny prikazy. def left(angle) @angle_deg -= angle end def right(angle) @angle_deg += angle end def pen(size) @pen_size = size end def forward(length) angle_rad = @angle_deg * Math::PI / 180.0 x1 = @pos_x y1 = @pos_y x2 = x1 + length * Math.sin(angle_rad) y2 = y1 - length * Math.cos(angle_rad) if @pen_size > 0 if @draws @draws -= 1 return unless @draws >= 0 end @context.stroke(@color) @context.stroke_width(@pen_size) @context.line(x1, y1, x2, y2) end @pos_x = x2 @pos_y = y2 end def color(r, g, b) # jednotlive slozky se nejdrive "orezou" do rozsahu 0..255 a pak se spoji # pomoci carek @color = "rgb(#{[r, g, b].map do |c| if c < 0 0 elsif c > 255 255 else c end end.join ","})" end def _define(name, &block) # TODO: definuje se metoda cele tridy Environment misto singletonu! self.class.send(:define_method, name, &block) end def _if(expr) yield if expr > 0 end def _repeat(num) num.times { yield } end # vyhodnoti jakoby dalsiho zelvaka ale ne soucasne s ostatnima nybrz # samostatne, protoze vysledek je stejny (pokud nejde krokovat, coz nejde) def _split(&block) # ulozeni promennych aby se pote mohly obnovit to_restore = %w[pos_x pos_y angle_deg pen_size draws].map { |s| :"@#{s}" } values = {} to_restore.each do |ivar| values[ivar] = instance_variable_get ivar end instance_eval &block to_restore.each do |ivar| instance_variable_set ivar, values[ivar] end end end end