RosettaCodeData/Task/Stable-marriage-problem/Lua/stable-marriage-problem.lua

129 lines
4.2 KiB
Lua

local Person = {}
Person.__index = Person
function Person.new(inName)
local o = {
name = inName,
prefs = nil,
fiance = nil,
_candidateIndex = 1,
}
return setmetatable(o, Person)
end
function Person:indexOf(other)
for i, p in pairs(self.prefs) do
if p == other then return i end
end
return 999
end
function Person:prefers(other)
return self:indexOf(other) < self:indexOf(self.fiance)
end
function Person:nextCandidateNotYetProposedTo()
if self._candidateIndex >= #self.prefs then return nil end
local c = self.prefs[self._candidateIndex];
self._candidateIndex = self._candidateIndex + 1
return c;
end
function Person:engageTo(other)
if other.fiance then
other.fiance.fiance = nil
end
other.fiance = self
if self.fiance then
self.fiance.fiance = nil
end
self.fiance = other;
end
local function isStable(men)
local women = men[1].prefs
local stable = true
for _, guy in pairs(men) do
for _, gal in pairs(women) do
if guy:prefers(gal) and gal:prefers(guy) then
stable = false
print(guy.name .. ' and ' .. gal.name ..
' prefer each other over their partners ' ..
guy.fiance.name .. ' and ' .. gal.fiance.name)
end
end
end
return stable
end
local abe = Person.new("Abe")
local bob = Person.new("Bob")
local col = Person.new("Col")
local dan = Person.new("Dan")
local ed = Person.new("Ed")
local fred = Person.new("Fred")
local gav = Person.new("Gav")
local hal = Person.new("Hal")
local ian = Person.new("Ian")
local jon = Person.new("Jon")
local abi = Person.new("Abi")
local bea = Person.new("Bea")
local cath = Person.new("Cath")
local dee = Person.new("Dee")
local eve = Person.new("Eve")
local fay = Person.new("Fay")
local gay = Person.new("Gay")
local hope = Person.new("Hope")
local ivy = Person.new("Ivy")
local jan = Person.new("Jan")
abe.prefs = { abi, eve, cath, ivy, jan, dee, fay, bea, hope, gay }
bob.prefs = { cath, hope, abi, dee, eve, fay, bea, jan, ivy, gay }
col.prefs = { hope, eve, abi, dee, bea, fay, ivy, gay, cath, jan }
dan.prefs = { ivy, fay, dee, gay, hope, eve, jan, bea, cath, abi }
ed.prefs = { jan, dee, bea, cath, fay, eve, abi, ivy, hope, gay }
fred.prefs = { bea, abi, dee, gay, eve, ivy, cath, jan, hope, fay }
gav.prefs = { gay, eve, ivy, bea, cath, abi, dee, hope, jan, fay }
hal.prefs = { abi, eve, hope, fay, ivy, cath, jan, bea, gay, dee }
ian.prefs = { hope, cath, dee, gay, bea, abi, fay, ivy, jan, eve }
jon.prefs = { abi, fay, jan, gay, eve, bea, dee, cath, ivy, hope }
abi.prefs = { bob, fred, jon, gav, ian, abe, dan, ed, col, hal }
bea.prefs = { bob, abe, col, fred, gav, dan, ian, ed, jon, hal }
cath.prefs = { fred, bob, ed, gav, hal, col, ian, abe, dan, jon }
dee.prefs = { fred, jon, col, abe, ian, hal, gav, dan, bob, ed }
eve.prefs = { jon, hal, fred, dan, abe, gav, col, ed, ian, bob }
fay.prefs = { bob, abe, ed, ian, jon, dan, fred, gav, col, hal }
gay.prefs = { jon, gav, hal, fred, bob, abe, col, ed, dan, ian }
hope.prefs = { gav, jon, bob, abe, ian, dan, hal, ed, col, fred }
ivy.prefs = { ian, col, hal, gav, fred, bob, abe, ed, jon, dan }
jan.prefs = { ed, hal, gav, abe, bob, jon, col, ian, fred, dan }
local men = abi.prefs
local freeMenCount = #men
while freeMenCount > 0 do
for _, guy in pairs(men) do
if not guy.fiance then
local gal = guy:nextCandidateNotYetProposedTo()
if not gal.fiance then
guy:engageTo(gal)
freeMenCount = freeMenCount - 1
elseif gal:prefers(guy) then
guy:engageTo(gal)
end
end
end
end
print(' ')
for _, guy in pairs(men) do
print(guy.name .. ' is engaged to ' .. guy.fiance.name)
end
print('Stable: ', isStable(men))
print(' ')
print('Switching ' .. fred.name .. "'s & " .. jon.name .. "'s partners")
jon.fiance, fred.fiance = fred.fiance, jon.fiance
print('Stable: ', isStable(men))