diff --git a/data/scenarios/Testing/144-subworlds/_subworld-robots/judges.sw b/data/scenarios/Testing/144-subworlds/_subworld-robots/judges.sw new file mode 100644 index 000000000..8ca85ea5f --- /dev/null +++ b/data/scenarios/Testing/144-subworlds/_subworld-robots/judges.sw @@ -0,0 +1,52 @@ + +def getRobotNumber = \n. + r <- robotnumbered n; + if (r == self) { + return n; + } {getRobotNumber $ n + 1}; + end; + +def amLowestRecursive = \targetName. \idx. + r <- robotnumbered idx; + thisName <- as r {whoami}; + if (thisName == targetName) { + return $ r == self; + } {amLowestRecursive targetName $ idx + 1}; + end; + +/** +Iterates through robots by increasing index. +If we encounter a robot, fetched by index, +with the same name as me, but I am not that robot, +then we return false. +*/ +def amFirstOfMyName = + myName <- whoami; + amLowestRecursive myName 0; + end; + +def waitToGiveThing = \thing. + r <- meet; + case r (\_. wait 1; waitToGiveThing thing) $ \b. give b thing; + end; + +def waitToGive = + let thing = "bitcoin" in + create thing; + waitToGiveThing thing; + end; + +def waitToReceive = + noop; + end; + +def go = + myNumber <- getRobotNumber 0; + log $ "My number: " ++ format myNumber; + amFirst <- amFirstOfMyName; + log $ "Am first with this name? " ++ format amFirst; + + if amFirst {waitToReceive} {waitToGive}; + end; + +go; \ No newline at end of file diff --git a/data/scenarios/Testing/144-subworlds/_subworld-robots/solution.sw b/data/scenarios/Testing/144-subworlds/_subworld-robots/solution.sw new file mode 100644 index 000000000..b43d0fd76 --- /dev/null +++ b/data/scenarios/Testing/144-subworlds/_subworld-robots/solution.sw @@ -0,0 +1,8 @@ + +def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end; + +doN 16 move; + +r <- meet; +case r return $ \j. give j "bitcoin"; + diff --git a/data/scenarios/Testing/144-subworlds/subworld-robots.yaml b/data/scenarios/Testing/144-subworlds/subworld-robots.yaml index 8a886e710..9d317a865 100644 --- a/data/scenarios/Testing/144-subworlds/subworld-robots.yaml +++ b/data/scenarios/Testing/144-subworlds/subworld-robots.yaml @@ -1,16 +1,21 @@ version: 1 name: Subworld robots description: | - Demonstrate that system robots can be placed in any subworld -# objectives: -# - goal: -# - | -# `place` the "flower" on the white cell. -# condition: | -# j <- robotnamed "judge"; -# as j {ishere "flower"} -# solution: | -# run "scenarios/Testing/144-subworlds/_basic-subworld/solution.sw" + Demonstrate that system robots can be placed in any subworld. + + Also demonstrates tiebreaking logic for robot numbering based + on subworld. +objectives: + - goal: + - | + `give` the "bitcoin" to the robot in the "root" world. + - | + First obtain it from the robot living underground. + condition: | + j <- robotnumbered 1; + as j {has "bitcoin"} +solution: | + run "scenarios/Testing/144-subworlds/_subworld-robots/solution.sw" attrs: - name: portal_in fg: "#ff9a00" @@ -38,6 +43,7 @@ robots: dir: [1, 0] devices: - ADT calculator + - antenna - branch predictor - comparator - compass @@ -54,7 +60,9 @@ robots: system: true display: char: 'J' - invisible: true + invisible: false + program: | + run "scenarios/Testing/144-subworlds/_subworld-robots/judges.sw"; known: [flower, boulder] subworlds: - name: underground @@ -63,6 +71,7 @@ subworlds: '.': [dirt] 'f': [dirt, flower] 'b': [dirt, boulder] + 't': [grass, null, judge] 'p': cell: [dirt, telepad exit] waypoint: @@ -79,14 +88,14 @@ subworlds: upperleft: [-1, 1] map: | b..b..b..b - .p..f...P. + .p.t....P. b..b..b..b world: default: [blank] palette: '.': [grass] 'B': [grass, null, base] - 't': [ice, null, judge] + 't': [grass, null, judge] 'p': cell: [grass, telepad exit] waypoint: @@ -103,5 +112,5 @@ world: subworldName: underground map: | .......... - .p.Bt...P. + .p.B..t.P. .......... diff --git a/src/Swarm/Game/State.hs b/src/Swarm/Game/State.hs index 0411d4916..6ffed257d 100644 --- a/src/Swarm/Game/State.hs +++ b/src/Swarm/Game/State.hs @@ -1160,6 +1160,10 @@ scenarioToGameState scenario (LaunchParams (Identity userSeed) (Identity toRun)) -- 2.a. If multiple robots are specified in the map, prefer the one that -- is defined first within the Scenario file. -- 2.b. If multiple robots are instantiated from the same template, then + -- prefer the one with a lower-indexed subworld. Note that the root + -- subworld is always first. + -- 2.c. If multiple robots instantiated from the same template are in the + -- same subworld, then -- prefer the one closest to the upper-left of the screen, with higher -- rows given precedence over columns (i.e. first in row-major order). robotsByBasePrecedence = locatedRobots ++ map snd (sortOn fst genRobots) @@ -1206,16 +1210,21 @@ scenarioToGameState scenario (LaunchParams (Identity userSeed) (Identity toRun)) (maybe True (`S.member` initialCaps) . constCaps) allConst - -- TODO: We currently only utilize genRobots on the root world. - (genRobots, _wf) = buildWorld em $ NE.head $ scenario ^. scenarioWorlds + -- Subworld order as encountered in the scenario YAML file is preserved for + -- the purpose of numbering robots, other than the "root" subworld + -- guaranteed to be first. + genRobots = concat $ NE.toList $ NE.map (fst . snd) builtWorldTuples + + builtWorldTuples = NE.map (worldName &&& buildWorld em) + $ scenario ^. scenarioWorlds allSubworldsMap s = - M.fromList - . map (worldName &&& genWorld) + M.map genWorld + . M.fromList . NE.toList - $ scenario ^. scenarioWorlds + $ builtWorldTuples where - genWorld x = W.newWorld $ snd (buildWorld em x) s + genWorld x = W.newWorld $ snd x s theWinCondition = maybe diff --git a/test/integration/Main.hs b/test/integration/Main.hs index 5affd337f..23d6e2204 100644 --- a/test/integration/Main.hs +++ b/test/integration/Main.hs @@ -298,6 +298,7 @@ testScenarioSolution _ci _em = , testSolution Default "Testing/1295-density-command" , testSolution Default "Testing/1356-portals/portals-flip-and-rotate.yaml" , testSolution Default "Testing/144-subworlds/basic-subworld.yaml" + , testSolution Default "Testing/144-subworlds/subworld-robots.yaml" ] ] where