-
Notifications
You must be signed in to change notification settings - Fork 0
/
conversion.lua
103 lines (77 loc) · 2.08 KB
/
conversion.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
local M = {}
M.__index = M
local UnitWrapper = require "units"
function M.new ()
local self = setmetatable ({}, M)
self.conversions = {}
return self
end
--[[
Arguments:
value, unitA, unitB
such that
there are value unitAs per unitB
e.g. (100, units.centimeters, units.meters)
or (5280, units.feet, units.miles)
Conversions are automatically inversed to produce a bidirectional graph
from / to all commensurable units
--]]
function M:addConversion (value, unitA, unitB)
--[[
Re-use existing units if possible
Units are objects, so they're harder to intern than
numbers or strings
--]]
local unitA = self:getUnit (unitA) or unitA
local unitB = self:getUnit (unitB) or unitB
local unitBConversions = self.conversions [unitB] or {}
unitBConversions [unitA] = (value * unitA) / unitB
local unitAConversions = self.conversions [unitA] or {}
unitAConversions [unitB] = unitB / (value * unitA)
self.conversions [unitB] = unitBConversions
self.conversions [unitA] = unitAConversions
end
-- Does a linear search for a unit key
function M:getUnit (wrapped)
if self.conversions [wrapped] then
return wrapped
end
for unit, _ in pairs (self.conversions) do
if UnitWrapper.unitEquality (unit, wrapped.units) then
return unit
end
end
return nil
end
--[[
Recursively finds a path from srcUnits to destUnits
closedUnits is used by recursive calls
This is NOT tailcall-optimized
--]]
function M:solveWithoutSubdividing (srcUnits, destUnits, closedUnits)
closedUnits = closedUnits or {}
local srcUnits = self:getUnit (srcUnits)
local destUnits = self:getUnit (destUnits)
closedUnits [srcUnits] = true
local srcConversions = self.conversions [srcUnits]
local baseCase = srcConversions [destUnits]
if baseCase then
return baseCase
else
for middleUnit, value in pairs (srcConversions) do
if closedUnits [middleUnit] then
-- Can't go there
else
local middleResult = self:solveWithoutSubdividing (
middleUnit, destUnits, closedUnits)
if middleResult then
return value * middleResult
end
end
end
end
return nil
end
--[[
--]]
return M