okay here's my shot at the quiz, it's quite large for such a simple
problem, but i couldn't resist to use
:* in my code ;-)
class Integer
def even?
self % 2 == 0
end
def odd?
not even?
end
end
# solves rubyquiz #60
class Solver
def initialize(start, goal)
@start, @goal = start, goal
@visited = {}
@queue = [[@goal, []]]
@ops = []
[AddTwo, Double, Halve].each {|op| @ops <<
op.new(@start, @goal) }
end
# are we there yet?
def done_with?(temp_goal)
@start == temp_goal
end
# transforms the carried steps into a valid solution
def solution(steps)
steps.reverse.unshift @start
end
# does all the work
def solve
# there should be a better way to recover the steps
than carrying them
# around in the search tree (depth first search for
example?)
while current = @queue.shift
temp_goal, steps = *current # parallel
assignment in conditionals won't work
return solution(steps) if done_with? temp_goal
next if @visited[temp_goal] # been there, done
that
#puts "#{@start} -> #{@goal}: testing
#{temp_goal}, steps so far: #{steps.join(" ")}"
#gets
@visited[temp_goal] = true
new_steps = steps + [temp_goal]
@ops.each do |op|
@queue << [op.apply(temp_goal),
new_steps] if op.makes_sense? temp_goal
end
end
# my guess is, that there's always a solution. any
proof?
raise "no solution found"
end
# creates a new solver and attempts to solve(a,b)
def self.solve(a,b)
new(a,b).solve
end
end
# Applies a method with the argument 2
# maybe too much OO? :-)
class TwoOperation
def initialize(start, goal)
@start, @goal = start, goal
end
def apply(temp_goal)
temp_goal.send(@meth, 2)
end
def makes_sense?
false
end
end
# inverse of double
class Double < TwoOperation
def initialize(start, goal)
super
@meth = :/
end
def makes_sense?(temp_goal)
temp_goal.even?
end
end
# inverse of halve
class Halve < TwoOperation
def initialize(start, goal)
super
@meth = :* # heh a kissing smiley, ruby is soo cute
end
def makes_sense?(temp_goal)
# was (@goal < @start and temp_goal.even?) or (not
temp_goal.even?)
temp_goal.odd? or @goal < @start
end
end
# inverse of add_two
class AddTwo < TwoOperation
def initialize(start, goal)
super
@meth = :-
end
def makes_sense?(temp_goal)
temp_goal > 1
end
end
# for the testcases
def solve(a, b)
Solver.solve(a,b)
end