こんなBrainf*ckのコードを,
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.
こんな殴り合い(ボクシング)に変換する.
(o'-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')≡o)゚-')=o)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')=o)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')=o)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-゚(o=('-゚(o=('-゚(o=('-゚(6('-゚(o≡('-'o)(o'-')=o)゚-')-o)゚-')=o)゚-')9)゚-')9)゚-')-o)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')-o)゚-')-o)゚-')9)゚-')9)゚-')9)゚-')-o)゚-')=o)゚-゚(6('-'o)(o'-')-o)゚-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-'o)(o'-')-o)゚-゚(o=('-'o)(o'-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')9)゚-')-o)゚-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-'o)(o'-')-o)゚-')9)゚-')9)゚-')9)゚-')-o)゚-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-'o)(o'-')-o)゚-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-゚(6('-'o)(o'-')-o)゚-')=o)゚-')9)゚-')-o)゚-'o)
誰得!
Brainf*ckの詳細についてはWikipediaを参照してね.
http://ja.wikipedia.org/wiki/Brainfuck
変換規則
変換規則は以下の通り.
変換前 | 変換後 |
---|---|
> | (o'-')=o |
< | o=('-'o) |
+ | (o'-')9 |
- | 6('-'o) |
. | (o'-')-o |
, | o-('-'o) |
[ | (o'-')≡o |
] | o≡('-'o) |
さらに,
- 右向きに殴るやつが連続した場合は,殴られる側の顔を")゚"のように凹ませる
- 左向きに殴るやつが連続した場合は,殴られる側の顔を"゚("のように凹ませる
- 最初に左向きに殴るやつが来た場合はその左に"(o'-゚("を追加
- 最後に右向きに殴るやつが来た場合はその右に")゚-'o)"を追加
- 右向きに殴るやつと左向きに殴るやつが向かい合った場合は間に")゚-゚("を追加
変換コード
Ruby 1.9で動作確認済み.
#!/usr/bin/env ruby1.9 # -*- coding: utf-8 -*- def enboxing(code) boxing = { ">" => "(o'-')=o", "<" => "o=('-'o)", "+" => "(o'-')9", "-" => "6('-'o)", "." => "(o'-')-o", "," => "o-('-'o)", "[" => "(o'-')≡o", "]" => "o≡('-'o)", } result = "" code.each_char do |c| next if !boxing[c] c = boxing[c].clone if c[0..2] == "(o'" && ["o", "9"].include?(result[-1]) c[0..2] = ")゚" elsif result[-3..-1] == "'o)" && ["o", "6"].include?(c[0]) result[-3..-1] = "゚(" elsif ["o", "9"].include?(result[-1]) && ["o", "6"].include?(c[0]) result += ")゚-゚(" end result += c end if ["o", "6"].include?(result[0]) result += "(o'-゚(" end if ["o", "9"].include?(result[-1]) result += ")゚-'o)" end result end if __FILE__ == $0 puts enboxing(ARGF.read) end
復元コード
殴り合いをBrainf*ckのコードに再変換する.殴る手の形さえ考慮すれば元のコードを復元できる.
#!/usr/bin/env ruby1.9 # -*- coding: utf-8 -*- def deboxing(code) result = code.gsub(/['゚]-['゚]/, "") result.gsub!(/=o/, ">") result.gsub!(/o=/, "<") result.gsub!(/9/, "+") result.gsub!(/6/, "-") result.gsub!(/-o/, ".") result.gsub!(/o-/, ",") result.gsub!(/≡o/, "[") result.gsub!(/o≡/, "]") result.gsub!(/[^><+-\.,\[\]]/, "") result end if __FILE__ == $0 puts deboxing(ARGF.read) end
あとは復元したコードをBrainf*ckのインタプリタで実行すればOK.
殴り合いコード用インタプリタ
#!/usr/bin/env ruby1.9 # -*- coding: utf-8 -*- class Brainfxxk class ProgramError < StandardError; end def self.run(code) tokens = code.chars.to_a jumps = analyze_jumps(tokens) output = "" mem = [] pc = 0 ptr = 0 while pc < tokens.size mem[ptr] ||= 0 case tokens[pc] when "+" mem[ptr] = (mem[ptr] + 1) % 256 when "-" mem[ptr] = (mem[ptr] + 255) % 256 when ">" ptr += 1 when "<" ptr -= 1 raise ProgramError, "ptr < 0" unless ptr >= 0 when "." output += mem[ptr].chr when "," mem[ptr] = $stdin.getc.ord when "[" if mem[ptr] == 0 pc = jumps[pc] end when "]" if mem[ptr] != 0 pc = jumps[pc] end end pc += 1 end output end def self.analyze_jumps(tokens) jumps = {} starts = [] tokens.each_with_index do |c, i| if c == "[" starts.push(i) elsif c == "]" raise ProgramError, "the number of [ and ] don't match" unless !starts.empty? from = starts.pop to = i jumps[from] = to jumps[to] = from end end raise ProgramError, "the number of [ and ] ddon't match" unless starts.empty? jumps end end def deboxing(code) result = code.gsub(/['゚]-['゚]/, "") result.gsub!(/=o/, ">") result.gsub!(/o=/, "<") result.gsub!(/9/, "+") result.gsub!(/6/, "-") result.gsub!(/-o/, ".") result.gsub!(/o-/, ",") result.gsub!(/≡o/, "[") result.gsub!(/o≡/, "]") result.gsub!(/[^><+-\.,\[\]]/, "") result end if __FILE__ == $0 code = ARGF.read puts Brainfxxk.run(deboxing(code)) end
ちなみにBrainf*ck用classの実装はyharaさんのRubyで作る奇妙なプログラミング言語 ~Esoteric Language~を参考にさせていただきました.