Macr055でクリスマスの詩

次の http://parametron.blogspot.jp/2015/03/christopher-stracheygpm.html の記事に移って、クリスマスの詩。

"$:" が10番目の引数に置換されるようにM55を改造。文字と文字コードの相互変換は chr と ord という名前の関数とするのが定番ですが、GNU awk のマニュアルにサンプルがあったので https://www.gnu.org/software/gawk/manual/html_node/Ordinal-Functions.html それを参考に実装。

{m55_define|1-|`{-1|0|1|2|3|4|5|6|7|8|9|:|
  {m55_define|-1|$$$1}}'}{m55_dnl}
{m55_define|getn|`{11th|10th|9th|8th|7th|6th|5th|4th|3rd|2nd|1st|
  {m55_define|11th|$$$1}}'}{m55_dnl}
{m55_define|gets|`{11 Pipers
|10 Lords
|9 Ladies
|8 Maids
|7 Swans
|6 Geese
|5 Rings
|4 Birds
|3 Hens
|2 Turtle Doves
|a Partridge
|{m55_define|11 Pipers
|$$$1}}'}{m55_dnl}
{m55_define|song|`{$1|
  {m55_define|$1|`On the {getn|$1} day
{gets|$1}$2
{song|{1-|$1}|{gets|$1}$2}'}
  {m55_define|-1|`On the 12th day
12 Drummers
'$2}}'}{m55_dnl}
{song|:}{m55_dnl}

色相環はマクロでやるのがそんなに面白そうでもなかったのでRubyで書いた(円の生成法に http://parametron.blogspot.jp/2008/07/blog-post_24.html のものを使っているので、楕円になっている)。

include Math

NUM_OF_DIV = 6

def get_rgb sel, i
  case sel
  when "f" then
    255
  when "d" then
    ((255*(NUM_OF_DIV-i)).to_f / NUM_OF_DIV).round
  when "0" then
    0
  when "u" then
    ((255*i).to_f / NUM_OF_DIV).round
  else
    raise
  end
end

magic = "fd00uffd00uffd00uf"

outer_radius = 125
inner_radius = 25

  print <<EOS
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256">
  <g style="stroke-width:0.1">
EOS

  eps = PI / (6 * NUM_OF_DIV)

  p1 = nil

  old_x, old_y = 1.0, 0.0

  (0 ... 6).each {|col|
    (0 ... NUM_OF_DIV).each {|i|
      rgb = [get_rgb(magic[col], i), get_rgb(magic[col+4], i), get_rgb(magic[col+2], i)]
      rgb.map! {|a| "%02x" % [a]}
      rgb = rgb.join
      rgb[0, 0] = "#"
      x1 = old_x - eps * old_y
      y1 = old_y + eps * x1
      unless p1 then
        p1 = [x1, y1]
        old_x, old_y = x1, y1
      else
        print %!    <g style="color:#{rgb}">\n!
        x2 = x1 - eps * y1
        y2 = y1 + eps * x2
        x_1, y_1 = [old_x, old_y].map{|a| 128 + outer_radius * a }
        x_2, y_2 = [x1, y1].map{|a| 128 + outer_radius * a }
        x_3, y_3 = [x2, y2].map{|a| 128 + outer_radius * a }
        x_4, y_4 = [x2, y2].map{|a| 128 + inner_radius * a }
        x_5, y_5 = [x1, y1].map{|a| 128 + inner_radius * a }
        x_6, y_6 = [old_x, old_y].map{|a| 128 + inner_radius * a }
        print %!      <path style="stroke:currentColor;fill:currentColor" d="M#{x_1} #{y_1}L#{x_2} #{y_2} #{x_3} #{y_3} #{x_4} #{y_4} #{x_5} #{y_5} #{x_6} #{y_6}"/>\n!
        print %!    </g>\n!

        old_x, old_y = x2, y2
      end
    }
  }
  print %!    <g style="color:#ff0000">\n!
  x_1, y_1 = [old_x, old_y].map{|a| 128 + outer_radius * a }
  x_2, y_2 = [1.0, 0.0].map{|a| 128 + outer_radius * a }
  x_3, y_3 = [p1[0], p1[1]].map{|a| 128 + outer_radius * a }
  x_4, y_4 = [p1[0], p1[1]].map{|a| 128 + inner_radius * a }
  x_5, y_5 = [1.0, 0.0].map{|a| 128 + inner_radius * a }
  x_6, y_6 = [old_x, old_y].map{|a| 128 + inner_radius * a }
  print %!      <path style="stroke:currentColor;fill:currentColor" d="M#{x_1} #{y_1}L#{x_2} #{y_2} #{x_3} #{y_3} #{x_4} #{y_4} #{x_5} #{y_5} #{x_6} #{y_6}"/>\n!
  print %!    </g>\n!

if false then
  epsiron = 2.0 * PI / NUM_OF_DIV

  old_x = 1.0
  old_y = 0.0

  (0 ... NUM_OF_DIV).each {
    new_x = old_x - epsiron * old_y
    new_y = old_y + epsiron * new_x

    print %!    <line x1="#{old_x*100.0}" y1="#{old_y*100.0}" x2="#{new_x*100.0}" y2="#{new_y*100.0}"/>\n!

    old_x = new_x
    old_y = new_y
  }
end

  print <<EOS
  </g>
</svg>
EOS