-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
World description DSL #1376
World description DSL #1376
Conversation
Fix up `mask`, `perlin`, `seed`, slightly better errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@byorgey I will try to take a look at the code later. I like how the DSL looks nice and clean from your description though. 👍
Could you maybe copy the DLS description from the PR notes to some README?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic! This opens up a lot of possibilities for scenario design.
Agree with @xsebek that the PR description is good and as much of it as possible should be copied into Haddocks.
Co-authored-by: Karl Ostmo <[email protected]>
Also link to a new README for the world DSL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impressive, I look forward to playing with this. 👍 🚀
🗺️ 🥳 |
This was broken by #1376. Any challenge which did *not* specify a `default` field would have had the classic world as an implicit background, but I failed to add the proper `dsl` field to specify it.
This was broken by #1376. Any challenge which did *not* specify a `default` field would have had the classic world as an implicit background, but in this case I failed to add the proper `dsl` field to specify it. I don't *think* there are any other such challenge scenarios, although to be really sure we would have to identify all the scenarios did not specify a `default` field before #1376 was merged and ensure that each of them now has an appropriate `dsl` field. Before: ![before](https://github.com/swarm-game/swarm/assets/533859/4756e889-5455-4a88-b114-ae00df79555c) After: ![after](https://github.com/swarm-game/swarm/assets/533859/9004e108-5c39-4de9-a2fe-c60e38b63ca0)
DSL for programming worlds, towards #1320 and #29 (and, indirectly, toward #50, since the world DSL should make a nice target for world saves) . Eventually this should be able to recreate all the world description/building features we have, though there is still a long way to go. But currently we can at least recreate the "classic" procedurally-generated world. I think this is a solid foundation we can merge as a first step, and then work on adding more features in subsequent PRs. Below are some notes that should help in reviewing. Note that the large number of files changed is due in large part to the elimination of the
default
field in scenario descriptions; see the "changed files" section below for an overview of the important/interesting changes.Issues split off from this one: #1394 #1395 #1396 #1397
Major changes
data/worlds
subdirectory.world
files are parsed at load time and saved in aWorldMap
which gets threaded through, similar toEntityMap
(perhaps we should think about passing around a single record instead)testWorld2
, defined in Haskell code; now it is defined via the DSL inworlds/classic.world
. This should make it much easier to experiment with variations.extractEntities
. There used to be an explicit list intestWorld2Entities
, used to check pedagogy, generate documentation, etc., but it turns out it had (predictably) gotten out of date! This can't happen anymore.default
field of world descriptions is no more: one can usedsl
to just specify a constantSwarm.Game.State
,dslWF
andarrayWF
are combined using theMonoid
instance to createwf
.Erasable
map
would completely override the default. However, we want to move towards combining everything with aMonoid
instance. But by default this means the default entity would show through anywhere themap
did not specify an entity. So we need a way to explicitly "erase" an entity from a lower layer.e
is aSemigroup
, thenMaybe e
is aMonoid
whereNothing
acts as an identity element. Likewise,Erasable e
is aMonoid
but adds two new elements:ENothing
to be an identity, andEErase
to be an annihilator. i.e. combining withEErase
is like multiplying by zero.erase
as an entity to override entity underneath.Erasable
, relating to e.g. the world editor,PCells
, etc.; I'm not 100% sure I've always done the right thing here.DSL overview
3
is always anint
, and3.0
is afloat
. It makes things much easier to not have to deal with3
possibly being eitherint
orfloat
, though it does make things slightly more annoying for programmers.if ... then ... else ...
<>
operator for combining viaSemigroup
instance{foo}
will be resolved as either terrain, an entity, or a robot, whichever is successful. So if the names are unambiguous one can just write{tree}
or{stone}
.{entity: tree}
or{terrain: stone}
.<>
. e.g.{tree, entity: boulder, stone} = {tree} <> {entity: boulder} <> {stone}
.seed
x
ory
coordinates or thehash
of the current coordinateslet
-expressions for multiple variables:let x1 = e1, x2 = e2, ... in ...
overlay [e1, e2, ...]
layerse1
on the bottom,e2
on top of that, etc., using theSemigroup
instance for world functions"foo"
imports the DSL term inworlds/foo.world
perlin
function to generate perlin noisemask
function to mask with a conditionChanged files
Swarm.Util
: moved theacquire
function here and gave it a more descriptive name.Swarm.Doc.Gen
: can now extract mentioned entities directly.Swarm.Game.Failure
: added new failure modesSwarm.Game.Scenario.Topography.WorldDescription
: get rid ofdefaultTerrain
field, addworldProg
for DSL.Swarm.Game.State
: see comment.Swarm.Game.World
: a bit of reorganization. Added a bunch of modules under this.Swarm.Game.World.Coords
: moved some code here fromSwarm.Game.World
.Swarm.Game.World.Gen
: moved some things here fromSwarm.Game.WorldGen
(also deleted a bunch of irrelevant code), and also added theextractEntities
function to get all entities mentioned by a DSL term.Swarm.Game.World.Syntax
: raw, untyped syntax for world DSL terms.Swarm.Game.World.Parse
: parser for world DSL terms. Fairly standard.Swarm.Game.World.Typecheck
: takes raw, untyped terms produced by the parser and both typechecks and elaborates them into a simpler core language. An interesting feature is that the core language is type-indexed, so that the Haskell type system is actually ensuring that our typechecker is correct; every typechecked world DSL term value has a type which is indexed by a Haskell type corresponding to the type of the underlying DSL term. For example,{entity: tree}
would have a type likeTTerm [] (World CellVall)
etc. Once terms make it through the typechecker, there cannot possibly be any bugs in the rest of the pipeline which would result in a crash, because the Haskell type system. (There could of course be semantic bugs.) Understanding exactly how the typechecker works is not too important. Of interest may be theresolveCell
function, which determines how we decide whatCell
is represented by a cell expression in curly braces.Swarm.Game.World.Abstract
: compile elaborated, typechecked world DSL terms down into an extremely simple core language with only constants and function application. This gives us very fast evaluation of world DSL terms. Understanding this module is not really necessary but there is a link to a blog post for those who are interested in how it works.Swarm.Game.World.Compile
: a further processing/compilation step afterSwarm.Game.World.Abstract
. Currently we don't actually use this, since it doesn't seem like it makes a big efficiency difference.Swarm.Game.World.Interpret
: interpreter for abstracted world DSL terms.Swarm.Game.World.Eval
: just puts together the pieces of the pipeline to evaluate a typechecked world DSL term.Swarm.Game.World.Load
: just loading world DSL terms from disk.