Решение на Четвърта задача от Моника Димитрова

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

Към профила на Моника Димитрова

Резултати

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

Код

module Asm
class Evaluator
attr_accessor :registers, :operations_queue
attr_reader :ax, :bx, :cx, :dx
operations = {
mov: :'mov',
inc: :'+',
dec: :'-',
cmp: :'<=>',
jmp: :'jmp',
}
operations.each do |operation, operator|
define_method operation do |register, value = 1|
@operations_queue << {index: register, value: value, operator: operator}
end
end
def initialize
@registers = {ax: 0, bx: 0, cx: 0, dx: 0}
@labels = {}
@operations_queue = []
@ax = :ax
@bx = :bx
@cx = :cx
@dx = :dx
end
def label(label_name)
@labels[label_name] = operations_queue.size
end
def jump(jump_operator, label)
#TODO
end
def method_missing(method)
method.to_s
end
def evaluate(start_index)
operations_queue.each do |operation|
index = operation[:index]
value = operation[:value]
operator = operation[:operator]
if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include? operator
jump(operator, index)
break
else
update_register(index, value, operator)
end
end
@registers.values
end
private
def update_register(index, value, operator)
value = registers[value] if value.is_a? Symbol
if operator == :mov
registers[index] = value
elsif operator == :<=>
operator.to_proc.call(registers[index], value)
else
registers[index] = operator.to_proc.call(registers[index], value)
end
end
end
def self.asm(&block)
e = Evaluator.new
e.instance_eval &block
e.evaluate(0)
end
end

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

....FFFF

Failures:

  1) Asm.asm implements CMP
     Failure/Error: je 5
     ArgumentError:
       wrong number of arguments (2 for 1)
     # /tmp/d20140115-8451-cups5f/solution.rb:38:in `method_missing'
     # /tmp/d20140115-8451-cups5f/spec.rb:38:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-cups5f/solution.rb:73:in `instance_eval'
     # /tmp/d20140115-8451-cups5f/solution.rb:73:in `asm'
     # /tmp/d20140115-8451-cups5f/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: Asm.asm do
       
       expected: [0, 0, 1, 1]
            got: [0, 0, 1, 0]
       
       (compared using ==)
     # /tmp/d20140115-8451-cups5f/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
     ArgumentError:
       wrong number of arguments (2 for 1)
     # /tmp/d20140115-8451-cups5f/solution.rb:38:in `method_missing'
     # /tmp/d20140115-8451-cups5f/spec.rb:81:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-cups5f/solution.rb:73:in `instance_eval'
     # /tmp/d20140115-8451-cups5f/solution.rb:73:in `asm'
     # /tmp/d20140115-8451-cups5f/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: je finish
     ArgumentError:
       wrong number of arguments (2 for 1)
     # /tmp/d20140115-8451-cups5f/solution.rb:38:in `method_missing'
     # /tmp/d20140115-8451-cups5f/spec.rb:94:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-cups5f/solution.rb:73:in `instance_eval'
     # /tmp/d20140115-8451-cups5f/solution.rb:73:in `asm'
     # /tmp/d20140115-8451-cups5f/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.00766 seconds
8 examples, 4 failures

Failed examples:

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

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

Моника обнови решението на 15.01.2014 17:13 (преди почти 11 години)

+module Asm
+ class Evaluator
+ attr_accessor :registers, :operations_queue
+ attr_reader :ax, :bx, :cx, :dx
+
+ operations = {
+ mov: :'mov',
+ inc: :'+',
+ dec: :'-',
+ cmp: :'<=>',
+ jmp: :'jmp',
+ }
+
+ operations.each do |operation, operator|
+ define_method operation do |register, value = 1|
+ @operations_queue << {:index => register, :value => value, :operator => operator}
+ end
+ end
+
+ def initialize
+ @registers = {:ax => 0, :bx => 0,:cx => 0, :dx => 0}
+ @labels = {}
+ @operations_queue = []
+ @ax = :ax
+ @bx = :bx
+ @cx = :cx
+ @dx = :dx
+ end
+
+ def label(label_name)
+ @labels[label_name] = operations_queue.size
+ end
+
+ def jump(jump_operator, label)
+ #TODO
+ end
+
+ def method_missing(method)
+ method.to_s
+ end
+
+ def evaluate(start_index)
+ operations_queue.each do |operation|
+ index = operation[:index]
+ value = operation[:value]
+ operator = operation[:operator]
+ if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include? operator
+ jump(operator, index)
+ break
+ else
+ update_register(index, value, operator)
+ end
+ end
+ @registers.values
+ end
+
+ private
+
+ def update_register(index, value, operator)
+ value = registers[value] if value.is_a? Symbol
+ if operator == :mov
+ registers[index] = value
+ elsif operator == :<=>
+ operator.to_proc.call(registers[index], value)
+ else
+ registers[index] = operator.to_proc.call(registers[index], value)
+ end
+ end
+ end
+
+ def self.asm(&block)
+ e = Evaluator.new
+ e.instance_eval &block
+ e.evaluate(0)
+ end
+end

Моника обнови решението на 15.01.2014 17:25 (преди почти 11 години)

module Asm
class Evaluator
attr_accessor :registers, :operations_queue
attr_reader :ax, :bx, :cx, :dx
operations = {
mov: :'mov',
inc: :'+',
dec: :'-',
cmp: :'<=>',
jmp: :'jmp',
}
operations.each do |operation, operator|
define_method operation do |register, value = 1|
- @operations_queue << {:index => register, :value => value, :operator => operator}
+ @operations_queue << {index: register, value: value, operator: operator}
end
end
def initialize
- @registers = {:ax => 0, :bx => 0,:cx => 0, :dx => 0}
+ @registers = {ax: 0, bx: 0, cx: 0, dx: 0}
@labels = {}
@operations_queue = []
@ax = :ax
@bx = :bx
@cx = :cx
@dx = :dx
end
def label(label_name)
@labels[label_name] = operations_queue.size
end
def jump(jump_operator, label)
#TODO
end
def method_missing(method)
method.to_s
end
def evaluate(start_index)
operations_queue.each do |operation|
index = operation[:index]
value = operation[:value]
operator = operation[:operator]
if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include? operator
jump(operator, index)
break
else
update_register(index, value, operator)
end
end
@registers.values
end
private
def update_register(index, value, operator)
value = registers[value] if value.is_a? Symbol
if operator == :mov
registers[index] = value
elsif operator == :<=>
operator.to_proc.call(registers[index], value)
else
registers[index] = operator.to_proc.call(registers[index], value)
end
end
end
def self.asm(&block)
e = Evaluator.new
e.instance_eval &block
e.evaluate(0)
end
end

Като изключим повторенията на имената на регистрите на някои места и неспазването на конвенцията на 54-ти ред всичко е започнало добре. Дребен съвет: в Asm.asm имаше едно e.evaluate(0). Понеже го прочетох преди да видя имплементацията на Evaluator#evaluate първата ми реакция беше „WTF?“ и чак после видях, че 0 отива в аргумент, който се казва start_index и всичко си дойде на мястото. Това е чудесно място да се използва keyword аргумент – e.evaluate(start_index: 0) и „WTF“-а щеше да бъде спестен. :-)

P.S. wtf/m е чудесна метрика за качеството на кода :-)