mirror of
https://github.com/swarm-game/swarm.git
synced 2024-08-16 18:10:23 +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.
|
||||
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
|
||||
display:
|
||||
attr: entity
|
||||
|
@ -228,8 +228,9 @@ at various locations.
|
||||
|
||||
#### Cells
|
||||
|
||||
Each cell of the world is specified by a 1-, 2-, or 3-tuple, for
|
||||
example, `[grass]`, `[grass, tree]`, or `[grass, null, base]`.
|
||||
Each cell of the world is specified by a list of terrain, optional entity
|
||||
and robots present (if any). For example, `[grass]`, `[grass, tree]`,
|
||||
or `[grass, null, base]`.
|
||||
|
||||
- The first (required) item specifies the terrain. Currently, valid
|
||||
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
|
||||
custom entity specified in the `entities` section. `null` may be
|
||||
used to explicitly specify no entity in the cell.
|
||||
- The third item (if present) specifies the name of a robot which
|
||||
should be present in the cell. This must be the name of a robot
|
||||
specified in the `robots` section. A copy of the robot will be
|
||||
- The third item and later (if present) specifies the names of the robots
|
||||
which should be present in the cell. These must be names of robots
|
||||
specified in the `robots` section. A copy of each robot will be
|
||||
created at each location in the `map` where it is drawn.
|
||||
|
||||
Although multiple robots may be in a single location in general,
|
||||
|
@ -13,3 +13,4 @@
|
||||
378-objectives.yaml
|
||||
684-swap.yaml
|
||||
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.Lens hiding (from, (<.>))
|
||||
import Control.Monad (filterM, when)
|
||||
import Control.Monad.Extra (mapMaybeM)
|
||||
import Data.Aeson.Key qualified as Key
|
||||
import Data.Aeson.KeyMap (KeyMap)
|
||||
import Data.Aeson.KeyMap qualified as KeyMap
|
||||
@ -153,7 +154,7 @@ getRobot = getThing "robot" M.lookup
|
||||
data Cell = Cell
|
||||
{ cellTerrain :: TerrainType
|
||||
, cellEntity :: Maybe Entity
|
||||
, cellRobot :: Maybe TRobot
|
||||
, cellRobots :: [TRobot]
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
|
||||
@ -164,7 +165,7 @@ data Cell = Cell
|
||||
instance FromJSONE (EntityMap, RobotMap) Cell where
|
||||
parseJSONE = withArrayE "tuple" $ \v -> do
|
||||
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)
|
||||
|
||||
@ -174,13 +175,13 @@ instance FromJSONE (EntityMap, RobotMap) Cell where
|
||||
meName <- liftE $ parseJSON @(Maybe Text) e
|
||||
traverse (localE fst . getEntity) meName
|
||||
|
||||
rob <- case tup ^? ix 2 of
|
||||
Nothing -> return Nothing
|
||||
Just r -> do
|
||||
mrName <- liftE $ parseJSON @(Maybe Text) r
|
||||
traverse (localE snd . getRobot) mrName
|
||||
let name2rob r = do
|
||||
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
|
||||
|
@ -808,7 +808,7 @@ scenarioToGameState scenario userSeed toRun g = do
|
||||
-- | Take a world description, parsed from a scenario file, and turn
|
||||
-- it into a list of located robots and a world function.
|
||||
buildWorld :: EntityMap -> WorldDescription -> ([TRobot], Seed -> WorldFun Int Entity)
|
||||
buildWorld em (WorldDescription {..}) = (robots, first fromEnum . wf)
|
||||
buildWorld em WorldDescription {..} = (robots, first fromEnum . wf)
|
||||
where
|
||||
rs = fromIntegral $ length area
|
||||
cs = fromIntegral $ length (head area)
|
||||
@ -831,11 +831,10 @@ buildWorld em (WorldDescription {..}) = (robots, first fromEnum . wf)
|
||||
area
|
||||
& traversed Control.Lens.<.> traversed %@~ (,) -- add (r,c) indices
|
||||
& concat
|
||||
& mapMaybe
|
||||
( \((fromIntegral -> r, fromIntegral -> c), Cell _ _ robot) ->
|
||||
robot
|
||||
& traverse . trobotLocation
|
||||
?~ W.coordsToLoc (Coords (ulr + r, ulc + c))
|
||||
& concatMap
|
||||
( \((fromIntegral -> r, fromIntegral -> c), Cell _ _ robotList) ->
|
||||
let robotWithLoc = trobotLocation ?~ W.coordsToLoc (Coords (ulr + r, ulc + c))
|
||||
in map robotWithLoc robotList
|
||||
)
|
||||
|
||||
-- | 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-liquid"
|
||||
, testSolution Default "Testing/699-movement-fail/699-teleport-blocked"
|
||||
, testSolution Default "Testing/710-multi-robot"
|
||||
]
|
||||
]
|
||||
where
|
||||
|
Loading…
Reference in New Issue
Block a user