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\$
5
  • \$\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
    Commented Dec 20, 2016 at 0:20
  • \$\begingroup\$ brain_luck was how the code challenge presented it (same with the double * in brainf**k) \$\endgroup\$
    – Mirror318
    Commented Dec 20, 2016 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
    Commented Dec 20, 2016 at 0:35
  • 1
    \$\begingroup\$ Does it work for this BF-program now? ,>+>>>>++++++++++++++++++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<+>>[-]]<<<<<<<]>>>>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++++++++++++++++++++++++++++++++++++++++++++++.[-]<<<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-] \$\endgroup\$ Commented Dec 20, 2016 at 9:41
  • \$\begingroup\$ @SimonForsberg sure does ;) \$\endgroup\$
    – Mirror318
    Commented Dec 20, 2016 at 21:08

1 Answer 1

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 and acknowledge you have read our privacy policy.

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