Class: Dat::Solver
- Inherits:
-
Object
- Object
- Dat::Solver
- Defined in:
- lib/dat/solver.rb
Defined Under Namespace
Classes: Stop
Constant Summary collapse
- MAX_PATH_DEPTH =
5
- MAX_ALLOWABLE_DISTANCE =
2
Instance Method Summary collapse
-
#distance(start, target) ⇒ Object
Returns the distance between the start and the target.
-
#initialize(logic, opt = {}) ⇒ Solver
constructor
A new instance of Solver.
-
#path(start, target, orig_dist = nil, result = []) ⇒ Object
Try to find a path between two words simply by perturbing them.
Constructor Details
#initialize(logic, opt = {}) ⇒ Solver
Returns a new instance of Solver.
12 13 14 15 16 17 |
# File 'lib/dat/solver.rb', line 12 def initialize(logic, opt={}) @logic = logic @max_depth = opt.fetch(:max_depth, MAX_PATH_DEPTH) @max_distance = opt.fetch(:max_distance, MAX_ALLOWABLE_DISTANCE) end |
Instance Method Details
#distance(start, target) ⇒ Object
Returns the distance between the start and the target. Note this is not the minimum distance, merely a distance
21 22 23 24 |
# File 'lib/dat/solver.rb', line 21 def distance(start, target) pth = path(start, target, nil, []) pth.size if pth end |
#path(start, target, orig_dist = nil, result = []) ⇒ Object
Try to find a path between two words simply by perturbing them. This does not guarantee the shortest path, it simply attempts to find a path. The orig_dist parameter helps short circuit our effort if we ever get too far away from the goal. To be extra safe it is important to timeout this function, using an actual interval of time.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/dat/solver.rb', line 31 def path(start, target, orig_dist=nil, result=[]) # TODO need to worry about the RELATIVES of every word we have chosen. orig_dist ||= @logic.leven(start.get, target.get) p [start, target, result] # We need to stop recursion after a while so we don't end up going through # the entire dictionary raise Stop if result.size >= @max_depth # We also want to stop if we start to get too far away from the word we # are targeting. While it is possible we could eventually get to our # target, it is more unlikely the further away from it that we get. raise Stop if (@logic.leven(start.word, target.word) - orig_dist) > @max_distance result << start # short circuit if we happen to have the case where start is the target return result if start.word.upcase == target.word.upcase # The heuristic we use is to sort by the Levenshtein distance, as we # assume those words with a closer edit distance are likely closer to the # target word. # This should be parallelizable - if we do spawn a thread for each # perturbed word, other than quickly running out of threads, the # levenshtein distance calculation is a lot less necessary. @logic.perturb(start.get).sort_by { |w| @logic.leven(w.get.upcase, target.get.upcase) }.each do |word| if !result.include?(word) begin pth = path(word, target, orig_dist, result.clone) return pth if pth rescue Stop break end end end # if we get here then the was no path from start to target so we simply # return nothing which will end up being nil nil end |