-- Idee: Elke ronde begint met een nieuw paar van (ophaalcapaciteit, aflevercapaciteit)
-- Na elk bezoek moeten beide capaciteiten >= 0 en <= kamionetcapaciteit zijn
ronde :: Int -> [(String, Int)] -> [(String, Int)] -> [String]
ronde cap heen terug =
let
joined = join heen terug
in
doall cap joined
doall :: Int -> [(String, (Int, Int))] -> [String]
doall _ [] = []
doall cap deliveries =
let
(steden, remainingdeliveries) = ronde2 cap (0, cap) deliveries
in
steden ++ "depot" : doall cap remainingdeliveries
join :: [(String, Int)] -> [(String, Int)] -> [(String, (Int, Int))]
join [] [] = []
join [(s1, h1)] [] = [(s1, (h1, 0))] -- stad waar enkel geleverd moet worden
join [] [(s2, h2)] = [(s2, (0, h2))] -- stad waar enkel afgehaald moet worden
join heen@((s1, h1) : hs) terug@((s2, h2) : ts)
| s1 == s2 = (s1, (h1, h2)): join hs ts -- stad waar geleverd als opgehaald moet worden
| s1 < s2 = (s1, (h1, 0)) : join hs terug -- stad waar enkel geleverd moet worden
| s1 > s2 = (s2, (0, h2)) : join heen ts -- stad waar enkel afgehaald moet worden
ronde2 :: Int -> (Int, Int) -> [(String, (Int, Int))] -> ([String], [(String, (Int, Int))])
ronde2 _ _ [] = ([], [])
ronde2 cap (afcap, opcap) (entry@(stad, (af, op)) : xs) =
let
remafcap = afcap + af
remopcap = opcap - op
remafcapok = remafcap <= cap && remafcap >= 0
remopcapok = remopcap <= cap && remopcap >= 0
in
if remafcapok && remopcapok
then
let (a, b) = ronde2 cap (remafcap, remopcap) xs
in (stad : a, b)
else
let (a, b) = ronde2 cap (afcap, opcap) xs
in (a, entry : b)