chore: rewrite ExamRoomRandom mapping, so it actually respects room sizes
This commit is contained in:
parent
4e76fe7e50
commit
f0a79dff65
@ -1,4 +1,5 @@
|
|||||||
{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
|
{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
|
||||||
|
{-# OPTIONS_GHC -Wwarn #-}
|
||||||
|
|
||||||
module Handler.Utils.Exam
|
module Handler.Utils.Exam
|
||||||
( fetchExamAux
|
( fetchExamAux
|
||||||
@ -264,7 +265,7 @@ examAutoOccurrence :: forall seed.
|
|||||||
-> Map ExamOccurrenceId Natural
|
-> Map ExamOccurrenceId Natural
|
||||||
-> Map UserId (User, Maybe ExamOccurrenceId)
|
-> Map UserId (User, Maybe ExamOccurrenceId)
|
||||||
-> (Maybe (ExamOccurrenceMapping ExamOccurrenceId), Map UserId (Maybe ExamOccurrenceId))
|
-> (Maybe (ExamOccurrenceMapping ExamOccurrenceId), Map UserId (Maybe ExamOccurrenceId))
|
||||||
examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences users
|
examAutoOccurrence (hash -> seed) rule config@ExamAutoOccurrenceConfig{..} occurrences users
|
||||||
| sum occurrences' < usersCount
|
| sum occurrences' < usersCount
|
||||||
|| sum occurrences' <= 0
|
|| sum occurrences' <= 0
|
||||||
|| Map.null users'
|
|| Map.null users'
|
||||||
@ -273,11 +274,39 @@ examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences
|
|||||||
= case rule of
|
= case rule of
|
||||||
ExamRoomRandom
|
ExamRoomRandom
|
||||||
-> ( Nothing
|
-> ( Nothing
|
||||||
, flip Map.mapWithKey users $ \uid (_, mOcc)
|
, Map.union (Map.map snd assignedUsers) randomlyAssignedUsers
|
||||||
-> let randomOcc = flip evalRand (mkStdGen $ hashWithSalt seed uid) $
|
|
||||||
weighted $ over _2 fromIntegral <$> occurrences''
|
|
||||||
in Just $ fromMaybe randomOcc mOcc
|
|
||||||
)
|
)
|
||||||
|
where
|
||||||
|
assignedUsers,unassignedUsers :: Map UserId (User, Maybe ExamOccurrenceId)
|
||||||
|
(assignedUsers, unassignedUsers) = Map.partition (isJust . snd) users
|
||||||
|
shuffledUsers :: [UserId]
|
||||||
|
shuffledUsers = shuffle' (Map.keys unassignedUsers) (length unassignedUsers) (mkStdGen seed)
|
||||||
|
occurrencesMap :: Map ExamOccurrenceId Natural
|
||||||
|
occurrencesMap = Map.fromList occurrences''
|
||||||
|
-- reduce available space until to excess space is left while keeping the filling ratio as equal as possible
|
||||||
|
decreaseBiggestOutlier :: Natural -> Map ExamOccurrenceId Natural -> Map ExamOccurrenceId Natural
|
||||||
|
decreaseBiggestOutlier 0 currentOccurrences = currentOccurrences
|
||||||
|
decreaseBiggestOutlier n currentOccurrences = decreaseBiggestOutlier (pred n)
|
||||||
|
$ Map.update predToPositive biggestOutlier currentOccurrences
|
||||||
|
where
|
||||||
|
currentRatios :: Map ExamOccurrenceId (Ratio Natural)
|
||||||
|
currentRatios = Map.merge Map.dropMissing Map.dropMissing (Map.zipWithMatched $ const (%)) currentOccurrences occurrencesMap
|
||||||
|
biggestOutlier :: ExamOccurrenceId
|
||||||
|
biggestOutlier = fst $ List.maximumBy (\a b -> compare (snd a) (snd b)) $ Map.toList currentRatios
|
||||||
|
extraCapacity :: Natural
|
||||||
|
extraCapacity = sum (map snd occurrences'') - fromIntegral (length unassignedUsers)
|
||||||
|
finalOccurrences :: [(ExamOccurrenceId, Natural)]
|
||||||
|
finalOccurrences = Map.toList $ decreaseBiggestOutlier extraCapacity occurrencesMap
|
||||||
|
-- fill in users in a random order
|
||||||
|
randomlyAssignedUsers :: Map UserId (Maybe ExamOccurrenceId)
|
||||||
|
randomlyAssignedUsers = Map.fromList $ fst $ foldl' addUsers ([], shuffledUsers) finalOccurrences
|
||||||
|
addUsers :: ([(UserId, Maybe ExamOccurrenceId)], [UserId])
|
||||||
|
-> (ExamOccurrenceId, Natural)
|
||||||
|
-> ([(UserId, Maybe ExamOccurrenceId)], [UserId])
|
||||||
|
addUsers (acc, userList) (roomId, roomSize) = (map (, Just roomId) newUsers ++ acc, remainingUsers)
|
||||||
|
where
|
||||||
|
newUsers, remainingUsers :: [UserId]
|
||||||
|
(newUsers, remainingUsers) = List.genericSplitAt roomSize userList
|
||||||
_ | Just (postprocess -> (resMapping, result)) <- bestOption
|
_ | Just (postprocess -> (resMapping, result)) <- bestOption
|
||||||
-> ( Just $ ExamOccurrenceMapping rule resMapping
|
-> ( Just $ ExamOccurrenceMapping rule resMapping
|
||||||
, Map.unionWith (<|>) (view _2 <$> users) result
|
, Map.unionWith (<|>) (view _2 <$> users) result
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user