Skip to content

Commit

Permalink
sow command
Browse files Browse the repository at this point in the history
  • Loading branch information
kostmo committed May 3, 2024
1 parent db920df commit 092ed62
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 42 deletions.
3 changes: 2 additions & 1 deletion data/scenarios/Testing/00-ORDER.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ Achievements
1747-volume-command.yaml
1777-capability-cost.yaml
1775-custom-terrain.yaml
1642-biomes.yaml
1642-biomes.yaml
1533-sow-command.yaml
73 changes: 73 additions & 0 deletions data/scenarios/Testing/1533-sow-command.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
version: 1
name: Demo sow command
description: |
Demonstrate growth restrictions.
creative: true
attrs:
- name: clay
bg: "#c2b280"
terrains:
- name: clay
attr: clay
description: |
Sandy soil
objectives:
- id: harvested
goal:
- |
`harvest` both `wheat`{=entity}.
Only one should grow back.
condition: |
as base {
c <- count "wheat";
return $ c == 2;
}
solution: |
move; harvest;
move; harvest;
move;
move; move; move; move; move;
robots:
- name: base
dir: east
devices:
- treads
- harvester
- name: observer
dir: east
system: true
entities:
- name: wheat
display:
char: 'w'
attr: gold
description:
- Grain
properties: [known, pickable, growable]
growth:
duration: [2, 4]
spread:
radius: 2
density: 0.6
biomes: [dirt, clay]
- name: seed spreader
display:
char: 's'
description:
- A handheld pouch with a manual crank to broadcast seeds evenly within a small radius
properties: [known]
known: [flower]
world:
default: [blank]
palette:
'.': [grass]
'd': [dirt]
'c': [clay]
'w': [grass, wheat, observer]
'W': [dirt, wheat]
'B': [grass, null, base]
upperleft: [-1, 1]
map: |
..dddccc......
BwWddccc......
..dddccc......
42 changes: 34 additions & 8 deletions data/schema/entity.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,44 @@
},
"growth": {
"default": null,
"type": "array",
"items": [

"oneOf": [
{
"name": "minimum",
"type": "number"
"$ref": "range.json",
"description": "For growable entities, a 2-tuple of integers specifying the minimum and maximum amount of time taken for one growth stage. The actual time for one growth stage will be chosen uniformly at random from this range; it takes two growth stages for an entity to be fully grown."
},
{
"name": "maximum",
"type": "number"
"type": "object",
"additionalProperties": false,
"properties": {
"mature": {
"default": null,
"type": "string",
"description": "The name of the entity which will be planted by the `sow` command."
},
"spread": {
"default": null,
"type": "object",
"additionalProperties": false,
"properties": {
"radius": {
"default": 1,
"type": "number",
"description": "Manhattan distance within which the entity may spread"
},
"density": {
"default": 0,
"type": "number",
"description": "Density within the range to seed"
}
}
},
"duration": {
"$ref": "range.json"
}
}
}
],
"description": "For growable entities, a 2-tuple of integers specifying the minimum and maximum amount of time taken for one growth stage. The actual time for one growth stage will be chosen uniformly at random from this range; it takes two growth stages for an entity to be fully grown."
]
},
"combustion": {
"type": "object",
Expand Down
1 change: 1 addition & 0 deletions editors/emacs/swarm-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"turn"
"grab"
"harvest"
"sow"
"ignite"
"place"
"ping"
Expand Down
2 changes: 1 addition & 1 deletion editors/vim/swarm.vim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
syn keyword Keyword def end let in require
syn keyword Builtins self parent base if inl inr case fst snd force undefined fail not format chars split charat tochar key
syn keyword Command noop wait selfdestruct move backup volume path push stride turn grab harvest ignite place ping give equip unequip make has equipped count drill use build salvage reprogram say listen log view appear create halt time scout whereami waypoint structure floorplan hastag tagmembers detect resonate density sniff chirp watch surveil heading blocked scan upload ishere isempty meet meetall whoami setname random run return try swap atomic instant installkeyhandler teleport as robotnamed robotnumbered knows
syn keyword Command noop wait selfdestruct move backup volume path push stride turn grab harvest sow ignite place ping give equip unequip make has equipped count drill use build salvage reprogram say listen log view appear create halt time scout whereami waypoint structure floorplan hastag tagmembers detect resonate density sniff chirp watch surveil heading blocked scan upload ishere isempty meet meetall whoami setname random run return try swap atomic instant installkeyhandler teleport as robotnamed robotnumbered knows
syn keyword Direction east north west south down forward left back right
syn keyword Type int text dir bool cmd void unit actor

Expand Down
2 changes: 1 addition & 1 deletion editors/vscode/syntaxes/swarm.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
},
{
"name": "keyword.other",
"match": "\\b(?i)(self|parent|base|if|inl|inr|case|fst|snd|force|undefined|fail|not|format|chars|split|charat|tochar|key|noop|wait|selfdestruct|move|backup|volume|path|push|stride|turn|grab|harvest|ignite|place|ping|give|equip|unequip|make|has|equipped|count|drill|use|build|salvage|reprogram|say|listen|log|view|appear|create|halt|time|scout|whereami|waypoint|structure|floorplan|hastag|tagmembers|detect|resonate|density|sniff|chirp|watch|surveil|heading|blocked|scan|upload|ishere|isempty|meet|meetall|whoami|setname|random|run|return|try|swap|atomic|instant|installkeyhandler|teleport|as|robotnamed|robotnumbered|knows)\\b"
"match": "\\b(?i)(self|parent|base|if|inl|inr|case|fst|snd|force|undefined|fail|not|format|chars|split|charat|tochar|key|noop|wait|selfdestruct|move|backup|volume|path|push|stride|turn|grab|harvest|sow|ignite|place|ping|give|equip|unequip|make|has|equipped|count|drill|use|build|salvage|reprogram|say|listen|log|view|appear|create|halt|time|scout|whereami|waypoint|structure|floorplan|hastag|tagmembers|detect|resonate|density|sniff|chirp|watch|surveil|heading|blocked|scan|upload|ishere|isempty|meet|meetall|whoami|setname|random|run|return|try|swap|atomic|instant|installkeyhandler|teleport|as|robotnamed|robotnumbered|knows)\\b"
}
]
},
Expand Down
24 changes: 12 additions & 12 deletions src/swarm-engine/Swarm/Game/Step/Combustion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -120,18 +120,6 @@ addCombustionBot inputEntity combustibility ts loc = do
where
Combustibility _ durationRange maybeCombustionProduct = combustibility

-- Triggers the ignition of the entity underfoot with some delay.
ignitionProgram :: Integer -> ProcessedTerm
ignitionProgram waitTime =
[tmQ|
wait $int:waitTime;
try {
ignite down;
noop;
} {};
selfdestruct
|]

-- | A system program for a "combustion robot", to burn an entity
-- after it is ignited.
--
Expand Down Expand Up @@ -228,3 +216,15 @@ addIgnitionBot ignitionDelay inputEntity ts loc =
False
emptyExceptions
ts

-- Triggers the ignition of the entity underfoot with some delay.
ignitionProgram :: Integer -> ProcessedTerm
ignitionProgram waitTime =
[tmQ|
wait $int:waitTime;
try {
ignite down;
noop;
} {};
selfdestruct
|]
67 changes: 55 additions & 12 deletions src/swarm-engine/Swarm/Game/Step/Const.hs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import Swarm.Game.Step.RobotStepState
import Swarm.Game.Step.Util
import Swarm.Game.Step.Util.Command
import Swarm.Game.Step.Util.Inspect
import Swarm.Game.Terrain (TerrainType)
import Swarm.Game.Tick
import Swarm.Game.Universe
import Swarm.Game.Value
Expand Down Expand Up @@ -304,6 +305,22 @@ execConst runChildProg c vs s k = do
_ -> badConst
Grab -> mkReturn <$> doGrab Grab' PerformRemoval
Harvest -> mkReturn <$> doGrab Harvest' PerformRemoval
Sow -> case vs of
[VText name] -> do
loc <- use robotLocation

-- Make sure there's nothing already here
nothingHere <- isNothing <$> entityAt loc
nothingHere `holdsOrFail` ["There is already an entity here."]

-- Make sure the robot has the thing in its inventory
e <- hasInInventoryOrFail name

(terrainHere, _) <- contentAt loc
doPlantSeed terrainHere loc e

return $ mkReturn ()
_ -> badConst
Ignite -> case vs of
[VDir d] -> do
Combustion.igniteCommand c d
Expand Down Expand Up @@ -1714,6 +1731,42 @@ execConst runChildProg c vs s k = do
mkReturn :: Valuable a => a -> CESK
mkReturn x = Out (asValue x) s k

doPlantSeed ::
(HasRobotStepState sig m, Has Effect.Time sig m) =>
TerrainType ->
Cosmic Location ->
Entity ->
m ()
doPlantSeed terrainHere loc e = do
when ((e `hasProperty` Growable) && isAllowedInBiome terrainHere e) $ do
let Growth maybeMaturesTo maybeSpread (GrowthTime (minT, maxT)) =
(e ^. entityGrowth) ? defaultGrowth

em <- use $ landscape . terrainAndEntities . entityMap
let seedEntity = fromMaybe e $ (`lookupEntityName` em) =<< maybeMaturesTo

createdAt <- getNow
let radius = maybe 1 spreadRadius maybeSpread
let seedlingDensity = maybe 0 spreadDensity maybeSpread

let seedlingArea = 1 + 2 * (radius * (radius + 1))
let seedlingCount = floor $ seedlingDensity * fromIntegral seedlingArea

-- Grow a new entity from a seed.
addSeedBot
seedEntity
(minT, maxT)
seedlingCount
(fromIntegral radius)
loc
createdAt
where
isAllowedInBiome terr ent =
null biomeRestrictions
|| terr `S.member` biomeRestrictions
where
biomeRestrictions = ent ^. entityBiomes

-- The code for grab and harvest is almost identical, hence factored
-- out here.
-- Optionally defer removal from the world, for the case of the Swap command.
Expand All @@ -1740,18 +1793,8 @@ execConst runChildProg c vs s k = do

-- Possibly regrow the entity, if it is growable and the 'harvest'
-- command was used.
let biomeRestrictions = e ^. entityBiomes
isAllowedInBiome =
null biomeRestrictions
|| terrainHere `S.member` biomeRestrictions

when ((e `hasProperty` Growable) && cmd == Harvest' && isAllowedInBiome) $ do
let GrowthTime (minT, maxT) = (e ^. entityGrowth) ? defaultGrowthTime

createdAt <- getNow

-- Grow a new entity from a seed.
addSeedBot e (minT, maxT) loc createdAt
when (cmd == Harvest') $
doPlantSeed terrainHere loc e

-- Add the picked up item to the robot's inventory. If the
-- entity yields something different, add that instead.
Expand Down
40 changes: 36 additions & 4 deletions src/swarm-engine/Swarm/Game/Step/Util/Command.hs
Original file line number Diff line number Diff line change
Expand Up @@ -469,12 +469,14 @@ addSeedBot ::
Has (State GameState) sig m =>
Entity ->
(Integer, Integer) ->
Integer ->
Integer ->
Cosmic Location ->
TimeSpec ->
m ()
addSeedBot e (minT, maxT) loc ts =
addSeedBot e (minT, maxT) seedlingCount seedlingRadius loc ts =
zoomRobots
. addTRobot (initMachine (seedProgram minT (maxT - minT) (e ^. entityName)) empty emptyStore)
. addTRobot (initMachine seedProg empty emptyStore)
$ mkRobot
Nothing
"seed"
Expand All @@ -492,19 +494,49 @@ addSeedBot e (minT, maxT) loc ts =
False
emptyExceptions
ts
where
seedProg = seedProgram
minT
(maxT - minT)
seedlingCount
seedlingRadius
(e ^. entityName)

-- | A system program for a "seed robot", to regrow a growable entity
-- after it is harvested.
seedProgram :: Integer -> Integer -> Text -> ProcessedTerm
seedProgram minTime randTime thing =
seedProgram ::
Integer ->
-- ^ min time
Integer ->
-- ^ rand time
Integer ->
-- ^ seedling count
Integer ->
-- ^ seedling radius
EntityName ->
-- ^ entity to place
ProcessedTerm
seedProgram minTime randTime seedlingCount seedlingRadius thing =
[tmQ|
def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;

try {
r <- random (1 + $int:randTime);
wait (r + $int:minTime);
appear "|" (inl ());
r <- random (1 + $int:randTime);
wait (r + $int:minTime);
place $str:thing;

doN $int:seedlingCount (
_robo <- build {
x <- random (1 + $int:seedlingRadius);
y <- random (1 + $int:seedlingRadius);
teleport self (x, y);
sow $str:thing;
selfdestruct;
};
);
} {};
selfdestruct
|]
Expand Down
3 changes: 3 additions & 0 deletions src/swarm-lang/Swarm/Language/Capability.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ data Capability
CGrab
| -- | Execute the 'Harvest' command
CHarvest
| -- | Execute the 'Sow' command
CSow
| -- | Execute the 'Ignite' command
CIgnite
| -- | Execute the 'Place' command
Expand Down Expand Up @@ -239,6 +241,7 @@ constCaps = \case
Turn -> Just CTurn
Grab -> Just CGrab
Harvest -> Just CHarvest
Sow -> Just CSow
Ignite -> Just CIgnite
Place -> Just CPlace
Ping -> Just CPing
Expand Down
7 changes: 7 additions & 0 deletions src/swarm-lang/Swarm/Language/Syntax.hs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ data Const
Grab
| -- | Harvest an item from the current location.
Harvest
| -- | Scatter seeds of a plant
Sow
| -- | Ignite a combustible item
Ignite
| -- | Try to place an item at the current location.
Expand Down Expand Up @@ -630,6 +632,11 @@ constInfo c = case c of
[ "Leaves behind a growing seed if the harvested item is growable."
, "Otherwise it works exactly like `grab`."
]
Sow ->
command 1 short . doc (Set.singleton $ Mutation EntityChange) "Distribute seeds for a plant at current location" $
[ "Spread plant seeds nearby."
, "The success, range, and density of child growth depends on the 'spread' attributes."
]
Ignite ->
command 1 short
. doc
Expand Down
Loading

0 comments on commit 092ed62

Please sign in to comment.