4
\$\begingroup\$

I wrote this interpreter for a code challenge. Can this be written any cleaner/smaller? Could I reduce the amount of nested conditional/loops?

def brain_luck(code, input)
  output = ''
  cp = 0 # code pointer
  dp = 0 # data pointer
  ip = 0 # input pointer
  data = Array.new(10, 0)
  while cp < code.length
    case code[cp]
    when '>'
      dp += 1
      if dp == data.length
        data.push(0)
      end
    when '<'
      dp -= 1
      if dp == -1
        dp = 0
        data.unshift(0)
      end
    when '+'
      data[dp] = (data[dp].ord+1)%256
    when '-'
      data[dp] = (data[dp].ord-1)%256
    when '.'
      output += data[dp].chr
    when ','
      data[dp] = input[ip].ord
      ip += 1
    when '['
      if data[dp] == 0
        nest_count = 1
        while nest_count > 0
          case code[cp += 1]
          when '[' then nest_count += 1
          when ']' then nest_count -= 1
          end
        end
      end
    when ']' 
      if data[dp] != 0
        nest_count = 1
        while nest_count > 0
          case code[cp -= 1]
          when ']' then nest_count += 1
          when '[' then nest_count -= 1
          end
        end
      end
    end
    cp += 1
  end
  output
end
\$\endgroup\$
  • \$\begingroup\$ I know you don't want to swear, but brain_luck is not the way to go. It's confusing since it doesn't make sense why there is a function like that. You could just do something like eval_program. \$\endgroup\$ – Dair Dec 20 '16 at 0:20
  • \$\begingroup\$ brain_luck was how the code challenge presented it (same with the double * in brainf**k) \$\endgroup\$ – Mirror318 Dec 20 '16 at 0:33
  • \$\begingroup\$ Ok, if you need to submit it that way for the challenge, but outside of the challenge, I would highly recommend changing it. :) \$\endgroup\$ – Dair Dec 20 '16 at 0:35
  • 1
    \$\begingroup\$ Does it work for this BF-program now? ,>+>>>>++++++++++++++++++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<+>>[-]]<<<<<<<]>>>>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++++++++++++++++++++++++++++++++++++++++++++++.[-]<<<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-] \$\endgroup\$ – Simon Forsberg Dec 20 '16 at 9:41
  • \$\begingroup\$ @SimonForsberg sure does ;) \$\endgroup\$ – Mirror318 Dec 20 '16 at 21:08
1
\$\begingroup\$

Sure it can!

Steps I see to make it clean:

  1. Create a class, define state attrs:

    private
    
    attr_reader :output, :code_pointer, :data_pointer, :input_pointer
    
  2. define initialize method

    def initialize(args = {})
      @code = args[:code]
      @input = args[:input]
      @output = ''
      @code_pointer, @data_pointer, @input_pointer = 0, 0, 0
    end
    
  3. define whens as a methods and give it right names: next_cell, prev_cell, increment, decrement, write_byte, read_byte and so on

  4. define constant for configuration:

    OPERATORS = {
      '>' => :next_cell,
      '<' => :prev_cell,
      '+' => :increment,
      ...
    }
    
  5. define method to evaluate code:

    def evaluate_code
      code.each { |operator| public_send OPERATORS[operator] }
    end
    
  6. Finally instantiate object of your class and call evaluate_code

    BrainLuck.new(code: code, input: input).evaluate_code
    

I think you'll love your object oriented result.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.