swarm-0.7.0.0: src/swarm-engine/Swarm/Game/Step/Path/Walkability.hs
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Walkability logic
module Swarm.Game.Step.Path.Walkability where
import Control.Lens
import Data.Set qualified as S
import Swarm.Game.Entity hiding (empty, lookup, singleton, union)
import Swarm.Game.Robot.Walk
import Swarm.Language.Capability
data MoveFailureMode
= -- | Can't move due to something blocking the path. Note that if
-- the robot has a path Whitelist, then the /absence/ of an entity
-- could block the path (represented by `PathBlockedBy
-- Nothing`).
PathBlockedBy (Maybe Entity)
| -- | Some liquid entity is in the path.
PathLiquid Entity
-- | Pure logic used inside of
-- 'Swarm.Game.Step.Util.checkMoveFailureUnprivileged'. Given a
-- (possibly empty) walkable entity whitelist or blacklist, and the
-- entity (or lack thereof) in the cell we are trying to move to,
-- determine whether there is some kind of movement failure.
checkUnwalkable ::
WalkabilityContext ->
Maybe Entity ->
Maybe MoveFailureMode
checkUnwalkable (WalkabilityContext _ walkExceptions) Nothing =
-- If there's no entity in the path, we are blocked only if a
-- whitelist of walkable entities is specified
case walkExceptions of
Whitelist _ -> Just $ PathBlockedBy Nothing
Blacklist _ -> Nothing
checkUnwalkable (WalkabilityContext caps walkExceptions) (Just e)
| isUnwalkableEntity =
Just $ PathBlockedBy $ Just e
-- Robots drown if they walk over liquid without the Float capability
| e `hasProperty` Liquid && CFloat `S.notMember` caps =
Just $ PathLiquid e
| otherwise = Nothing
where
eName = e ^. entityName
-- An entity blocks a robot if...
isUnwalkableEntity = case walkExceptions of
-- ...it's not one of the whitelisted entities...
Whitelist onlyWalkables -> eName `S.notMember` onlyWalkables
-- ...OR if it is inherently unwalkable, or is blacklisted.
Blacklist unwalkables -> e `hasProperty` Unwalkable || eName `S.member` unwalkables