Towards #845
This is to avoid the undesirable transformation by `yq` of whitespace-preserving string fields into quoted one-line strings, described in https://github.com/swarm-game/swarm/pull/1706#discussion_r1442274007.
Command:
find data/scenarios -type f -name '*.yaml' -print0 | xargs -0 --max-args 1 sed -i -e 's/[[:blank:]]\+$//'
Towards #1415.
Potential candidate for a web-based world display
Uses [pixi.js](https://pixijs.com/).
# Demo
1. Run swarm: `scripts/play.sh -i scenarios/Fun/horton.yaml --autoplay --speed 6`
1. Visit http://localhost:5357/play.html
This is in preparation for both #1672 and #1650.
* Added some utility methods for color flattening
* The `Grid` type has a new home in `Area.hs` and now derives more instances
* `getTerrainEntityColor` is extracted from the `getDisplayColor` function
* Add a favicon to silence browser warnings
Closes#1644.
The `"recognize"` property in scenario `.yaml` files is changed from a boolean to a list of "up" directions.
The structure recognizer adds a rotated copy of each supported orientation to its automaton. Rotational symmetry is accounted for to avoid duplicate work in the recognizer.
Also in this PR:
* Add cardinal directions to the JSON schema
* Tetromino packing challenge scenario
## Demos
scripts/run-tests.sh --test-arguments '--pattern "1644-rotated"'
### Structures dialog
![Screenshot from 2023-12-10 18-47-01](https://github.com/swarm-game/swarm/assets/261693/3904b66e-dd22-455b-8b68-5913021f806a)
### Tetromino packing
scripts/play.sh -i data/scenarios/Challenges/pack-tetrominoes.yaml --autoplay
![Screenshot from 2023-12-09 23-11-00](https://github.com/swarm-game/swarm/assets/261693/0ad7c0ce-3553-4ad5-a927-82bbfdbe63d8)
This seems to help with rebuild times, since we are specifically requesting to only build the `swarm` executable and not, say, the `swarm-docs` executable.
Towards #1662
Prerequisite for #1672
To allow a robot-occupied cell to take on the underlying terrain color as the background color of its cell, the terrain color must be representable strictly as a "background". However, currently, the `dirt`, `stone`, and `grass` terrains are represented by a half-shaded **foreground** glyph upon `black` background.
Currently the ["Medium Shade" unicode character](https://www.compart.com/en/unicode/U+2592) (`▒`) is used to "blend" a somewhat bright color with a black background, resulting in a moderately dark color in the terminal for `dirt`, `stone`, and `grass`. However, these same dark colors are not reproducible in the 240-color scheme without this foreground+background blending trick; the closest approximations as a background-only or foreground-only color come out quite a bit lighter.
## Visual comparison
Using:
scripts/play.sh -i creative --seed 2 --autoplay
| Before | After |
| --- | --- |
| ![Screenshot from 2023-12-03 23-33-15](https://github.com/swarm-game/swarm/assets/261693/edeeaeac-13e0-4641-9822-773fdb20f1d4) | ![Screenshot from 2023-12-03 23-32-36](https://github.com/swarm-game/swarm/assets/261693/ae5a5b5d-aa69-4580-b7e1-85eec21b4aeb) |
## Possible approaches
So, we need to decide whether to:
1. Accept the new lighter colors
2. Choose new, alternative terrain colors that may be darker given the 240-color palette
3. Abandon support for 240 colors and assume "full" color terminals
4. Abandon efforts to passthrough terrain color as background of robot cells
Closes#1443.
Also added `-Wunused-packages` to clean up dependencies.
## Demo
This still works as usual:
stack run
Output editor keywords:
stack run swarm-docs -- editors --emacs
A continuation of #1667.
* Do not export `_viewCenter` or `_focusedRobotID`
* Move record initialization code to `Robot.hs` as `setRobotInfo`.
* `modifyViewCenter`, `unfocus`, `recalcViewCenter` now operate directly on `Robots` instead of `GameState`.
Closes#1663.
The status quo is that built-children of system robots are visible, even if the system robot is invisible. So we preserve that behavior for now, with the potential to override it at some future point. We don't yet have a definite need to make children of system robots invisible, but this PR does at least provide a mechanism to set the foreground and background of child robots (as a stopgap until #1230).
Tested with:
scripts/play.sh -i scenarios/Challenges/Ranching/beekeeping.yaml --autoplay
| Before | After |
| --- | --- |
| ![Screenshot from 2023-12-01 17-31-00](https://github.com/swarm-game/swarm/assets/261693/9a9a49cb-fee5-424d-a748-9cb3c65ffe8f) | ![Screenshot from 2023-12-01 17-35-19](https://github.com/swarm-game/swarm/assets/261693/4da17e20-8f1a-46fc-ac9c-6154ccb7d4c7) |
This is a continuation of #1652.
Most of the sub-records are bundled into `Swarm.Game.State.Substate`, but we create a `Swarm.Game.State.Robot` module just for robots.
We introduce a `zoomRobots` function so that applicable functions can operate directly on `Robots` state instead of `GameState`.
## Size comparison
### Before
| File | Lines |
| --- | --- |
| `State.hs` | 1569 |
### After
| File | Lines |
| --- | --- |
| `State.hs` | 812 |
| `Substate.hs` | 497 |
| `Robot.hs` | 395 |
| `Config.hs` | 21 |
## For follow-up PR:
- [ ] Remove exports of `_viewCenter` and `_focusedRobotID` from `Swarm.Game.State.Robot`
Both `execConst` and `stepCESK` are huge case statements. This refactor puts them in different modules.
Also many supporting functions for implementing commands in `execConst` are moved to their own modules.
Whereas `Step.hs` previously had `2931` lines, the new linecounts are:
| File | lines |
| --- | --- |
| `Step.hs` | 848 |
| `Arithmetic.hs` | 124 |
| `Const.hs` | 1687 |
| `Command.hs` | 417 |
The only tricky thing was that `execConst` is mutually recursive with `runCESK`. So to get them into different modules, I pass a wrapper of `runCESK` as an argument to `execConst`.
Previously, the logic to wrap horizontally was hand-coded, both for the player (using a dedicated monitor robot) and for ghosts (who, as system robots, implemented the teleportation themselves).
Now that we can use built-in portal functionality (#1356), no custom logic is needed to handle the teleportation. A (much-simplified) monitor robot still observes the base robot to award the hidden "World wrap" goal.
## Demo
scripts/play.sh -i data/scenarios/Challenges/hackman.yaml --autoplay --speed 6
Add another subrecord to `GameState` dedicated to robot fields. This shrinks the size of `GameState` by 8 more fields. It's getting reasonable now!
The `_viewCenter*` fields were put there too, for now, because the manually-defined `setter` of the `viewCenterRule` lens needs access to the `robotMap` field.
API docs are moved under `api/`, and the landing page for http://localhost:5357/ is now a static `index.html` page.
This paves the way for a JS-enabled web frontend demo.
Towards #1415.
## Uses
This capability could be used to quickly iterate on DSL world descriptions, e.g. when tuning noise parameters.
## Implementation notes
* For the hard-coded ANSI terminal color names, I chose RGB triples that matched my own terminal settings. This means that a rendered PNG might not exactly match one's own terminal colors.
* `Blank` terrain corresponds to a transparent pixel.
* Implemented parse-time validation of `attr` references. Previously, referencing a nonexistent `attr` by an entity would fail silently at runtime.
* Normalization: strings like `"rock"` now only exist once; the string is shared via toplevel variable definitions
* Entities and terrain have TUI-independent color definitions from which VTY Attrs are derived, but all TUI user-interface colors are defined only as VTY Attrs.
## Demos
Each pixel in the output image correponds to one world cell. To enlarge, can use [imagemagick](https://legacy.imagemagick.org/Usage/resize/#scale):
stack run -- map data/scenarios/classic.yaml --seed 0 --png -w 300 -h 200 && convert output.png -scale 800% out2.png
![out2](https://github.com/swarm-game/swarm/assets/261693/51794b63-7d78-4738-b20a-8b4f4352f006)
stack run -- map data/scenarios/Challenges/bridge-building.yaml --png && convert output.png -scale 800% out2.png
![image](https://github.com/swarm-game/swarm/assets/261693/b04895a2-eb61-4499-a122-ae8444f7e4fb)
Structure recognition already supports overlapping bounding boxes between two structures (where one of the structure templates has vacant cells). This PR adds test coverage for this.
More importantly, this PR makes sure that structures can be recognized even with non-participating entities within their bounding box. The same integration test (`1575-bounding-box-overlap.yaml`) covers this case as well.
A "non-participating entity" is an entity that is not an ingredient to any structures participating in structure recognition. Such entities are "masked out" when the world cells (i.e. the "haystack") are queried to apply the Aho-Corasick matcher to.
## Example
Given a structure defined as `boulder`s (`@`) in a backwards "L" shape, it will be recognized despite a `mountain` (`A`) within its bounding box:
![image](https://github.com/swarm-game/swarm/assets/261693/1c559a50-e9bd-4f97-87a1-20d4f964cfa9)
This is because `mountain` is not a member of any recognizable structures.
## Caveats
This PR strictly increases the situations in which valid structures may be recognized.
However, it is still the case that encroaching entities that **are** members of some structure template will thwart structure recognition. One consequence of this is that the order in which structures are completed can matter.
If some partially-built but incomplete structure lies within the bounding box of another candidate structure, the candidate structure will not be recognized as "complete" unless (1) the offending entities are removed first, or (2) the other structure is completed first.
Closes#1631
## Design
* Entities have a new property: a `Set` of textual tags.
* Two new commands are introduced:
* `HasTag` checks whether a single entity has a given tag
* `TagMembers` allows cycling through all members with a given tag
* `TagMembers` may be considered more powerful than `HasTag`, so has its own separate capability (`CTagmembers`).
* A map is computed at scenario initialization to facilitate `TagMembers` lookups.
* Tag names are highlighted in yellow in markdown.
## Demo
scripts/play.sh -i scenarios/Testing/1631-tags.yaml --autoplay
## Other changes
* Incidentally, changed `knownEntities` from a list to a `Set` so that `Set.member` can be used instead of `elem`.
Closes#1624.
Note, however, that currently (until #1623) this will not work on Windows, since I explicitly added `vty-unix` as an `extra-dep` in the `stack.yaml` file. However, I expect we will get #1623 soon and then we can remove it.
Closes#1569
## Performance
Path cache invalidation upon world modifications (i.e. entities inserted or removed) entails iterating over all of the previously-cached paths [here](https://github.com/swarm-game/swarm/pull/1595/files#r1390158411). For efficiency's sake, we avoid iterating over "all existing robots".
Any scenario that does not use the `path` command is entirely unaffected by this change.
## Demo
Previously, this demo was virtually unplayable, since when moving between widely-spaced "clusters" of flowers, an expensive A-star search was invoked at almost every tick. Now, the vast majority of moves utilize the cache, and the demo exhibits minimal stuttering (e.g. when a single A-star search is performed when moving between distant clusters).
scripts/play.sh -i scenarios/Fun/horton.yaml --autoplay --speed 7
### Event log
An event log specific to the path cache is maintained with its own ring buffer:
scripts/play.sh -i scenarios/Testing/1569-pathfinding-cache/1569-harvest-batch.yaml --autoplay
and view http://localhost:5357/paths/log
Added support for running on Windows, in command line or Powershell terminals.
Currently terminal emulators such as mintty, ConEmu, alacritty, etc are not supported.
Addresses issues #1607 and #53.
* Highlight occurrences of structures in markdown in red
* Add a new `blueprint` entity to provide `floorplan` and `structure` commands
* new `floorplan` command to get the dimensions of a structure
* structure location is southwest instead of northwest corner
* handle structures with "holes" for statically-recognized structures and when modifying interior cells post-recognition
Each of these is its own commit for reviewability's sake.