Class: WordWrapper::MinimumRaggedness
- Inherits:
-
WordWrapper
- Object
- WordWrapper
- WordWrapper::MinimumRaggedness
- Defined in:
- lib/minimum_raggedness.rb
Constant Summary
Constants inherited from WordWrapper
Infinity, OneSpaceWidth, Width
Instance Attribute Summary collapse
-
#splits ⇒ Object
Returns the value of attribute splits.
Attributes inherited from WordWrapper
Instance Method Summary collapse
- #compute_wrapping ⇒ Object
- #cost ⇒ Object
-
#cost_between(words, i, j) ⇒ Integer
Return the c.
-
#optimal_cost(words, j) ⇒ Array<Integer, Array<String>>
Use dynamic programming to computer the optimal cost of this text.
- #solution? ⇒ Boolean
- #wrap ⇒ Object
Methods inherited from WordWrapper
#illegal_words, #initialize, #line_cost, #total_cost
Constructor Details
This class inherits a constructor from WordWrapper
Instance Attribute Details
#splits ⇒ Object
Returns the value of attribute splits.
3 4 5 |
# File 'lib/minimum_raggedness.rb', line 3 def splits @splits end |
Instance Method Details
#compute_wrapping ⇒ Object
87 88 89 90 |
# File 'lib/minimum_raggedness.rb', line 87 def compute_wrapping @words = @input.split @cost, @splits = optimal_cost(@words.dup, @words.length) end |
#cost ⇒ Object
70 71 72 73 |
# File 'lib/minimum_raggedness.rb', line 70 def cost compute_wrapping unless @cost @cost end |
#cost_between(words, i, j) ⇒ Integer
Return the c
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/minimum_raggedness.rb', line 10 def cost_between(words, i, j) @c ||= {} @c[[i,j]] ||= begin # Special case for single words that are longer than @width. # Mark their cost as 0 so they get their own line without # messing up the algorithm if j == i and words[j-1].length >= @width cost = 0 else cost = @width - ((j - i) * OneSpaceWidth ) - words[i-1..j-1].inject(0){ |acc, w| acc + w.length } # 0 indexed cost = cost >= 0 ? cost**2 : Infinity end end end |
#optimal_cost(words, j) ⇒ Array<Integer, Array<String>>
Use dynamic programming to computer the optimal cost of this text. Recursively calls itself, keeping track of costs found as well as the array of splits required to give that cost (so we can actually generate the optimal text at the end).
The evaluation looks like this (o is shorthand for optimal_cost):
-- o(1, j) if c(1,j) < Inf
o(j) = -
-- min[ 1 <= k < j ] ( o(k) + c(k+1, j) ) if c(1,j) == Inf
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 |
# File 'lib/minimum_raggedness.rb', line 44 def optimal_cost(words, j) @o ||= {} @o[j] ||= begin ks = [] cost = cost_between words, 1, j if cost == Infinity and j > 1 ks = (1..j-1) candidates = {} ks.collect do |k| o = optimal_cost words, k c = cost_between words, k + 1, j # store both the chain of the child call and k candidates[c + o[0]] = [o[1], k] end if candidates.any? cost = candidates.keys.min # ks is the chain of splits for this line of recursion ks = candidates[cost][0] + [candidates[cost][1]] end end # cost of this line, chain of splits that result in this cost [cost,ks] end end |
#solution? ⇒ Boolean
92 93 94 |
# File 'lib/minimum_raggedness.rb', line 92 def solution? cost != Infinity end |
#wrap ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/minimum_raggedness.rb', line 75 def wrap compute_wrapping unless @splits prev = 0 ans = "" @splits.each do |s| ans << @words[prev..s-1].join(" ") << "\n" prev = s end ans << @words[prev..@words.length].join(" ") << "\n" ans end |