Решение на Четвърта задача от Йордан Пулов

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

Към профила на Йордан Пулов

Резултати

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

Код

#jump-овете само за label-и които вече са срещани
module Asm
class Inline_assembler
attr :ax , :bx , :cx , :dx
attr_reader :registers
def initialize()
@queue = {}
@registers={:ax=>{:value=>0},:bx=>{:value=>0},:cx =>{:value=>0},:dx=>{:value=>0}}
@ax = @registers[:ax]
@bx = @registers[:bx]
@cx = @registers[:cx]
@dx = @registers[:dx]
@last_cmp = 0
@Func = Struct.new(:name, :args)
end
conditional_jumps = {
je: :'==',
jne: :'!=',
jl: :'<',
jle: :'<=',
jg: :'>',
jge: :'>=',
}
conditional_jumps.each do |method_name, operation|
define_method method_name do |argument,*args|
jmp(argument,*args) if @last_cmp.send(operation,0)
end
end
def mov(x,y)
@queue.each {|_,j| j << @Func.new("mov", [x,y]) }
( y.is_a? Numeric )? x[:value] = y : x[:value] = y[:value]
self
end
def inc(x,y=1)
@queue.each {|_,j| j << @Func.new("inc", [x,y]) }
( y.is_a? Numeric )? x[:value] += y : x[:value] += y[:value]
self
end
def dec(x,y=1)
@queue.each {|_,j| j << @Func.new("dec", [x,y]) }
( y.is_a? Numeric )? x[:value] -= y : x[:value] -= y[:value]
self
end
def cmp (x,y)
@queue.each {|_,j| j << @Func.new("cmp", [x,y]) }
@last_cmp = ( y.is_a? Numeric )? x[:value] <=> y : x[:value] <=> y[:value]
self
end
def label (label_name)
@queue[label_name] = []
end
def jmp(where,*args)
n = @queue[where].size - 1
0.upto(n) do |j|
element = @queue[where][j]
send(element.name,element.args[0],element.args[1])
end
end
def method_missing(name , *args)
name
end
end
def self.asm(&block)
asm =Inline_assembler.new
asm.instance_eval(&block)
asm.registers.map { |_,e| e[:value] }
end
end

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

....FFFF

Failures:

  1) Asm.asm implements CMP
     Failure/Error: je 5
     NoMethodError:
       undefined method `size' for nil:NilClass
     # /tmp/d20140115-8451-luyg66/solution.rb:65:in `jmp'
     # /tmp/d20140115-8451-luyg66/solution.rb:32:in `block (2 levels) in <class:Inline_assembler>'
     # /tmp/d20140115-8451-luyg66/spec.rb:38:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-luyg66/solution.rb:80:in `instance_eval'
     # /tmp/d20140115-8451-luyg66/solution.rb:80:in `asm'
     # /tmp/d20140115-8451-luyg66/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
     NoMethodError:
       undefined method `size' for nil:NilClass
     # /tmp/d20140115-8451-luyg66/solution.rb:65:in `jmp'
     # /tmp/d20140115-8451-luyg66/spec.rb:70:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-luyg66/solution.rb:80:in `instance_eval'
     # /tmp/d20140115-8451-luyg66/solution.rb:80:in `asm'
     # /tmp/d20140115-8451-luyg66/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
     NoMethodError:
       undefined method `size' for nil:NilClass
     # /tmp/d20140115-8451-luyg66/solution.rb:65:in `jmp'
     # /tmp/d20140115-8451-luyg66/solution.rb:32:in `block (2 levels) in <class:Inline_assembler>'
     # /tmp/d20140115-8451-luyg66/spec.rb:81:in `block (3 levels) in <top (required)>'
     # /tmp/d20140115-8451-luyg66/solution.rb:80:in `instance_eval'
     # /tmp/d20140115-8451-luyg66/solution.rb:80:in `asm'
     # /tmp/d20140115-8451-luyg66/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: Asm.asm do
       
       expected: [8, 8, 0, 0]
            got: [-136, 192, 0, 0]
       
       (compared using ==)
     # /tmp/d20140115-8451-luyg66/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.0076 seconds
8 examples, 4 failures

Failed examples:

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

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

Йордан обнови решението на 12.01.2014 14:56 (преди почти 11 години)

+#без jump-овете и label
+module Asm
+
+ class Inline_assembler
+ attr :ax , :bx , :cx , :dx
+ attr_reader :registers
+ def initialize()
+
+ @registers={:ax=>{:val=>0},:bx=>{:val=>0},:cx =>{:val=>0},:dx=>{:val=>0}}
+ @ax = @registers[:ax]
+ @bx = @registers[:bx]
+ @cx = @registers[:cx]
+ @dx = @registers[:dx]
+ @last_cmp = 0
+ end
+
+ method_to_define = {
+ je: :'==',
+ jne: :'!=',
+ jl: :'<',
+ jle: :'<=',
+ jg: :'>',
+ jge: :'>=',
+
+ }
+
+ method_to_define.each do |method_name, operation|
+ define_method method_name do |argument|
+ jmp(argument) if @last_cmp.send(operation,0)
+ end
+ end
+
+ def mov(x,y)
+ ( y.is_a? Numeric )? x[:val] = y : x[:val] = y[:val]
+ self
+ end
+ def inc(x,y=1)
+ ( y.is_a? Numeric )? x[:val] += y : x[:val] += y[:val]
+ self
+ end
+ def dec(x,y=1)
+ ( y.is_a? Numeric )? x[:val] -= y : x[:val] -= y[:val]
+ self
+ end
+ def cmp (x,y)
+ @last_cmp = ( y.is_a? Numeric )? x[:val] <=> y : x[:val] <=> y[:val]
+ self
+ end
+ def label (label_name)
+ end
+ def jmp(where)
+ puts "GoGoGo"
+ end
+
+
+
+ end
+
+ def self.asm(&block)
+ asm =Inline_assembler.new
+ asm.instance_eval(&block)
+ return [asm.ax[:val] , asm.bx[:val] , asm.cx[:val] , asm.dx[:val]]
+ end
+end

Йордан обнови решението на 12.01.2014 17:46 (преди почти 11 години)

-#без jump-овете и label
+#jump-овете само за label-и които вече са срещани
module Asm
-
+ require 'thread'
class Inline_assembler
attr :ax , :bx , :cx , :dx
attr_reader :registers
def initialize()
-
+ @queue = {}
@registers={:ax=>{:val=>0},:bx=>{:val=>0},:cx =>{:val=>0},:dx=>{:val=>0}}
@ax = @registers[:ax]
@bx = @registers[:bx]
@cx = @registers[:cx]
@dx = @registers[:dx]
@last_cmp = 0
+ @Func = Struct.new(:name, :args)
end
method_to_define = {
je: :'==',
jne: :'!=',
jl: :'<',
jle: :'<=',
jg: :'>',
jge: :'>=',
}
method_to_define.each do |method_name, operation|
define_method method_name do |argument|
jmp(argument) if @last_cmp.send(operation,0)
end
end
def mov(x,y)
+
+ @queue.each {|_,j| j << @Func.new("mov", [x,y]) }
+
( y.is_a? Numeric )? x[:val] = y : x[:val] = y[:val]
self
end
def inc(x,y=1)
+ @queue.each {|_,j| j << @Func.new("inc", [x,y]) }
( y.is_a? Numeric )? x[:val] += y : x[:val] += y[:val]
self
end
def dec(x,y=1)
+ @queue.each {|_,j| j << @Func.new("dec", [x,y]) }
( y.is_a? Numeric )? x[:val] -= y : x[:val] -= y[:val]
self
end
def cmp (x,y)
+ @queue.each {|_,j| j << @Func.new("cmp", [x,y]) }
@last_cmp = ( y.is_a? Numeric )? x[:val] <=> y : x[:val] <=> y[:val]
self
end
def label (label_name)
+
+ @queue[label_name.to_sym] = []
end
def jmp(where)
- puts "GoGoGo"
+ n = @queue[where.to_sym].size - 1
+ 0.upto(n) do |j|
+ element = @queue[where.to_sym][j]
+ send(element.name.to_sym,element.args[0],element.args[1])
+ end
end
-
-
-
end
-
def self.asm(&block)
asm =Inline_assembler.new
asm.instance_eval(&block)
return [asm.ax[:val] , asm.bx[:val] , asm.cx[:val] , asm.dx[:val]]
end
-end
+end
  • require-нал си thread без да го използваш.
  • @registers, дефиниран като Hash от Hash-ове, е пример за Primitive obsession. Помисли има ли начин да превърнеш регистрите в обекти, които спазват определен интерфейс, ако ще и само с употребата на Struct.new :value. Предимството на това да използваш Struct е, че ако някой ден искаш да добавиш функционалност към регистрите (например някакъв метод) просто ще напишеш един клас с attr_accessor :value, ще си добавиш новите методи и няма да променяш съществуващ код. Ако го запазиш като Hash ще трябва да превърнеш всички срещания на код от типа x[:val] в x.value, например.
  • Hardcode-ването на имената на регистрите е лошо. Каква част от кода си ще трябва да пренапишеш, ако условието на задачата се промени и се каже, че регистрите няма да ax, bx, cx и dx, а a, b, c, d, e и f? Освен това имената са hardcode-нати на различни места из цялата програма, което е в разрез с DRY принципа
  • :val -> :value С какво пропускането на две букви подобрява четимостта на кода?
  • Whitespace-а е лош. Разгледай style guide-а и пооправи нещата, понеже ще взимаме точки за лош whitespace. Например, трябва да има празен ред между дефинициите на методите.
  • method_to_define не е добро име, особено като се вземе предвид, че зад името стои колекция от неща. jumps, или дори conditional_jumps е по-описателно.

Йордан обнови решението на 15.01.2014 09:56 (преди почти 11 години)

#jump-овете само за label-и които вече са срещани
module Asm
- require 'thread'
+
class Inline_assembler
attr :ax , :bx , :cx , :dx
attr_reader :registers
+
def initialize()
@queue = {}
- @registers={:ax=>{:val=>0},:bx=>{:val=>0},:cx =>{:val=>0},:dx=>{:val=>0}}
+ @registers={:ax=>{:value=>0},:bx=>{:value=>0},:cx =>{:value=>0},:dx=>{:value=>0}}
@ax = @registers[:ax]
@bx = @registers[:bx]
@cx = @registers[:cx]
@dx = @registers[:dx]
@last_cmp = 0
@Func = Struct.new(:name, :args)
end
- method_to_define = {
+ conditional_jumps = {
je: :'==',
jne: :'!=',
jl: :'<',
jle: :'<=',
jg: :'>',
jge: :'>=',
}
- method_to_define.each do |method_name, operation|
- define_method method_name do |argument|
- jmp(argument) if @last_cmp.send(operation,0)
+ conditional_jumps.each do |method_name, operation|
+ define_method method_name do |argument,*args|
+
+ jmp(argument,*args) if @last_cmp.send(operation,0)
end
end
def mov(x,y)
-
@queue.each {|_,j| j << @Func.new("mov", [x,y]) }
-
- ( y.is_a? Numeric )? x[:val] = y : x[:val] = y[:val]
+ ( y.is_a? Numeric )? x[:value] = y : x[:value] = y[:value]
self
end
+
def inc(x,y=1)
@queue.each {|_,j| j << @Func.new("inc", [x,y]) }
- ( y.is_a? Numeric )? x[:val] += y : x[:val] += y[:val]
+ ( y.is_a? Numeric )? x[:value] += y : x[:value] += y[:value]
self
end
+
def dec(x,y=1)
@queue.each {|_,j| j << @Func.new("dec", [x,y]) }
- ( y.is_a? Numeric )? x[:val] -= y : x[:val] -= y[:val]
+ ( y.is_a? Numeric )? x[:value] -= y : x[:value] -= y[:value]
self
end
+
def cmp (x,y)
@queue.each {|_,j| j << @Func.new("cmp", [x,y]) }
- @last_cmp = ( y.is_a? Numeric )? x[:val] <=> y : x[:val] <=> y[:val]
+ @last_cmp = ( y.is_a? Numeric )? x[:value] <=> y : x[:value] <=> y[:value]
self
end
- def label (label_name)
- @queue[label_name.to_sym] = []
+ def label (label_name)
+ @queue[label_name] = []
end
- def jmp(where)
- n = @queue[where.to_sym].size - 1
+
+ def jmp(where,*args)
+ n = @queue[where].size - 1
0.upto(n) do |j|
- element = @queue[where.to_sym][j]
- send(element.name.to_sym,element.args[0],element.args[1])
+ element = @queue[where][j]
+ send(element.name,element.args[0],element.args[1])
end
end
+
+ def method_missing(name , *args)
+ name
+ end
+
end
+
def self.asm(&block)
asm =Inline_assembler.new
asm.instance_eval(&block)
- return [asm.ax[:val] , asm.bx[:val] , asm.cx[:val] , asm.dx[:val]]
+ asm.registers.map { |_,e| e[:value] }
end
-end
+
+end