Mae向きなブログ

Mae向きな情報発信を続けていきたいと思います。

数学ガールの秘密ノート/ビットとバイナリー(1)

数学ガールの秘密ノート/ビットとバイナリー』の「第2章 変幻ピクセル」で紹介されている内容を実際に作って動かしてみました。読んでいるだけで楽しい本書ですが、実際に動かしてみるとさらに楽しくなりますね。

出来るだけ本文に沿った形で作ってみたかったのですが、FILETERだけが少し違っています。while文がない形になってしまいました。

bits_and_binary.rb

copy.rb

スキャナで読んで、フィルタを通さずにプリンタで出力するだけです。

require_relative 'bits_and_binary'

if __FILE__ == $0
  scanner = SCAN.new("F.txt")
  printer = PRINT.new(scanner)
  printer.execute
end

F.txt

0000000000000000
0000000000000000
0011111111111100
0011111111111100
0011111111111100
0011100000000000
0011100000000000
0011111111111100
0011111111111100
0011111111111100
0011100000000000
0011100000000000
0011100000000000
0011100000000000
0000000000000000
0000000000000000

実行

上記のbits_and_binary.rb,copy.rbF.txtを同じディレクトリに置いて実行すると以下のように出力されます。1は#、0は.で出力しています。

$ ruby copy.rb
................
................
..############..
..############..
..############..
..###...........
..###...........
..############..
..############..
..############..
..###...........
..###...........
..###...........
..###...........
................
................

complement_xor.rb

ビット反転です。FILTERクラスを継承したCOMPLEMENT_XORクラスを定義し、readメソッドの中でフィルタ処理を書いていきます。

require_relative 'bits_and_binary'

class COMPLEMENT_XOR < FILTER
  def read
    super ^ 0xffff
  end
end

if __FILE__ == $0
  scanner = SCAN.new("F.txt")
  filter  = COMPLEMENT_XOR.new(scanner)
  printer = PRINT.new(filter)
  printer.execute
end

実行

$ ruby complement_xor.rb
################
################
##............##
##............##
##............##
##...###########
##...###########
##............##
##............##
##............##
##...###########
##...###########
##...###########
##...###########
################
################

reverse_trick.rb

左右の反転です。

require_relative 'bits_and_binary'

class REVERSE_TRICK < FILTER
  def read
    m1 = 0b0101010101010101
    m2 = 0b0011001100110011
    m4 = 0b0000111100001111
    m8 = 0b0000000011111111
    x = super
    x = ((x & m1) << 1) | ((x >> 1) & m1)
    x = ((x & m2) << 2) | ((x >> 2) & m2)
    x = ((x & m4) << 4) | ((x >> 4) & m4)
    x = ((x & m8) << 8) | ((x >> 8) & m8)
    x
  end
end

if __FILE__ == $0
  scanner = SCAN.new("F.txt")
  filter  = REVERSE_TRICK.new(scanner)
  printer = PRINT.new(filter)
  printer.execute
end

実行

$ ruby reverse_trick.rb
................
................
..############..
..############..
..############..
...........###..
...........###..
..############..
..############..
..############..
...........###..
...........###..
...........###..
...........###..
................
................

hemming.rb

縁取りです。

require_relative 'bits_and_binary'

class RIGHT < FILTER
  def read
    super >> 1
  end
end

class LEFT < FILTER
  def read
    super << 1
  end
end

class UP < FILTER
  def initialize source
    super
    @counter = 0
  end
  def read
    @counter += 1
    super if @counter == 1
    @counter >= 16 ? 0 : super
 end
end

class DOWN < FILTER
  def initialize source
    super
    @counter = 0
  end
  def read
    @counter += 1
    @counter == 1 ? 0 : super
  end
end

class AND < FILTER
  def read
    a, b = super
    a & b
  end
end

class COMPLEMENT < FILTER
  def read
    0xffff - super
  end
end

if __FILE__ == $0
  scanner0 = SCAN.new("F.txt")
  scanner1 = SCAN.new("F.txt")
  scanner2 = SCAN.new("F.txt")
  scanner3 = SCAN.new("F.txt")
  scanner4 = SCAN.new("F.txt")
  right    = RIGHT.new(scanner1)
  left     = LEFT.new(scanner2)
  up       = UP.new(scanner3)
  down     = DOWN.new(scanner4)
  and1     = AND.new(right, left)
  and2     = AND.new(up, down)
  and3     = AND.new(and1, and2)
  comp     = COMPLEMENT.new(and3)
  and4     = AND.new(scanner0, comp)
  printer  = PRINT.new(and4)
  printer.execute
end

実行

数種類の部品がお互いに連携しあって、出力される様は非常に面白いですね。

$ ruby hemming.rb
................
................
..############..
..#..........#..
..#..#########..
..#.#...........
..#.#...........
..#..#########..
..#..........#..
..#..#########..
..#.#...........
..#.#...........
..#.#...........
..###...........
................
................