mirror of
https://github.com/swarm-game/swarm.git
synced 2024-09-11 14:46:33 +03:00
parent
91a186e354
commit
1b3e622655
@ -656,10 +656,27 @@
|
|||||||
- "The 'install' command takes two arguments: the robot
|
- "The 'install' command takes two arguments: the robot
|
||||||
on which to install a device (which can be at most 1 cell away),
|
on which to install a device (which can be at most 1 cell away),
|
||||||
and the name of the device to install."
|
and the name of the device to install."
|
||||||
|
|
||||||
capabilities: [grab, give, place, install]
|
capabilities: [grab, give, place, install]
|
||||||
properties: [portable]
|
properties: [portable]
|
||||||
|
|
||||||
|
- name: fast grabber
|
||||||
|
display:
|
||||||
|
attr: device
|
||||||
|
char: '≪'
|
||||||
|
description:
|
||||||
|
- A fast grabber is an improved version of the basic grabber - not only
|
||||||
|
can it 'grab', 'place', 'give', and 'install', it can also 'swap'.
|
||||||
|
- The 'swap' command allows the robot to execute grab and place at the
|
||||||
|
same time so that the location where the robot is standing does not
|
||||||
|
become empty.
|
||||||
|
- You can use this to prevent failures where multiple robots
|
||||||
|
are trying to grab, place or scan a given location.
|
||||||
|
- In addition you retain the capability to use the 'atomic' command,
|
||||||
|
with which you can implement other commands that are safe when
|
||||||
|
run in parallel.
|
||||||
|
capabilities: [grab, swap, give, place, install, atomic]
|
||||||
|
properties: [portable]
|
||||||
|
|
||||||
- name: harvester
|
- name: harvester
|
||||||
display:
|
display:
|
||||||
attr: device
|
attr: device
|
||||||
@ -1000,7 +1017,7 @@
|
|||||||
rock to grab. However, it is actually possible for the 'grab' to
|
rock to grab. However, it is actually possible for the 'grab' to
|
||||||
fail, if some other robot B snatches the rock right after robot A sensed
|
fail, if some other robot B snatches the rock right after robot A sensed
|
||||||
it and before robot A got around to grab it on the next game tick."
|
it and before robot A got around to grab it on the next game tick."
|
||||||
- This will make robot A very sad and it will crash.
|
- "This will make robot A very sad and it will crash."
|
||||||
- "To prevent this situation, robot A can wrap the commands in 'atomic', like so:"
|
- "To prevent this situation, robot A can wrap the commands in 'atomic', like so:"
|
||||||
- |
|
- |
|
||||||
atomic (b <- ishere "rock"; if b {grab} {})
|
atomic (b <- ishere "rock"; if b {grab} {})
|
||||||
@ -1020,4 +1037,3 @@
|
|||||||
- will attempt to move, but if that fails, turn left instead.
|
- will attempt to move, but if that fails, turn left instead.
|
||||||
properties: [portable]
|
properties: [portable]
|
||||||
capabilities: [try]
|
capabilities: [try]
|
||||||
|
|
||||||
|
@ -471,6 +471,12 @@
|
|||||||
out:
|
out:
|
||||||
- [1, grabber]
|
- [1, grabber]
|
||||||
|
|
||||||
|
- in:
|
||||||
|
- [2, grabber]
|
||||||
|
- [1, rubber band]
|
||||||
|
out:
|
||||||
|
- [1, fast grabber]
|
||||||
|
|
||||||
- in:
|
- in:
|
||||||
- [4, circuit]
|
- [4, circuit]
|
||||||
- [1, iron plate]
|
- [1, iron plate]
|
||||||
|
@ -10,3 +10,4 @@
|
|||||||
555-teleport-location.yaml
|
555-teleport-location.yaml
|
||||||
562-lodestone.yaml
|
562-lodestone.yaml
|
||||||
378-objectives.yaml
|
378-objectives.yaml
|
||||||
|
684-swap.yaml
|
||||||
|
60
data/scenarios/Testing/684-swap.yaml
Normal file
60
data/scenarios/Testing/684-swap.yaml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
name: Swap in one tick
|
||||||
|
description: |
|
||||||
|
Swapping an entity should be done in one tick.
|
||||||
|
https://github.com/swarm-game/swarm/issues/684
|
||||||
|
objectives:
|
||||||
|
- condition: |
|
||||||
|
try {
|
||||||
|
as base {
|
||||||
|
l <- has "lambda";
|
||||||
|
b <- has "bitcoin";
|
||||||
|
return $ l && b
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
solution: |
|
||||||
|
swap "bitcoin"; swap "gold coin";
|
||||||
|
robots:
|
||||||
|
- name: base
|
||||||
|
loc: [0,0]
|
||||||
|
dir: [1,0]
|
||||||
|
devices:
|
||||||
|
- logger
|
||||||
|
- scanner
|
||||||
|
- grabber
|
||||||
|
- fast grabber
|
||||||
|
inventory:
|
||||||
|
- [1, gold coin]
|
||||||
|
- [1, bitcoin]
|
||||||
|
- name: watcher
|
||||||
|
loc: [0,0]
|
||||||
|
dir: [1,0]
|
||||||
|
system: true
|
||||||
|
devices:
|
||||||
|
- logger
|
||||||
|
program: |
|
||||||
|
def repeat = \c. c; repeat c end;
|
||||||
|
repeat (
|
||||||
|
d <- scan down;
|
||||||
|
case d (\_.
|
||||||
|
say "Fatal error: swap does not work atomically!"
|
||||||
|
) (\_.
|
||||||
|
return ()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
world:
|
||||||
|
default: [blank]
|
||||||
|
palette:
|
||||||
|
'┌': [stone, upper left corner]
|
||||||
|
'┐': [stone, upper right corner]
|
||||||
|
'└': [stone, lower left corner]
|
||||||
|
'┘': [stone, lower right corner]
|
||||||
|
'─': [stone, horizontal wall]
|
||||||
|
'│': [stone, vertical wall]
|
||||||
|
'λ': [grass, lambda]
|
||||||
|
upperleft: [-1, 1]
|
||||||
|
map: |
|
||||||
|
┌─┐
|
||||||
|
│λ│
|
||||||
|
└─┘
|
@ -81,6 +81,7 @@
|
|||||||
"run"
|
"run"
|
||||||
"return"
|
"return"
|
||||||
"try"
|
"try"
|
||||||
|
"swap"
|
||||||
"atomic"
|
"atomic"
|
||||||
"teleport"
|
"teleport"
|
||||||
"as"
|
"as"
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
All notable changes to the "swarm-language" extension will be documented in this file.
|
All notable changes to the "swarm-language" extension will be documented in this file.
|
||||||
|
|
||||||
|
## WIP
|
||||||
|
- [Highlighter] added `swap` command
|
||||||
|
|
||||||
## version 0.0.6
|
## version 0.0.6
|
||||||
- [Highlighter] **FIX:** the number pattern now matches properly, previously it broke everything!
|
- [Highlighter] **FIX:** the number pattern now matches properly, previously it broke everything!
|
||||||
- [Highlighter] added `listen` command
|
- [Highlighter] added `listen` command
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "keyword.other",
|
"name": "keyword.other",
|
||||||
"match": "\\b(?i)(self|parent|base|if|inl|inr|case|fst|snd|force|undefined|fail|not|format|noop|wait|selfdestruct|move|turn|grab|harvest|place|give|install|make|has|installed|count|drill|build|salvage|reprogram|say|listen|log|view|appear|create|time|whereami|blocked|scan|upload|ishere|whoami|setname|random|run|return|try|atomic|teleport|as|robotnamed|robotnumbered|knows)\\b"
|
"match": "\\b(?i)(self|parent|base|if|inl|inr|case|fst|snd|force|undefined|fail|not|format|noop|wait|selfdestruct|move|turn|grab|harvest|place|give|install|make|has|installed|count|drill|build|salvage|reprogram|say|listen|log|view|appear|create|time|whereami|blocked|scan|upload|ishere|whoami|setname|random|run|return|try|swap|atomic|teleport|as|robotnamed|robotnumbered|knows)\\b"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -774,8 +774,23 @@ execConst c vs s k = do
|
|||||||
flagRedraw
|
flagRedraw
|
||||||
return $ Out VUnit s k
|
return $ Out VUnit s k
|
||||||
_ -> badConst
|
_ -> badConst
|
||||||
Grab -> doGrab False
|
Grab -> doGrab Grab'
|
||||||
Harvest -> doGrab True
|
Harvest -> doGrab Harvest'
|
||||||
|
Swap -> case vs of
|
||||||
|
[VText name] -> do
|
||||||
|
loc <- use robotLocation
|
||||||
|
-- Make sure the robot has the thing in its inventory
|
||||||
|
e <- hasInInventoryOrFail name
|
||||||
|
-- Grab
|
||||||
|
r <- doGrab Swap'
|
||||||
|
case r of
|
||||||
|
Out {} -> do
|
||||||
|
-- Place the entity and remove it from the inventory
|
||||||
|
updateEntityAt loc (const (Just e))
|
||||||
|
robotInventory %= delete e
|
||||||
|
_ -> pure ()
|
||||||
|
return r
|
||||||
|
_ -> badConst
|
||||||
Turn -> case vs of
|
Turn -> case vs of
|
||||||
[VDir d] -> do
|
[VDir d] -> do
|
||||||
when (isCardinal d) $ hasCapabilityFor COrient (TDir d)
|
when (isCardinal d) $ hasCapabilityFor COrient (TDir d)
|
||||||
@ -785,7 +800,6 @@ execConst c vs s k = do
|
|||||||
_ -> badConst
|
_ -> badConst
|
||||||
Place -> case vs of
|
Place -> case vs of
|
||||||
[VText name] -> do
|
[VText name] -> do
|
||||||
inv <- use robotInventory
|
|
||||||
loc <- use robotLocation
|
loc <- use robotLocation
|
||||||
|
|
||||||
-- Make sure there's nothing already here
|
-- Make sure there's nothing already here
|
||||||
@ -793,12 +807,7 @@ execConst c vs s k = do
|
|||||||
nothingHere `holdsOrFail` ["There is already an entity here."]
|
nothingHere `holdsOrFail` ["There is already an entity here."]
|
||||||
|
|
||||||
-- Make sure the robot has the thing in its inventory
|
-- Make sure the robot has the thing in its inventory
|
||||||
e <-
|
e <- hasInInventoryOrFail name
|
||||||
listToMaybe (lookupByName name inv)
|
|
||||||
`isJustOrFail` ["What is", indefinite name <> "?"]
|
|
||||||
|
|
||||||
(E.lookup e inv > 0)
|
|
||||||
`holdsOrFail` ["You don't have", indefinite name, "to place."]
|
|
||||||
|
|
||||||
-- Place the entity and remove it from the inventory
|
-- Place the entity and remove it from the inventory
|
||||||
updateEntityAt loc (const (Just e))
|
updateEntityAt loc (const (Just e))
|
||||||
@ -1698,15 +1707,23 @@ execConst c vs s k = do
|
|||||||
[VInt n1, VInt n2] -> (\r -> Out (VInt r) s k) <$> evalArith c n1 n2
|
[VInt n1, VInt n2] -> (\r -> Out (VInt r) s k) <$> evalArith c n1 n2
|
||||||
_ -> badConst
|
_ -> badConst
|
||||||
|
|
||||||
|
-- Make sure the robot has the thing in its inventory
|
||||||
|
hasInInventoryOrFail :: (Has (Throw Exn) sig m, Has (State Robot) sig m) => Text -> m Entity
|
||||||
|
hasInInventoryOrFail eName = do
|
||||||
|
inv <- use robotInventory
|
||||||
|
e <-
|
||||||
|
listToMaybe (lookupByName eName inv)
|
||||||
|
`isJustOrFail` ["What is", indefinite eName <> "?"]
|
||||||
|
let cmd = T.toLower . T.pack . show $ c
|
||||||
|
(E.lookup e inv > 0)
|
||||||
|
`holdsOrFail` ["You don't have", indefinite eName, "to", cmd <> "."]
|
||||||
|
return e
|
||||||
|
|
||||||
-- The code for grab and harvest is almost identical, hence factored
|
-- The code for grab and harvest is almost identical, hence factored
|
||||||
-- out here.
|
-- out here.
|
||||||
doGrab shouldHarvest = do
|
doGrab cmd = do
|
||||||
let verb
|
let verb = verbGrabbingCmd cmd
|
||||||
| shouldHarvest = "harvest"
|
verbed = verbedGrabbingCmd cmd
|
||||||
| otherwise = "grab"
|
|
||||||
verbed
|
|
||||||
| shouldHarvest = "harvested"
|
|
||||||
| otherwise = "grabbed"
|
|
||||||
|
|
||||||
-- Ensure there is an entity here.
|
-- Ensure there is an entity here.
|
||||||
loc <- use robotLocation
|
loc <- use robotLocation
|
||||||
@ -1729,7 +1746,7 @@ execConst c vs s k = do
|
|||||||
|
|
||||||
-- Possibly regrow the entity, if it is growable and the 'harvest'
|
-- Possibly regrow the entity, if it is growable and the 'harvest'
|
||||||
-- command was used.
|
-- command was used.
|
||||||
when ((e `hasProperty` Growable) && shouldHarvest) $ do
|
when ((e `hasProperty` Growable) && cmd == Harvest') $ do
|
||||||
let GrowthTime (minT, maxT) = (e ^. entityGrowth) ? defaultGrowthTime
|
let GrowthTime (minT, maxT) = (e ^. entityGrowth) ? defaultGrowthTime
|
||||||
|
|
||||||
createdAt <- getNow
|
createdAt <- getNow
|
||||||
@ -1754,6 +1771,20 @@ execConst c vs s k = do
|
|||||||
-- Some utility functions
|
-- Some utility functions
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
data GrabbingCmd = Grab' | Harvest' | Swap' deriving (Eq, Show)
|
||||||
|
|
||||||
|
verbGrabbingCmd :: GrabbingCmd -> Text
|
||||||
|
verbGrabbingCmd = \case
|
||||||
|
Harvest' -> "harvest"
|
||||||
|
Grab' -> "grab"
|
||||||
|
Swap' -> "swap"
|
||||||
|
|
||||||
|
verbedGrabbingCmd :: GrabbingCmd -> Text
|
||||||
|
verbedGrabbingCmd = \case
|
||||||
|
Harvest' -> "harvested"
|
||||||
|
Grab' -> "grabbed"
|
||||||
|
Swap' -> "swapped"
|
||||||
|
|
||||||
-- | Give some entities from a parent robot (the robot represented by
|
-- | Give some entities from a parent robot (the robot represented by
|
||||||
-- the ambient @State Robot@ effect) to a child robot (represented
|
-- the ambient @State Robot@ effect) to a child robot (represented
|
||||||
-- by the given 'RID') as part of a 'Build' or 'Reprogram' command.
|
-- by the given 'RID') as part of a 'Build' or 'Reprogram' command.
|
||||||
|
@ -111,6 +111,8 @@ data Capability
|
|||||||
CTeleport
|
CTeleport
|
||||||
| -- | Capability to run commands atomically
|
| -- | Capability to run commands atomically
|
||||||
CAtomic
|
CAtomic
|
||||||
|
| -- | Capability to execute swap (grab and place atomically at the same time).
|
||||||
|
CSwap
|
||||||
| -- | Capabiltiy to do time-related things, like `wait` and get the
|
| -- | Capabiltiy to do time-related things, like `wait` and get the
|
||||||
-- current time.
|
-- current time.
|
||||||
CTime
|
CTime
|
||||||
@ -193,6 +195,7 @@ constCaps = \case
|
|||||||
Exp -> Just CArith
|
Exp -> Just CArith
|
||||||
Whoami -> Just CWhoami
|
Whoami -> Just CWhoami
|
||||||
Self -> Just CWhoami
|
Self -> Just CWhoami
|
||||||
|
Swap -> Just CSwap
|
||||||
Atomic -> Just CAtomic
|
Atomic -> Just CAtomic
|
||||||
Time -> Just CTime
|
Time -> Just CTime
|
||||||
Wait -> Just CTime
|
Wait -> Just CTime
|
||||||
|
@ -355,7 +355,9 @@ data Const
|
|||||||
AppF
|
AppF
|
||||||
| -- Concurrency
|
| -- Concurrency
|
||||||
|
|
||||||
-- | When executing @atomic c@, a robot will not be interrupted,
|
-- | Swap placed entity with one in inventory. Essentially atomic grab and place.
|
||||||
|
Swap
|
||||||
|
| -- | When executing @atomic c@, a robot will not be interrupted,
|
||||||
-- that is, no other robots will execute any commands while
|
-- that is, no other robots will execute any commands while
|
||||||
-- the robot is executing @c@.
|
-- the robot is executing @c@.
|
||||||
Atomic
|
Atomic
|
||||||
@ -637,6 +639,11 @@ constInfo c = case c of
|
|||||||
, "For exaple:"
|
, "For exaple:"
|
||||||
, "`f $ g $ h x = f (g (h x))`"
|
, "`f $ g $ h x = f (g (h x))`"
|
||||||
]
|
]
|
||||||
|
Swap ->
|
||||||
|
command 1 short . doc "Swap placed entity with one in inventory." $
|
||||||
|
[ "This essentially works like atomic grab and place."
|
||||||
|
, "Use this to avoid race conditions where more robots grab, scan or place in one location."
|
||||||
|
]
|
||||||
Atomic ->
|
Atomic ->
|
||||||
command 1 Intangible . doc "Execute a block of commands atomically." $
|
command 1 Intangible . doc "Execute a block of commands atomically." $
|
||||||
[ "When executing `atomic c`, a robot will not be interrupted, that is, no other robots will execute any commands while the robot is executing @c@."
|
[ "When executing `atomic c`, a robot will not be interrupted, that is, no other robots will execute any commands while the robot is executing @c@."
|
||||||
|
@ -525,6 +525,7 @@ inferConst c = case c of
|
|||||||
Format -> [tyQ| a -> text |]
|
Format -> [tyQ| a -> text |]
|
||||||
Concat -> [tyQ| text -> text -> text |]
|
Concat -> [tyQ| text -> text -> text |]
|
||||||
AppF -> [tyQ| (a -> b) -> a -> b |]
|
AppF -> [tyQ| (a -> b) -> a -> b |]
|
||||||
|
Swap -> [tyQ| text -> cmd text |]
|
||||||
Atomic -> [tyQ| cmd a -> cmd a |]
|
Atomic -> [tyQ| cmd a -> cmd a |]
|
||||||
Teleport -> [tyQ| robot -> (int * int) -> cmd () |]
|
Teleport -> [tyQ| robot -> (int * int) -> cmd () |]
|
||||||
As -> [tyQ| robot -> {cmd a} -> cmd a |]
|
As -> [tyQ| robot -> {cmd a} -> cmd a |]
|
||||||
|
@ -200,6 +200,7 @@ testScenarioSolution _ci _em =
|
|||||||
, expectFailBecause "Awaiting fix (#540)" $
|
, expectFailBecause "Awaiting fix (#540)" $
|
||||||
testSolution (Sec 10) "Testing/562-lodestone"
|
testSolution (Sec 10) "Testing/562-lodestone"
|
||||||
, testSolution Default "Testing/378-objectives"
|
, testSolution Default "Testing/378-objectives"
|
||||||
|
, testSolution Default "Testing/684-swap"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
|
Loading…
Reference in New Issue
Block a user