[QUIZ][SOLUTION] Secret Agent 00111 (#94)

Hi,

here is my solution (00111_gizmo.rb)

Karl

···

####################################

require 'stringio'

class SecretAgent00111CommunicationGizmo
  
  class UndefinedRLE < StandardError
  end
  
private

  class Rle
    def initialize
      @data = []
      @count = 0
    end
    
    def <<(event)
      if event
        @count += 1
      else
        @data << @count
        @count = 0
      end
    end
    
    def get
      @count == 0 ? @data : nil
    end
  end
  
  class UnRle
    def initialize
      @data = []
    end
    
    attr_reader :data
    
    def <<(count)
      count.times { @data << true }
      @data << false
    end
  end
  
public
  
  class Encoder < Rle
    def initialize(exponent, output)
      super()

      @output = output
      @exponent = exponent

      @byte = 0
      @byte_bit = 0x80
      
      insert @exponent, 8
    end
    
    def <<(event)
      super(event)
      while count = @data.shift
        (count >> @exponent).times { insert 1 }
        insert 0
        insert count, @exponent
      end
    end
    
    def finish
      self << false
      insert 1 while @byte_bit != 0x80
    end
    
  private

    def insert(num, bits = 1)
      (bits-1).downto(0) do |n|
        @byte |= @byte_bit if num[n] == 1
        if (@byte_bit >>= 1) == 0
          @output.putc @byte

          @byte_bit = 0x80
          @byte = 0
        end
      end
    end
  end
  
  class Decoder < UnRle
    def initialize(input)
      super()
      
      @exponent = 0
      @input = input

      @count = 0
      @remainder_bit = 0
    end

    def exponent
      decode
      @exponent
    end
    
    def read
      decode
      data = @data
      @data = []
      data
    end

  private
  
    def decode
      while byte = @input.getc
        if @exponent == 0
          @exponent = byte
        else
          insert byte
        end
      end
    end
    
    def insert(byte)
      7.downto(0) do |n|
        if @remainder_bit == 0
          if byte[n] == 1
            @count += 1 << @exponent
          else
            @remainder_bit = 1 << (@exponent - 1)
          end
        else
          @count += @remainder_bit if byte[n] == 1
          if (@remainder_bit >>= 1) == 0
            self.<<(@count)
            @count = 0
          end
        end
      end
    end
  end
    
  def SecretAgent00111CommunicationGizmo.rle(arr)
    rle = Rle.new

    arr.each do |event|
      rle << event
    end
    out = rle.get
    
    raise UndefinedRLE, "undefined rle" unless out and not out.empty?
    out
  end
  
  def SecretAgent00111CommunicationGizmo.unrle(arr)
    unrle = UnRle.new
    
    arr.each do |count|
      unrle << count
    end
    
    unrle.data
  end
  
  def SecretAgent00111CommunicationGizmo.encode(arr, exp)
    io = StringIO.new
    encoder = Encoder.new(exp, io)
    
    arr.each do |event|
      encoder << event
    end
    encoder.finish
    
    io.string
  end
  
  def SecretAgent00111CommunicationGizmo.decode(bits)
    io = StringIO.new(bits)
    
    decoder = Decoder.new(io)
    arr = decoder.read
    
    arr.pop if arr.last == false
    arr
  end
  
end