require 'victor' BASE = 4 DIRS = 7 def sum_digits(n) x = n % BASE x == 0 ? BASE : x end def step(x, y, n, dir) return [n*Math.cos(2*Math::PI/DIRS*dir), n*Math.sin(2*Math::PI/DIRS*dir), (dir+1) % DIRS] end def run_number(number) counter = 1 x, y, dir = 0.0, 0.0, 0 line_stack = [[0,0]] (BASE/BASE.gcd(number) * DIRS).times do |i| dx, dy, dir = step(x,y, sum_digits(i*number), dir) x += dx y += dy line_stack << [x,y] end puts line_stack.to_s return make_svg(line_stack) end def make_svg(line_stack) line_length = 20 xs = line_stack.map { |c| c[0] } ys = line_stack.map { |c| c[1] } x_offset = -xs.min y_offset = -ys.min svg_coords = ->(p) { nx, ny = p [(nx+x_offset)*line_length + line_length/2, (ny+y_offset)*line_length + line_length/2] } max_width = (xs.max - xs.min).abs * line_length + line_length max_height = (ys.max - ys.min).abs * line_length + line_length svg = Victor::SVG.new width: max_width, height: max_height style = { stroke: 'black', stroke_width: 5 } svg.build do line_stack.each_cons(2) do |pair| p1, p2 = pair x1, y1 = svg_coords.call(p1) x2, y2 = svg_coords.call(p2) line x1: x1, y1: y1, x2: x2, y2: y2, style: style circle cx: x2, cy: y2, r: line_length/6, style: style, fill: 'black' end end return svg end (1..10).each do |i| run_number(i).save "pattern_#{i}" end