mirror of
https://github.com/swarm-game/swarm.git
synced 2024-09-11 14:46:33 +03:00
Allow multiple robots in palette (#711)
- support specifying multiple robots in a cell - add a test with multiple robots revealing new rooms - add T shaped walls - closes #710
This commit is contained in:
parent
f3c92ca03d
commit
559a3450bd
@ -575,6 +575,22 @@
|
|||||||
- A lower right corner wall.
|
- A lower right corner wall.
|
||||||
properties: [unwalkable, known]
|
properties: [unwalkable, known]
|
||||||
|
|
||||||
|
- name: down and horizontal wall
|
||||||
|
display:
|
||||||
|
attr: entity
|
||||||
|
char: '┬'
|
||||||
|
description:
|
||||||
|
- A down and horizontal wall.
|
||||||
|
properties: [unwalkable, known]
|
||||||
|
|
||||||
|
- name: up and horizontal wall
|
||||||
|
display:
|
||||||
|
attr: entity
|
||||||
|
char: '┴'
|
||||||
|
description:
|
||||||
|
- A up and horizontal wall.
|
||||||
|
properties: [unwalkable, known]
|
||||||
|
|
||||||
- name: horizontal wall
|
- name: horizontal wall
|
||||||
display:
|
display:
|
||||||
attr: entity
|
attr: entity
|
||||||
|
@ -228,8 +228,9 @@ at various locations.
|
|||||||
|
|
||||||
#### Cells
|
#### Cells
|
||||||
|
|
||||||
Each cell of the world is specified by a 1-, 2-, or 3-tuple, for
|
Each cell of the world is specified by a list of terrain, optional entity
|
||||||
example, `[grass]`, `[grass, tree]`, or `[grass, null, base]`.
|
and robots present (if any). For example, `[grass]`, `[grass, tree]`,
|
||||||
|
or `[grass, null, base]`.
|
||||||
|
|
||||||
- The first (required) item specifies the terrain. Currently, valid
|
- The first (required) item specifies the terrain. Currently, valid
|
||||||
terrain values are `stone`, `dirt`, `grass`, `ice`, or `blank`.
|
terrain values are `stone`, `dirt`, `grass`, `ice`, or `blank`.
|
||||||
@ -237,9 +238,9 @@ example, `[grass]`, `[grass, tree]`, or `[grass, null, base]`.
|
|||||||
should be present in the cell. This may be a built-in entity, or a
|
should be present in the cell. This may be a built-in entity, or a
|
||||||
custom entity specified in the `entities` section. `null` may be
|
custom entity specified in the `entities` section. `null` may be
|
||||||
used to explicitly specify no entity in the cell.
|
used to explicitly specify no entity in the cell.
|
||||||
- The third item (if present) specifies the name of a robot which
|
- The third item and later (if present) specifies the names of the robots
|
||||||
should be present in the cell. This must be the name of a robot
|
which should be present in the cell. These must be names of robots
|
||||||
specified in the `robots` section. A copy of the robot will be
|
specified in the `robots` section. A copy of each robot will be
|
||||||
created at each location in the `map` where it is drawn.
|
created at each location in the `map` where it is drawn.
|
||||||
|
|
||||||
Although multiple robots may be in a single location in general,
|
Although multiple robots may be in a single location in general,
|
||||||
|
@ -13,3 +13,4 @@
|
|||||||
378-objectives.yaml
|
378-objectives.yaml
|
||||||
684-swap.yaml
|
684-swap.yaml
|
||||||
699-movement-fail
|
699-movement-fail
|
||||||
|
710-multi-robot.yaml
|
||||||
|
249
data/scenarios/Testing/710-multi-robot.yaml
Normal file
249
data/scenarios/Testing/710-multi-robot.yaml
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
name: Multiple robots in palette
|
||||||
|
description: |
|
||||||
|
Using multiple robots in palette to open new rooms.
|
||||||
|
See the lowright/upright robots in the second room.
|
||||||
|
https://github.com/swarm-game/swarm/issues/710
|
||||||
|
objectives:
|
||||||
|
- goal:
|
||||||
|
- Move to the end of the room.
|
||||||
|
condition: |
|
||||||
|
r <- robotNamed "check1";
|
||||||
|
as r {has "Win"}
|
||||||
|
- goal:
|
||||||
|
- Move to the end of the second room.
|
||||||
|
condition: |
|
||||||
|
r <- robotNamed "check2";
|
||||||
|
as r {has "Win"}
|
||||||
|
- goal:
|
||||||
|
- Move to the end of the third room.
|
||||||
|
condition: |
|
||||||
|
r <- robotNamed "check3";
|
||||||
|
as r {has "Win"}
|
||||||
|
solution: |
|
||||||
|
move;move;move; move;move;move; move;move;move;
|
||||||
|
world:
|
||||||
|
default: [blank]
|
||||||
|
palette:
|
||||||
|
'.': [blank]
|
||||||
|
# FIRST ROOM
|
||||||
|
'┌': [blank, upper left corner]
|
||||||
|
'└': [blank, lower left corner]
|
||||||
|
'─': [blank, horizontal wall]
|
||||||
|
'│': [blank, vertical wall]
|
||||||
|
'┐': [blank, upper right corner, upright0]
|
||||||
|
'┘': [blank, lower right corner, lowright0]
|
||||||
|
# SECOND ROOM
|
||||||
|
'1': [blank, vertical wall, gate1]
|
||||||
|
'-': [blank, "1", horizon]
|
||||||
|
'u': [blank, "1", upright, upright1]
|
||||||
|
'l': [blank, "1", lowright, lowright1]
|
||||||
|
'2': [blank, "1", vertice, gate2]
|
||||||
|
# THIRD ROOM
|
||||||
|
'~': [blank, "2", horizon]
|
||||||
|
'/': [blank, "2", vertice]
|
||||||
|
'U': [blank, "2", upright]
|
||||||
|
'L': [blank, "2", lowright]
|
||||||
|
upperleft: [-1, 1]
|
||||||
|
map: |
|
||||||
|
┌────┐--u~~U
|
||||||
|
│....1..2../
|
||||||
|
└────┘--l~~L
|
||||||
|
|
||||||
|
robots:
|
||||||
|
- name: base
|
||||||
|
dir: [1,0]
|
||||||
|
loc: [0,0]
|
||||||
|
devices:
|
||||||
|
- treads
|
||||||
|
- logger
|
||||||
|
- name: check1
|
||||||
|
dir: [0,0]
|
||||||
|
loc: [3,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
l <- whereami;
|
||||||
|
until (
|
||||||
|
try {
|
||||||
|
loc <- as base {whereami};
|
||||||
|
return (loc == l)
|
||||||
|
} { return false }
|
||||||
|
);
|
||||||
|
create "Win"
|
||||||
|
- name: check2
|
||||||
|
dir: [0,0]
|
||||||
|
loc: [6,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
l <- whereami;
|
||||||
|
until (
|
||||||
|
try {
|
||||||
|
loc <- as base {whereami};
|
||||||
|
return (loc == l)
|
||||||
|
} { return false }
|
||||||
|
);
|
||||||
|
create "Win"
|
||||||
|
- name: check3
|
||||||
|
dir: [0,0]
|
||||||
|
loc: [9,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
l <- whereami;
|
||||||
|
until (
|
||||||
|
try {
|
||||||
|
loc <- as base {whereami};
|
||||||
|
return (loc == l)
|
||||||
|
} { return false }
|
||||||
|
);
|
||||||
|
create "Win"
|
||||||
|
- name: horizon
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,horizontal wall]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
n <- (s <- scan down; case s (\_. fail "Fatal error: missing room number!") return);
|
||||||
|
c1 <- robotNamed ("check" ++ n);
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "horizontal wall"
|
||||||
|
- name: vertice
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,vertical wall]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
n <- (s <- scan down; case s (\_. fail "Fatal error: missing room number!") return);
|
||||||
|
c1 <- robotNamed ("check" ++ n);
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "vertical wall"
|
||||||
|
- name: upright
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,upper right corner]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
n <- (s <- scan down; case s (\_. fail "Fatal error: missing room number!") return);
|
||||||
|
c1 <- robotNamed ("check" ++ n);
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "upper right corner"
|
||||||
|
- name: lowright
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,lower right corner]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
n <- (s <- scan down; case s (\_. fail "Fatal error: missing room number!") return);
|
||||||
|
c1 <- robotNamed ("check" ++ n);
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "lower right corner"
|
||||||
|
- name: upleft
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,upper left corner]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
n <- (s <- scan down; case s (\_. fail "Fatal error: missing room number!") return);
|
||||||
|
c1 <- robotNamed ("check" ++ n);
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "upper left corner"
|
||||||
|
- name: upright0
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,down and horizontal wall]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
c1 <- robotNamed "check1";
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "down and horizontal wall"
|
||||||
|
- name: lowright0
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,up and horizontal wall]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
c1 <- robotNamed "check1";
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "up and horizontal wall"
|
||||||
|
- name: upright1
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,down and horizontal wall]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
c1 <- robotNamed "check2";
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "down and horizontal wall"
|
||||||
|
- name: lowright1
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
inventory: [[1,up and horizontal wall]]
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
c1 <- robotNamed "check2";
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
swap "up and horizontal wall"
|
||||||
|
- name: gate1
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
c1 <- robotNamed "check1";
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
grab
|
||||||
|
- name: gate2
|
||||||
|
dir: [0,0]
|
||||||
|
system: true
|
||||||
|
display:
|
||||||
|
invisible: true
|
||||||
|
program: |
|
||||||
|
def until = \c. b <- c; if b {} {until c} end;
|
||||||
|
c1 <- robotNamed "check2";
|
||||||
|
until (as c1 {has "Win"});
|
||||||
|
grab
|
||||||
|
entities:
|
||||||
|
- name: Win
|
||||||
|
display:
|
||||||
|
char: W
|
||||||
|
attr: gold
|
||||||
|
description:
|
||||||
|
- This entity signals that the objective has been met.
|
||||||
|
- name: "1"
|
||||||
|
display:
|
||||||
|
char: W
|
||||||
|
invisible: true
|
||||||
|
description:
|
||||||
|
- This entity is used to mean that the robot should check the 1st objective.
|
||||||
|
- name: "2"
|
||||||
|
display:
|
||||||
|
char: W
|
||||||
|
invisible: true
|
||||||
|
description:
|
||||||
|
- This entity is used to mean that the robot should check the 2nd objective.
|
@ -54,6 +54,7 @@ import Control.Carrier.Lift (Lift, sendIO)
|
|||||||
import Control.Carrier.Throw.Either (Throw, throwError)
|
import Control.Carrier.Throw.Either (Throw, throwError)
|
||||||
import Control.Lens hiding (from, (<.>))
|
import Control.Lens hiding (from, (<.>))
|
||||||
import Control.Monad (filterM, when)
|
import Control.Monad (filterM, when)
|
||||||
|
import Control.Monad.Extra (mapMaybeM)
|
||||||
import Data.Aeson.Key qualified as Key
|
import Data.Aeson.Key qualified as Key
|
||||||
import Data.Aeson.KeyMap (KeyMap)
|
import Data.Aeson.KeyMap (KeyMap)
|
||||||
import Data.Aeson.KeyMap qualified as KeyMap
|
import Data.Aeson.KeyMap qualified as KeyMap
|
||||||
@ -153,7 +154,7 @@ getRobot = getThing "robot" M.lookup
|
|||||||
data Cell = Cell
|
data Cell = Cell
|
||||||
{ cellTerrain :: TerrainType
|
{ cellTerrain :: TerrainType
|
||||||
, cellEntity :: Maybe Entity
|
, cellEntity :: Maybe Entity
|
||||||
, cellRobot :: Maybe TRobot
|
, cellRobots :: [TRobot]
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
@ -164,7 +165,7 @@ data Cell = Cell
|
|||||||
instance FromJSONE (EntityMap, RobotMap) Cell where
|
instance FromJSONE (EntityMap, RobotMap) Cell where
|
||||||
parseJSONE = withArrayE "tuple" $ \v -> do
|
parseJSONE = withArrayE "tuple" $ \v -> do
|
||||||
let tup = V.toList v
|
let tup = V.toList v
|
||||||
when (null tup || length tup > 3) $ fail "palette entry must have length 1, 2, or 3"
|
when (null tup) $ fail "palette entry must nonzero length (terrain, optional entity and then robots if any)"
|
||||||
|
|
||||||
terr <- liftE $ parseJSON (head tup)
|
terr <- liftE $ parseJSON (head tup)
|
||||||
|
|
||||||
@ -174,13 +175,13 @@ instance FromJSONE (EntityMap, RobotMap) Cell where
|
|||||||
meName <- liftE $ parseJSON @(Maybe Text) e
|
meName <- liftE $ parseJSON @(Maybe Text) e
|
||||||
traverse (localE fst . getEntity) meName
|
traverse (localE fst . getEntity) meName
|
||||||
|
|
||||||
rob <- case tup ^? ix 2 of
|
let name2rob r = do
|
||||||
Nothing -> return Nothing
|
mrName <- liftE $ parseJSON @(Maybe Text) r
|
||||||
Just r -> do
|
traverse (localE snd . getRobot) mrName
|
||||||
mrName <- liftE $ parseJSON @(Maybe Text) r
|
|
||||||
traverse (localE snd . getRobot) mrName
|
|
||||||
|
|
||||||
return $ Cell terr ent rob
|
robs <- mapMaybeM name2rob (drop 2 tup)
|
||||||
|
|
||||||
|
return $ Cell terr ent robs
|
||||||
|
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
-- World description
|
-- World description
|
||||||
|
@ -808,7 +808,7 @@ scenarioToGameState scenario userSeed toRun g = do
|
|||||||
-- | Take a world description, parsed from a scenario file, and turn
|
-- | Take a world description, parsed from a scenario file, and turn
|
||||||
-- it into a list of located robots and a world function.
|
-- it into a list of located robots and a world function.
|
||||||
buildWorld :: EntityMap -> WorldDescription -> ([TRobot], Seed -> WorldFun Int Entity)
|
buildWorld :: EntityMap -> WorldDescription -> ([TRobot], Seed -> WorldFun Int Entity)
|
||||||
buildWorld em (WorldDescription {..}) = (robots, first fromEnum . wf)
|
buildWorld em WorldDescription {..} = (robots, first fromEnum . wf)
|
||||||
where
|
where
|
||||||
rs = fromIntegral $ length area
|
rs = fromIntegral $ length area
|
||||||
cs = fromIntegral $ length (head area)
|
cs = fromIntegral $ length (head area)
|
||||||
@ -831,11 +831,10 @@ buildWorld em (WorldDescription {..}) = (robots, first fromEnum . wf)
|
|||||||
area
|
area
|
||||||
& traversed Control.Lens.<.> traversed %@~ (,) -- add (r,c) indices
|
& traversed Control.Lens.<.> traversed %@~ (,) -- add (r,c) indices
|
||||||
& concat
|
& concat
|
||||||
& mapMaybe
|
& concatMap
|
||||||
( \((fromIntegral -> r, fromIntegral -> c), Cell _ _ robot) ->
|
( \((fromIntegral -> r, fromIntegral -> c), Cell _ _ robotList) ->
|
||||||
robot
|
let robotWithLoc = trobotLocation ?~ W.coordsToLoc (Coords (ulr + r, ulc + c))
|
||||||
& traverse . trobotLocation
|
in map robotWithLoc robotList
|
||||||
?~ W.coordsToLoc (Coords (ulr + r, ulc + c))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
-- | Create an initial game state for a specific scenario.
|
-- | Create an initial game state for a specific scenario.
|
||||||
|
@ -206,6 +206,7 @@ testScenarioSolution _ci _em =
|
|||||||
, testSolution Default "Testing/699-movement-fail/699-move-blocked"
|
, testSolution Default "Testing/699-movement-fail/699-move-blocked"
|
||||||
, testSolution Default "Testing/699-movement-fail/699-move-liquid"
|
, testSolution Default "Testing/699-movement-fail/699-move-liquid"
|
||||||
, testSolution Default "Testing/699-movement-fail/699-teleport-blocked"
|
, testSolution Default "Testing/699-movement-fail/699-teleport-blocked"
|
||||||
|
, testSolution Default "Testing/710-multi-robot"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
|
Loading…
Reference in New Issue
Block a user