K
Kero
Here it is, my solution. From mathematical and algorithmic point of view,
you won't find anything new. However:
- One of the few times that class variables come in handy: I put the
halve/double operations into Integer and then decided to make the do-all
method Integer.solve_num_maze but the steps are done in
Integer#handle_num_maze
- Both optimizations are done in the method #enqueue
My permanent URL has header, license anouncement and large testsuite (orig
from swaits.com, unaccessible; not updated) included:
http://members.chello.nl/k.vangelder/ruby/quiz/
The code itself:
class Integer
def even?
self[0] == 0
end
def odd?
self[0] == 1
end
def halve
self / 2 if self.even?
end
def double
self * 2
end
# add inverse for add_two (we're doing DynProg)
def sub2
self - 2
end
Step = Struct.newdist, :next)
def self.source; @@source; end
def self.route; @@route; end
def self.queue; @@queue; end
def source; @@source; end
def route; @@route; end
def queue; @@queue; end
def self.solve_num_maze(source, target)
raise ArgumentError.new("Can't solve from >=0 to <0") if target < 0 and source >= 0
raise ArgumentError.new("Can't solve from >0 to 0") if target <= 0 and source > 0
@@source = source
@@route = {}
@@queue = []
@@max = [(source + 2) * 2, target * 2].max
# @@max = [source, target].max << 2 # and other attempts
queue << target
route[target] = Step.new(0, nil)
while (job = queue.shift) != source
job.handle_num_maze
end
result = [source]
step = source
while step != target
step = route[step].next
result << step
end
result
end
def enqueue(job)
# optimization 1, do not go through pending searches when effectively done
queue.clear if job == source
# optimization 2, do not look for solutions where it is not necessary
queue << job if job <= @@max
end
def handle_num_maze
if route[double].nil? or route[self].dist + 1 < route[double].dist
route[double] = Step.new(route[self].dist+1, self)
enqueue double
end
# mind the extra check on existence of #halve
if halve and (route[halve].nil? or route[self].dist + 1 < route[halve].dist)
route[halve] = Step.new(route[self].dist+1, self)
enqueue halve
end
if route[sub2].nil? or route[self].dist + 1 < route[sub2].dist
route[sub2] = Step.new(route[self].dist+1, self)
enqueue sub2
end
end
end
p Integer.solve_num_maze(ARGV[0].to_i, ARGV[1].to_i)
you won't find anything new. However:
- One of the few times that class variables come in handy: I put the
halve/double operations into Integer and then decided to make the do-all
method Integer.solve_num_maze but the steps are done in
Integer#handle_num_maze
- Both optimizations are done in the method #enqueue
My permanent URL has header, license anouncement and large testsuite (orig
from swaits.com, unaccessible; not updated) included:
http://members.chello.nl/k.vangelder/ruby/quiz/
The code itself:
class Integer
def even?
self[0] == 0
end
def odd?
self[0] == 1
end
def halve
self / 2 if self.even?
end
def double
self * 2
end
# add inverse for add_two (we're doing DynProg)
def sub2
self - 2
end
Step = Struct.newdist, :next)
def self.source; @@source; end
def self.route; @@route; end
def self.queue; @@queue; end
def source; @@source; end
def route; @@route; end
def queue; @@queue; end
def self.solve_num_maze(source, target)
raise ArgumentError.new("Can't solve from >=0 to <0") if target < 0 and source >= 0
raise ArgumentError.new("Can't solve from >0 to 0") if target <= 0 and source > 0
@@source = source
@@route = {}
@@queue = []
@@max = [(source + 2) * 2, target * 2].max
# @@max = [source, target].max << 2 # and other attempts
queue << target
route[target] = Step.new(0, nil)
while (job = queue.shift) != source
job.handle_num_maze
end
result = [source]
step = source
while step != target
step = route[step].next
result << step
end
result
end
def enqueue(job)
# optimization 1, do not go through pending searches when effectively done
queue.clear if job == source
# optimization 2, do not look for solutions where it is not necessary
queue << job if job <= @@max
end
def handle_num_maze
if route[double].nil? or route[self].dist + 1 < route[double].dist
route[double] = Step.new(route[self].dist+1, self)
enqueue double
end
# mind the extra check on existence of #halve
if halve and (route[halve].nil? or route[self].dist + 1 < route[halve].dist)
route[halve] = Step.new(route[self].dist+1, self)
enqueue halve
end
if route[sub2].nil? or route[self].dist + 1 < route[sub2].dist
route[sub2] = Step.new(route[self].dist+1, self)
enqueue sub2
end
end
end
p Integer.solve_num_maze(ARGV[0].to_i, ARGV[1].to_i)