This saves a step in the development setup process.
Note that the settings file is included in the toplevel `.gitignore`, so any changes on top of this one will not result in a "dirty" repo.
* add option `--width` to `format` CLI
* if width is not specified use terminal width
* if terminal width is unknown, use default (100)
This should help with testing (not so) long layouts like in #1473.
* move the VSCode extension under "swarm-game" organisation
* add Open VSX Registry to "Deploy Extension" GitHub Action
* bump version, so it gets pushed once tagged
* closes#1453
Closes#1428
Since the authoritative validation of scenario files is actually performed by virtue of `swarm` parsing them, this CI job actually exists to ensure the JSON Schema descriptions are accurate. This is important for two purposes:
* Documentation is generated from the JSON Schema files (#1436)
* JSON Schema has integration with VS Code and other IDEs
# Testing
Verified that the schema checker action does indeed work by intentionally pushing an invalid scenario file in f789f81.
- give lambdas lower precedence (9) then application (10)
- closes#1468
Before (with #1459):
```
❯ cabal run swarm -O0 -- format <(echo '\\m. case m (\\x. x + 1) (\\y. y * 2)')
\m. case m \x. x + 1 \y. y * 2
```
After:
```
❯ cabal run swarm -O0 -- format <(echo '\\m. case m (\\x. x + 1) (\\y. y * 2)')
\m. case m (\x. x + 1) (\y. y * 2)
```
- improve layout of terms:
- break lines on binds, unless it fits on one line
- lambdas go on same line, but the body _can_ go to next line
- def and let can have long body on next line (indented for def)
- parens and braces have body indented if it does not fit on line
- closes#11
Example using `--format` from #1459:
```
> cabal run swarm -O0 -- format scenarios/Challenges/_blender/patrol-clockwise.sw
def forever = \c. c; force forever c end;
def encircle = \lDir. \rDir.
turn lDir;
b <- blocked;
if b {turn rDir} {wait 1};
fwBlocked <- blocked;
if fwBlocked {turn rDir} {move}
end;
def patrolCW = force forever (force encircle right left) end;
force patrolCW
```
Closes#1462.
To demonstrate, *e.g.* temporarily remove `names.txt`. Without this patch, you will get an error message saying `The 0 is missing!`. With this patch, it now correctly says `The file is missing!`.
Blog post highlighting cool features in the newest release.
Also fix the version number in the .cabal file from 0.4 to 0.4.0.0. It's too late for the release (it always reports there is a new version available since 0.4.0.0 does not match 0.4) but oh well.
Adds a pull request template with some reminders for anyone opening a pull request. They are phrased as reminders, not a checklist, since I don't want to make this a barrier to contributions.
Closes#1429.
Closes#1430.
# Demo
scripts/play.sh -i data/scenarios/Testing/1430-built-robot-ownership.yaml
Before, pressing `F2` would show two robots: the `base` and the system-built robot.
Now, only the `base` is shown, as the built robot is properly classified as another system robot.
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
============
- New `data/worlds` subdirectory
- All `.world` files are parsed at load time and saved in a `WorldMap` which gets threaded through, similar to `EntityMap` (perhaps we should think about passing around a single record instead)
- Standard "classic" world
- Used to be `testWorld2`, defined in Haskell code; now it is defined via the DSL in `worlds/classic.world`. This should make it much easier to experiment with variations.
- We can now automatically extract entities mentioned in a world DSL term with `extractEntities`. There used to be an explicit list in `testWorld2Entities`, used to check pedagogy, generate documentation, etc., but it turns out it had (predictably) gotten out of date! This can't happen anymore.
- It is now referenced in several tutorials (backstory, farming, world101, speedruns, etc.)
- The `default` field of world descriptions is no more: one can use `dsl` to just specify a constant
- Note in `Swarm.Game.State`, `dslWF` and `arrayWF` are combined using the `Monoid` instance to create `wf`.
- `Erasable`
- It used to be the case that if some kind of default terrain + entity was specified (e.g. stone + water), any `map` would completely override the default. However, we want to move towards combining everything with a `Monoid` instance. But by default this means the default entity would show through anywhere the `map` did not specify an entity. So we need a way to explicitly "erase" an entity from a lower layer.
- If `e` is a `Semigroup`, then `Maybe e` is a `Monoid` where `Nothing` acts as an identity element. Likewise, `Erasable e` is a `Monoid` but adds two new elements: `ENothing` to be an identity, and `EErase` to be an *annihilator*. i.e. combining with `EErase` is like multiplying by zero.
- We can now specify `erase` as an entity to override entity underneath.
- There are several Haskell files with only changes related to `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
===========
- Integer, float, and Boolean literals. Note that `3` is *always* an `int`, and `3.0` is a `float`. It makes things much easier to not have to deal with `3` possibly being either `int` or `float`, though it does make things slightly more annoying for programmers.
- Standard boolean, arithmetic, and comparison operators
- `if ... then ... else ...`
- `<>` operator for combining via `Semigroup` instance
- Cell literals are enclosed in curly braces. Unlike the previous awkward world description syntax with one, two, or three-element lists denoting terrain, terrain + entity, or terrain + entity + robot, there can now be any number of elements in any order.
- `{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}`.
- It is possible to explicitly indicate the type of cell value with syntax like `{entity: tree}` or `{terrain: stone}`.
- Multiple items separated by commas is syntax sugar for combining with `<>`. e.g. `{tree, entity: boulder, stone} = {tree} <> {entity: boulder} <> {stone}`.
- Ability to refer to the `seed`
- Refer to the current `x` or `y` coordinates or the `hash` of the current coordinates
- `let`-expressions for multiple variables: `let x1 = e1, x2 = e2, ... in ...`
- `overlay [e1, e2, ...]` layers `e1` on the bottom, `e2` on top of that, etc., using the `Semigroup` instance for world functions
- `"foo"` imports the DSL term in `worlds/foo.world`
- `perlin` function to generate perlin noise
- `mask` function to mask with a condition
Changed files
===========
- `Swarm.Util`: moved the `acquire` function here and gave it a more descriptive name.
- `Swarm.Doc.Gen`: can now extract mentioned entities directly.
- `Swarm.Game.Failure`: added new failure modes
- `Swarm.Game.Scenario.Topography.WorldDescription`: get rid of `defaultTerrain` field, add `worldProg` 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 from `Swarm.Game.World`.
- `Swarm.Game.World.Gen`: moved some things here from `Swarm.Game.WorldGen` (also deleted a bunch of irrelevant code), and also added the `extractEntities` 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 like `TTerm [] (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 the `resolveCell` function, which determines how we decide what `Cell` 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 after `Swarm.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.
* use `Markdown.Document` as `entityDescription`
* add missing spaces in `chunksOf`
* fix code in `entities.yaml` (mostly types and few outdated snippets)
* add code markdown in craft tutorial
* use colours for types and entities
- closes#1408
- closes#1409
Towards #351. This is not a solution to the underlying problem, but at least it prevents the game from crashing and returns a placeholder error message instead.
Closes#1122 . General principles:
- Use `SystemFailure` as error rather than `Text` as much as possible, and use `prettyFailure` only at the very top level.
- Replace `ExceptT` with `Has (Throw SystemFailure)` constraint.
- Use `Accum (Seq SystemFailure)` constraints to accumulate warnings that should not abort computation, rather than returning a pair of a list of warnings + result.
- Use `Has (Lift IO)` constraint instead of `MonadIO`, which means using `sendIO` instead of `liftIO`.
- In general, use `runThrow` to dispatch a `Throw` constraint (results in returning an `Either`, just like `runExceptT`), and `runM` to dispatch a final `Lift IO` constraint to result in an `IO` computation.
- Use `withThrow` to adapt from one type of error to another.
The problem was that we loaded an entire directory with `mapM loadScenarioItem` which caused the entire directory to fail if any single scenario did. Now we run each individual `loadScenarioItem` call with `runExceptT` and appropriately collect up the individual failures together with any warnings from the successfully loaded scenarios.
Fixes#1380.
Closes#1379
Related: #950
Also moves "directions" types/logic into its own module.
## Demo
scripts/play.sh --scenario data/scenarios/Testing/1379-single-world-portal-reorientation.yaml --autoplay
Closes#144.
This builds upon portals support (#1356)
# Demo
scripts/play.sh --scenario data/scenarios/Testing/144-subworlds/subworld-mapped-robots.yaml --autoplay --speed 2
[![asciicast](https://asciinema.org/a/vC13dW8M1S8t2b1J4XkW80U1q.svg)](https://asciinema.org/a/vC13dW8M1S8t2b1J4XkW80U1q)
# Future work
* Augment portal definitions with an optional "relative orientation" attribute, that can turn the player around when passing through the portal (#1379)
* Specify whether portal performs instant transportation or whether `move down` is required (#1368)
Support GHC 9.6 / `base-4.18`, `mtl-2.3`, `megaparsec-9.4`, `servant-0.20`, `servant-docs-0.13`, `servant-server-0.20`, `template-haskell-2.20`, `optparse-applicative-0.18`, fix a bunch of new warnings, and update CI to test on GHC 9.6.
---------
Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <commits@restyled.io>
[Stackage LTS 21](https://www.stackage.org/blog/2023/06/announce-lts-21-nightly-ghc9.6) was just released, which is great news for us because it includes GHC 9.4.5 (GHC 9.4.4 was no longer supported by HLS) and we no longer have to rely on a specific "nightly" version. This PR updates a few things to build with LTS-21.
The biggest thing I *didn't* update was our `lsp` dependency: LTS-21 comes with `lsp-2.0` and `lsp-types-2.0`, but those apparently introduce some breaking changes and it wasn't immediately apparent to me what would need to change. I filed https://github.com/swarm-game/swarm/issues/1350 to track that issue.