Skip to content

Commit

Permalink
[wip] work on flower count scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
byorgey committed Dec 30, 2024
2 parents a1e09da + a179756 commit e06f586
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 38 deletions.
35 changes: 35 additions & 0 deletions data/scenarios/Challenges/_flower-count/judge.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
def win =
try {
firestarter <- robotNamed "firestarter";
halt firestarter
} {};
try {
fire <- robotNamed "fire";
halt fire;
log "reprogramming...";
reprogram fire { selfdestruct }; // XXX WHY WON'T THIS WORK
log "reprogrammed";
} {};
create "gold"
end

def judgeCount : Int -> Cmd Unit = \actual.
watch down;
wait 1024;
s <- scan down;
case s
(\_. return ())
(\p.
try {
let c = (read p : Int) in
if (c == actual) { win } {}
} {}
)
end

def judge =
numFlowers <- resonate "flower" ((-58,-19),(61,20));
judgeCount numFlowers;
end;

judge
170 changes: 170 additions & 0 deletions data/scenarios/Challenges/flower-count.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
version: 1
name: Flower Count
author: Brent Yorgey
description: |
Count the flowers quickly... or else!
creative: false
objectives:
- id: count_flowers
teaser: Count the flowers!
goal:
- |
Your evil nemesis, the sadistic supervillain Dr. Nemesis, is
at it again! They have wired up some explosives to your True
Love and lit the fuse, but promised to stop it... IF you can
count all the flowers in time!
- |
Specifically, Dr. Nemesis demands that you count the
total number of flowers in the 120x40 field bounded by walls,
`print` the number on a piece of `paper`{=entity}, and place
the paper at the origin, `(0,0)`. If the number is correct,
the countdown stops and your True Love is saved. If the
number is incorrect... nothing happens, but the fuse continues
to burn!
- |
And don't even think about trying to pick any of the flowers.
condition: |
judge <- robotNamed "judge";
as judge { has "gold" }
- id: pick_flower
hidden: true
optional: true
teaser: You just don't listen, do you
goal:
- |
I told you not to pick any flowers! Now your True Love is
dead... because of YOU!
- |
Perhaps you would like to go back in time and try again.
condition: |
f <- as base { has "flower" };
judge <- robotNamed "judge";
g <- as judge { has "gold" };
return (not g && f)
- id: out_of_time
hidden: true
optional: true
teaser: Not fast enough
goal:
- |
You were not fast enough, and now your True Love is
dead... because of YOU!
- |
Perhaps you would like to go back in time and try again.
condition: |
truelove <- robotNamed "truelove";
as truelove { b <- ishere "fuse"; return (not b) }
- id: joinpoint
hidden: true
teaser: Follow instructions!
prerequisite:
logic:
and:
- count_flowers
- not: pick_flower
- not: out_of_time
condition: |
return true
- id: win
teaser: Give a flower
prerequisite: joinpoint
goal:
- |
Congratulations! You foiled the plan of evil Dr. Nemesis and
saved your True Love! The only thing left is to give your
True Love a flower!
condition: |
truelove <- robotNamed "truelove";
as truelove { has "flower" }
solution: |
run "scenarios/Challenges/_flower-count/solution.sw"
robots:
- name: base
dir: north
devices:
- solar panel
- treads
- antenna
- comparator
- ADT calculator
- workbench
- grabber
- dictionary
- lambda
- logger
- welder
- scanner
- strange loop
- typewriter
inventory: []
- name: igniter
system: true
dir: east
devices:
- logger
program: 'ignite down'
- name: judge
system: true
dir: east
devices:
- logger
program: |
run "scenarios/Challenges/_flower-count/judge.sw"
- name: truelove
system: true
display:
invisible: false
attr: red
char: ''
description: Your One True Love.
attrs:
- name: fuse
fg: '#cccccc'
bg: '#002f00'
# - name: greyborder
# fg: '#cccccc'
# bg: '#002f00'
# - name: blueborder
# fg: '#4287f5'
# bg: '#002f00'
# - name: purpleborder
# fg: '#d885ff'
# bg: '#002f00'
# - name: yg
# fg: '#ffff8f'
# bg: '#002f00'
# - name: rg
# fg: '#ff8f8f'
# bg: '#002f00'
entities:
- name: fuse
display:
attr: fuse
char: '-'
description:
- XXX fuse
properties: [combustible, known, boundary]
combustion:
ignition: 20
duration: [64, 64]
delay: 63
product: ash
known: [flower, wall, ash]
world:
dsl: |
overlay
[ if (hash % 7 == 0) then {grass, flower} else {grass}
, mask ((x == 61 || x == (-60)) && y <= 21 && y >= -20) {wall, stone}
, mask ((y == 21 || y == (-20)) && x <= 61 && x >= -60) {wall, stone}
]
upperleft: [0, 0]
offset: false
palette:
'B': [grass, null, base]
'J': [grass, erase, judge]
'.': [grass]
'-': [grass, fuse]
'L': [grass, fuse, truelove]
'I': [grass, fuse, igniter]
map: |
JB..I---------------L
28 changes: 21 additions & 7 deletions data/scenarios/Testing/1355-combustion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ solution: |
ignite forward;
turn right;
move; move; move;
ignite left;
turn right;
move;
ignite left;
Expand Down Expand Up @@ -75,6 +76,18 @@ entities:
duration: [8, 8]
product: null
properties: [known, pickable, combustible]
- name: slowfuse
display:
attr: silver
char: '~'
description:
- Reliably combustible, but burns more slowly
combustion:
ignition: 20
duration: [64, 64]
delay: 63
product: null
properties: [known, pickable, combustible]
- name: dynamite
display:
attr: red
Expand Down Expand Up @@ -103,6 +116,7 @@ world:
'b': [grass, board]
'i': [grass, cotton]
'F': [grass, fuse]
'f': [grass, slowfuse]
'd': [grass, dynamite, judge]
'.': [grass]
upperleft: [0, 0]
Expand All @@ -123,11 +137,11 @@ world:
......iiiiiiii........F...F...F...F..
iiiiiiiiiiiiiii..Ω.FFFF...FFFFF...d..
......iiiiiiii.......................
iiiiiiiiiiiii.....qqqqqqqqqqqqqqqq...
......iiiiii......qqqqqqqqqqqqqqqq...
iiiiiiiiiii.......qqqqqqqqqqqqqqqq...
..................qqqqqqqqqqqqqqqq...
..................qqqqqqqqqqqqqqqq...
..................qqqqqqqqqqqqqqqq...
..................qqqqqqqqqqqqqqqq...
iiiiiiiiiiiii..f..qqqqqqqqqqqqqqqq...
......iiiiii...f..qqqqqqqqqqqqqqqq...
iiiiiiiiiii....f..qqqqqqqqqqqqqqqq...
...............f..qqqqqqqqqqqqqqqq...
..ffff...ffff..f..qqqqqqqqqqqqqqqq...
..f..f...f..f..f..qqqqqqqqqqqqqqqq...
..f..fffff..ffff..qqqqqqqqqqqqqqqq...
..................qqqqqqqqqqqqqqqq...
9 changes: 7 additions & 2 deletions data/schema/combustion.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@
"ignition": {
"default": 0.5,
"type": "number",
"description": "Rate of ignition by a neighbor, per tick."
"description": "Rate of ignition by a neighbor. This is the rate parameter of a Poisson distribution, i.e. the expected number of times per tick that a combusting neighbor would tend to ignite this entity. Typically a number between 0 and 1, but it can be any nonnegative real number (default: 0.5)."
},
"duration": {
"type": "array",
"default": [100, 200],
"$ref": "range.json",
"description": "For combustible entities, a 2-tuple of integers specifying the minimum and maximum amount of time that the combustion shall persist."
},
"delay": {
"type": "number",
"default": 0.0,
"description": "Warmup delay, i.e. the number of ticks combustion must persist until this entity will potentially start igniting its neighbors (default: 0)."
},
"product": {
"default": "ash",
"type": ["string", "null"],
"description": "What entity, if any, is left over after combustion"
"description": "What entity, if any, is left over after combustion."
}
}
}
32 changes: 22 additions & 10 deletions src/swarm-engine/Swarm/Game/Step/Combustion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ igniteCommand c d = do
let selfCombustibility = (e ^. entityCombustion) ? defaultCombustibility
createdAt <- getNow
combustionDurationRand <- addCombustionBot e selfCombustibility createdAt loc
forM_ (getNeighborLocs loc) $ igniteNeighbor createdAt combustionDurationRand
let warmup = delay selfCombustibility
let neighborAffectDuration = max 0 (combustionDurationRand - warmup)
when (neighborAffectDuration > 0) $
forM_ (getNeighborLocs loc) $
igniteNeighbor createdAt warmup neighborAffectDuration
where
verb = "ignite"
verbed = "ignited"
Expand Down Expand Up @@ -117,7 +121,7 @@ addCombustionBot inputEntity combustibility ts loc = do
ts
return combustionDurationRand
where
Combustibility _ durationRange maybeCombustionProduct = combustibility
Combustibility _ durationRange _ maybeCombustionProduct = combustibility

-- | A system program for a "combustion robot", to burn an entity
-- after it is ignited.
Expand All @@ -141,7 +145,7 @@ addCombustionBot inputEntity combustibility ts loc = do
-- cells. This would avoid polluting the logic of the currently burning cell
-- with logic to manage probabilities of combustion propagation.
combustionProgram :: Integer -> Combustibility -> TSyntax
combustionProgram combustionDuration (Combustibility _ _ maybeCombustionProduct) =
combustionProgram combustionDuration (Combustibility _ _ _ maybeCombustionProduct) =
[tmQ|
wait $int:combustionDuration;
if ($int:invQuantity > 0) {
Expand All @@ -156,18 +160,25 @@ combustionProgram combustionDuration (Combustibility _ _ maybeCombustionProduct)
Nothing -> (0, "")
Just p -> (1, p)

-- | We treat the 'ignition' field in the 'Combustibility' record
-- as a /rate/ in a Poisson distribution.
-- Ignition of neighbors depends on that particular neighbor entity's
-- combustion /rate/, but also on the duration
-- that the current entity will burn.
-- | Possibly ignite a neighbor of a source entity that is combusting.
-- @creationTime@ is the time the source entity began to combust.
-- @warmup@ is the number of ticks of delay that the source entity
-- needs to burn before it will start affecting its neighbors;
-- @sourceDuration@ is the number of ticks that it will potentially
-- affect its neighbors.
--
-- We treat the 'ignition' field in the 'Combustibility' record as a
-- /rate/ in a Poisson distribution. Ignition of neighbors depends
-- on that particular neighbor entity's combustion /rate/, but also
-- on the @sourceDuration@ time that the current entity will burn.
igniteNeighbor ::
Has (State GameState) sig m =>
TimeSpec ->
Integer ->
Integer ->
Cosmic Location ->
m ()
igniteNeighbor creationTime sourceDuration loc = do
igniteNeighbor creationTime warmup sourceDuration loc = do
maybeEnt <- entityAt loc
forM_ maybeEnt igniteEntity
where
Expand All @@ -177,7 +188,8 @@ igniteNeighbor creationTime sourceDuration loc = do
when (probabilityOfIgnition >= threshold) $ do
ignitionDelayRand <- uniform (0, 1)
let ignitionDelay =
floor
(warmup +)
. floor
. min (fromIntegral sourceDuration)
. negate
$ log ignitionDelayRand / rate
Expand Down
2 changes: 1 addition & 1 deletion src/swarm-engine/Swarm/Game/Step/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Swarm.Game.Entity hiding (empty, lookup, singleton, union)
import Swarm.Game.Exception
import Swarm.Game.Location
import Swarm.Game.Robot
import Swarm.Game.Scenario.Topography.Modify qualified as WM
import Swarm.Game.Scenario.Topography.Structure.Recognition.Tracking qualified as SRT
import Swarm.Game.State
import Swarm.Game.State.Landscape (recognizerAutomatons)
Expand All @@ -40,7 +41,6 @@ import Swarm.Game.Step.RobotStepState
import Swarm.Game.Universe
import Swarm.Game.World qualified as W
import Swarm.Game.World.Coords
import Swarm.Game.World.Modify qualified as WM
import Swarm.Language.Capability
import Swarm.Language.Requirements.Type qualified as R
import Swarm.Language.Syntax
Expand Down
Loading

0 comments on commit e06f586

Please sign in to comment.