These changes are experimental and for learning purpose so they are a bit hard to explain. But in hindsight the old algorithm didn't deal with cards moving between categories correctly. This algorithm works according to ghci testing between two decklists.
M54PYKIOETT3UT4N6HHTAENU4D5HB7MNEFEXM5CX6PJ4FTQIRAAAC
2P34LOESTKTXTUTLVASZEKZ3VEFVHBJDZJ3LLAOGKH3GECC76LCQC
3FF6XAALNQZ7AFOEBJ2WJ3ZYZTG73GWAGJPMZPJGXNUBYUK5XIPAC
NOKOPRVXR4V57S3FQGD4JZEZWN4APFH2BNPKNX7B364I23NYD36AC
DOPKLXQZP3TDISHODQNI6GZ57EYE42NG225WHSZMQ3L355YVYPNAC
2Z6NDCF6FFB7GMSSSNBDRBADERI4AQSANOVA76EECCRLUKUEECKQC
XQBYALGEDBGQIHMEI4FFDGMQCMOPE4SJLBDROYF5YVMU7H5IKV6AC
SV5ID4TDECS35D2F4XYBVEFIIVOZYCHV6BTZBS7QYTOTJRDBGCIAC
let totalFulfilled = sum . fmap (toNumber @Int) $ Compose res
when (totalFulfilled < toNumber @Int (x ^. copies)) $
resource
(x ^. Category.name)
( PositiveNumber . unsafeRefine . fromIntegral $
toNumber @Int (x ^. copies) - totalFulfilled
)
changes <- forM requested $ \x -> do
res <- ResourceQueue.take (x ^. _2)
pure $ map (uncurry (Diff.move (x ^. Category.name))) res
let totalTaken = sum . fmap (toNumber @Int) $ Compose res
moves = map (uncurry (`Diff.move` (x ^. _1))) res
deltas =
if totalTaken < toNumber @Int (x ^. _2)
then
let difference = toNumber @Int (x ^. _2) - totalTaken
in singleton $ Diff.deltaCopies difference (x ^. _1)
else mempty
go (mconcat changes ++ acc) mempty mempty
pure $ moves ++ deltas
available <- gets fst
let deltas =
Map.foldrWithKey'
(\k a xs -> Diff.deltaCopies (negate (toNumber @Int a)) k : xs)
[]
available
put (mempty, mempty)
pure (acc ++ mconcat changes ++ deltas)
go acc xs [] = do
changes <- forM xs $ \x -> fulfillRequest (x ^. copies) (x ^. Category.name)
go (acc ++ mconcat changes) mempty mempty
change 0 = acc
change n = Diff.deltaCopies n (x ^. Category.name) : acc
unless (delta == 0) $ do
if delta > 0
then
resource
(x ^. Category.name)
(PositiveNumber . unsafeRefine . fromIntegral $ delta)
else
request
(x ^. Category.name)
(PositiveNumber . unsafeRefine . abs . fromIntegral $ delta)
changes <- case compare delta 0 of
LT -> takeAvailable (PositiveNumber . unsafeRefine . fromIntegral . abs $ delta) (x ^. Category.name)
EQ -> pure acc
GT -> fulfillRequest (PositiveNumber . unsafeRefine . fromIntegral $ delta) (x ^. Category.name)
fulfillRequest count categoryname = do
requests <- ResourceQueue.fulfill count
let totalTaken = sum . fmap (toNumber @Int) $ Compose requests
when (totalTaken < toNumber @Int count) $
resource
categoryname
( PositiveNumber . unsafeRefine . fromIntegral $
toNumber @Int count - totalTaken
)
pure $ map (uncurry (Diff.move categoryname)) requests
takeAvailable count categoryname = do
available <- ResourceQueue.take count