Решение на Четвърта задача от Илия Тобов

Обратно към всички решения

Към профила на Илия Тобов

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 4 успешни тест(а)
  • 4 неуспешни тест(а)

Код

module Asm
class Evaluator
attr_accessor :ax, :bx, :cx, :dx, :registers, :last_cmp, :operations_queue
operations = {
mov: :'=',
inc: :'+',
dec: :'-',
cmp: :'<=>',
jg: :'jg',
label: :'label'
}
operations.each do |operation_name, operation|
define_method operation_name do |*arguments|
@operations_queue << [operation, *arguments]
end
end
def initialize
@ax, @bx, @cx, @dx = Register.new("ax"), Register.new("bx"),
Register.new("cx"), Register.new("dx")
@registers = [@ax, @bx, @cx, @dx]
@operations_queue = []
@labeled_operations = {}
end
def ax=(value)
@ax.value = value
end
def bx=(value)
@bx.value = value
end
def cx=(value)
@cx.value = value
end
def dx=(value)
@dx.value = value
end
end
def self.perform_operations(evaluator)
evaluator.operations_queue.each do |operation|
if operation[0] == :'='
evaluator.send operation[1].name+"=", get_value(operation[2])
else
is_cmp?(operation, evaluator)
end
end
end
private
def self.is_cmp?(operation, evaluator)
if operation[0] == :'<=>'
evaluator.last_cmp = operation[1].value.send operation[0], get_value(operation[2])
else
operation[1].value = operation[1].value.send operation[0], get_value(operation[2])
end
end
def self.get_value(value)
value.nil? ? 1 : ((value.is_a? Integer) ? value : value.value)
end
def self.asm(&block)
evaluator = Evaluator.new
evaluator.instance_eval(&block)
perform_operations(evaluator)
evaluator.registers.map { |register| register.value }
end
class Register
attr_accessor :value, :name
def initialize(name)
@value = 0
@name = name
end
end
end

Лог от изпълнението

....FFFF

Failures:

  1) Asm.asm implements CMP
     Failure/Error: je 5
     NoMethodError:
       undefined method `je' for #<Asm::Evaluator:0xb88dfc08>
     # /tmp/d20140115-8451-16zvc94/spec.rb:38:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `instance_eval'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `asm'
     # /tmp/d20140115-8451-16zvc94/spec.rb:34:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Asm.asm implements JMP
     Failure/Error: jmp l1
     NameError:
       undefined local variable or method `l1' for #<Asm::Evaluator:0xb88de114>
     # /tmp/d20140115-8451-16zvc94/spec.rb:70:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `instance_eval'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `asm'
     # /tmp/d20140115-8451-16zvc94/spec.rb:68:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Asm.asm implements LABEL
     Failure/Error: je l1
     NameError:
       undefined local variable or method `l1' for #<Asm::Evaluator:0xb88dc33c>
     # /tmp/d20140115-8451-16zvc94/spec.rb:81:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `instance_eval'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `asm'
     # /tmp/d20140115-8451-16zvc94/spec.rb:78:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Asm.asm can be used to find GCD of two numbers
     Failure/Error: label cycle
     NameError:
       undefined local variable or method `cycle' for #<Asm::Evaluator:0xb88d9970>
     # /tmp/d20140115-8451-16zvc94/spec.rb:92:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `instance_eval'
     # /tmp/d20140115-8451-16zvc94/solution.rb:72:in `asm'
     # /tmp/d20140115-8451-16zvc94/spec.rb:89:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.00707 seconds
8 examples, 4 failures

Failed examples:

rspec /tmp/d20140115-8451-16zvc94/spec.rb:33 # Asm.asm implements CMP
rspec /tmp/d20140115-8451-16zvc94/spec.rb:67 # Asm.asm implements JMP
rspec /tmp/d20140115-8451-16zvc94/spec.rb:77 # Asm.asm implements LABEL
rspec /tmp/d20140115-8451-16zvc94/spec.rb:88 # Asm.asm can be used to find GCD of two numbers

История (1 версия и 1 коментар)

Илия обнови решението на 15.01.2014 17:18 (преди почти 11 години)

+module Asm
+ class Evaluator
+
+ attr_accessor :ax, :bx, :cx, :dx, :registers, :last_cmp, :operations_queue
+
+ operations = {
+ mov: :'=',
+ inc: :'+',
+ dec: :'-',
+ cmp: :'<=>',
+ jg: :'jg',
+ label: :'label'
+ }
+
+ operations.each do |operation_name, operation|
+ define_method operation_name do |*arguments|
+ @operations_queue << [operation, *arguments]
+ end
+ end
+
+ def initialize
+ @ax, @bx, @cx, @dx = Register.new("ax"), Register.new("bx"),
+ Register.new("cx"), Register.new("dx")
+ @registers = [@ax, @bx, @cx, @dx]
+ @operations_queue = []
+ @labeled_operations = {}
+ end
+
+ def ax=(value)
+ @ax.value = value
+ end
+
+ def bx=(value)
+ @bx.value = value
+ end
+
+ def cx=(value)
+ @cx.value = value
+ end
+
+ def dx=(value)
+ @dx.value = value
+ end
+ end
+
+ def self.perform_operations(evaluator)
+ evaluator.operations_queue.each do |operation|
+ if operation[0] == :'='
+ evaluator.send operation[1].name+"=", get_value(operation[2])
+ else
+ is_cmp?(operation, evaluator)
+ end
+ end
+ end
+
+ private
+
+ def self.is_cmp?(operation, evaluator)
+ if operation[0] == :'<=>'
+ evaluator.last_cmp = operation[1].value.send operation[0], get_value(operation[2])
+ else
+ operation[1].value = operation[1].value.send operation[0], get_value(operation[2])
+ end
+ end
+
+ def self.get_value(value)
+ value.nil? ? 1 : ((value.is_a? Integer) ? value : value.value)
+ end
+
+ def self.asm(&block)
+ evaluator = Evaluator.new
+ evaluator.instance_eval(&block)
+ perform_operations(evaluator)
+
+ evaluator.registers.map { |register| register.value }
+ end
+
+ class Register
+ attr_accessor :value, :name
+
+ def initialize(name)
+ @value = 0
+ @name = name
+ end
+ end
+end

Кодът не спазва Tell, Don't Ask. Чудесни примери можеш да видиш тук. Още по темата тук и тук.

По-конкретно виж имплементацията на Asm.asm:

def self.asm(&block)
  evaluator = Evaluator.new
  evaluator.instance_eval(&block)
  perform_operations(evaluator)

  evaluator.registers.map { |register| register.value }
end

Вместо perform_operations(evaluator) щеше да е по-добре да има метод evaluator.perform_operations. Вместо evaluator.registers.map { ... } примерно щеше да е по-добре evaluator.register_values. Така няма да вържем Asm.asm с Asm::Register, понеже в момента Asm.asm знае, че има клас за регистри, който има метод value.

Можем да изведем този подход до крайност така:

def self.asm(&block)
  Evaluator.evaluate(&block).register_values
end

Подобен подход можеш да видиш в някои от решенията на колегите ти.