Skip to content

Commit

Permalink
[EXPERIMENTAL] RID parameter to halt iteration in iterateRobots
Browse files Browse the repository at this point in the history
  • Loading branch information
kostmo committed Mar 11, 2024
1 parent 4d34296 commit 8b3cb93
Showing 1 changed file with 37 additions and 13 deletions.
50 changes: 37 additions & 13 deletions src/swarm-engine/Swarm/Game/Step.hs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ gameTick = do
ticked <-
use (temporal . gameStep) >>= \case
WorldTick -> do
runRobotIDs active
void $ runRobotIDs Nothing active
temporal . ticks %= addTicks 1
pure True
RobotStep ss -> singleStep ss focusedRob active
Expand Down Expand Up @@ -174,10 +174,15 @@ type HasGameStepState sig m = (Has (State GameState) sig m, Has (Lift IO) sig m,
--
-- * Every tick, every active robot shall have exactly one opportunity to run.
-- * The sequence in which robots are chosen to run is by increasing order of 'RID'.
runRobotIDs :: HasGameStepState sig m => IS.IntSet -> m ()
runRobotIDs robotNames = do
runRobotIDs ::
HasGameStepState sig m =>
-- Optional RID to stop before
Maybe RID ->
IS.IntSet ->
m IS.IntSet
runRobotIDs maybeStopBeforeRID robotNames = do
time <- use $ temporal . ticks
flip (iterateRobots time) robotNames $ \rn -> do
flip (iterateRobots maybeStopBeforeRID time) robotNames $ \rn -> do
mr <- uses (robotInfo . robotMap) (IM.lookup rn)
forM_ mr (stepOneRobot rn)
where
Expand Down Expand Up @@ -217,13 +222,27 @@ getExtraRunnableRobots time = do
-- /splitting/ the min item from rest of the queue is still an O(log N) operation,
-- and therefore is not any better than the 'minView' function from 'IntSet'.
--
-- Tail-recursive.
iterateRobots :: HasGameStepState sig m => TickNumber -> (RID -> m ()) -> IS.IntSet -> m ()
iterateRobots time f runnableBots =
forM_ (IS.minView runnableBots) $ \(thisRobotId, remainingBotIDs) -> do
f thisRobotId
augmentRunPool <- getExtraRunnableRobots time
iterateRobots time f $ augmentRunPool remainingBotIDs
-- To support the interactive debugger, we also support the capability to
-- stop before reaching a certain 'RID', in which case we return the
-- remaining 'RID's we didn't get to yet.
iterateRobots ::
HasGameStepState sig m =>
-- Optional RID to stop before
Maybe RID ->
TickNumber ->
(RID -> m ()) ->
IS.IntSet ->
m IS.IntSet
iterateRobots maybeStopBeforeRID time f runnableBots =
case IS.minView runnableBots of
Nothing -> return runnableBots
Just (thisRobotId, remainingBotIDs) ->
if maybe False (>= thisRobotId) maybeStopBeforeRID
then return runnableBots
else do
f thisRobotId
augmentRunPool <- getExtraRunnableRobots time
iterateRobots maybeStopBeforeRID time f $ augmentRunPool remainingBotIDs

-- | This is a helper function to do one robot step or run robots before/after.
--
Expand All @@ -242,7 +261,10 @@ singleStep ss focRID robotSet =
----------------------------------------------------------------------------
-- run robots from the beginning until focused robot
SBefore -> do
runRobotIDs preFoc
remainingBotsForAfterward <- runRobotIDs (Just focRID) preFoc

-- TODO: Use 'remainingBotsForAfterward'

temporal . gameStep .= RobotStep (SSingle focRID)
-- also set ticks of focused robot
steps <- use $ temporal . robotStepsPerTick
Expand Down Expand Up @@ -275,6 +297,8 @@ singleStep ss focRID robotSet =
newR <- (if focusUnchanged then stepRobot else tickRobotRec) oldR
registerUpdatedRobotState focRID newR

-- This may have introduced more robots to run!
-- Need to check 'currentTickWakeableBots' and empty it.
time <- use $ temporal . ticks
augmentRunPool <- getExtraRunnableRobots time

Expand Down Expand Up @@ -304,7 +328,7 @@ singleStep ss focRID robotSet =
(preFoc, focusedActive, postFoc) = IS.splitMember focRID robotSet

finishTickWith stepMode = do
runRobotIDs postFoc
void $ runRobotIDs Nothing postFoc
temporal . gameStep .= stepMode
temporal . ticks %= addTicks 1
return True
Expand Down

0 comments on commit 8b3cb93

Please sign in to comment.