Commit Graph

1226 Commits

Author SHA1 Message Date
Brent Yorgey
62470f3513
Split out swarm-doc and swarm-tui sublibraries (#1834)
Split the final remaining default library into `swarm-doc` and `swarm-tui`.  Closes #1043 .
2024-05-11 02:08:49 +00:00
Karl Ostmo
5ed37d663f
structure placement order (#1833)
It is more intuitive in scenario design for "later" things to be placed "on top of" earlier things.

There were only a small number of scenarios for which placement order was relevant, so I fixed them.
2024-05-10 20:27:53 +00:00
Brent Yorgey
096816133f
Support GHC 9.8, bump upper bounds, and update CI (#1828)
Make sure Swarm builds with the most recent versions of dependencies. The only one that is still lagging is `filepath`, but `servant` doesn't support `filepath-1.5` so Swarm can't either.

The only real update needed was due to some breaking changes in `aeson-2.2`, but the necessary changes were very minor.  Also fixed a few places where GHC 9.8 is generating additional warnings.

Also update our CI: `haskell-ci` recently dropped support for `hlint`, in favor of projects defining their own standalone `hlint` workflows.
2024-05-10 14:43:41 -05:00
Karl Ostmo
46dda6cdeb
Use 'Grid' newtype in more places (#1832)
Towards #1826
2024-05-10 18:47:05 +00:00
Karl Ostmo
e59b33e7dc
reorganize code in Assembly.hs (#1829)
This does two main things to simplify the review of #1826:
* Add the `truncate` option to structure placement.  By default it shall be `true` to maintain the status quo behavior
* Extract a `validatePlacement` function to improve readability
2024-05-10 17:47:40 +00:00
Karl Ostmo
94b5e1506f
subdirectories for more scripts (#1831)
Introduces a bit more hierarchy into the `scripts` directory.
2024-05-10 17:32:23 +00:00
Karl Ostmo
d4982c838e
fix schema renderer (#1823)
Was crashing because `enum` type was not supported.

# Test
```
scripts/gen/schema-docs.sh
```

[New generated doc](ebe28c3a78/data/scenarios/_doc-fragments/SCHEMA.md (directions)) now contains "Directions" enum.
2024-05-06 01:29:16 +00:00
Brent Yorgey
a8087b725a
Recommend cabal (#1822)
Changes to documentation etc. to recommend the use of `cabal` rather than `stack`.  Closes #1820.

- [x] Update `README.md`
- [x] Update `feedback.yaml`
- [x] Update scripts in `scripts/`
- [x] Update `CONTRIBUTING.md`
- [x] Maybe HLS defaults to using Stack now? Should we create a `hie.yaml.cabal` file with `cradle: cabal:`?
    - See https://discourse.haskell.org/t/whats-the-current-status-of-hls-cradle-discovery/8254/5
    - See https://github.com/Avi-D-coder/implicit-hie
2024-05-06 00:09:33 +00:00
Brent Yorgey
0a001a6fa4
rename doc-fragments to _doc-fragments (#1821)
Recently the test suite started failing for me with an error about not finding an `00-ORDER.txt` file in `doc-fragments`.  I'm not sure why it never failed before, but the reason for the failure is clear enough: any folder under `data/scenarios` which does not start with an underscore is assumed to contain scenarios.
2024-05-05 00:36:23 +00:00
Karl Ostmo
e39255fbd3
Fix child robot privileges (#1819)
Fixes #1664
2024-05-04 16:13:32 +00:00
Karl Ostmo
db920dfa83
biomes (#1815)
Closes #1642
2024-05-03 11:31:21 +00:00
Brent Yorgey
786dea9ff2
Update recipe graph generation to take yields into account (#1814)
I noticed this when regenerating the recipe graph on the wiki and saw that `tea leaves` was sitting there with no input.  `tea leaves` are obtained by harvesting `tea plant`s (which now occur naturally in the world) but we were not taking such "yield" pairs into account when creating the graph.  This PR adds a directed edge for each entity that `yields` another.

The image is already updated on the wiki with the output from this PR:

  https://github.com/swarm-game/swarm/wiki/Recipes-cheat-sheet
2024-04-30 17:10:27 +00:00
Karl Ostmo
47390050b5
Split structure assembly into separate module (#1811)
Split the `Structure.hs` module in preparation for #1780.  This refactoring entails no functional change.

# Also included
* follow-up to #1804 to remove REPL re-exports
* reformat `swarm.cabal` for the latest version of `cabal-gild`
2024-04-29 04:33:12 +00:00
Brent Yorgey
078e8e6a07
refactor to remove swarm-tournament dep from swarm-integration (#1809)
The only reason the `swarm-integration` test had `swarm-tournament` as a dependency was because of a few validation functions in `Swarm.Web.Tournament.Validate`.  However, this seemed to me like a strange place for those validation functions to live, since they had nothing to do with running a tournament in particular, and it meant that running the integration tests required having postgresql installed even though no databases are used in the integration tests at all.

This PR moves those validation functions to two more generic places: the first function to extract text from a sequence of log messages now lives in `Swarm.Log`, and the other two functions to check for bad errors and run a `GameState` to completion now live in a new module `Swarm.Game.Step.Validate`.
2024-04-29 02:34:56 +00:00
Brent Yorgey
bf73f2acd9
Change appear command to take an optional attribute (#1807)
Also, fix a bug---it didn't work before if an appearance string of length 5 was given.

Closes #1230.

I don't know how to write an automated test for this, but you can see it working by *e.g.*:

- Start a creative game
- Execute e.g. `appear "DNESW" (inr "rock")`
- Observe that the base now looks like a rock-colored `N`
- Now do some `turn` commands (including `turn down`) and observe the appearance changing to e.g. `S` when facing south
2024-04-28 20:32:49 +00:00
Brent Yorgey
b39851d1ab
Some small updates and fixes (#1806)
A few minor updates:

- Fix formatting of code snippet in `Elmer's glue` entity description
- Fix type in conditional tutorial that referred to `robot` instead of `actor`
- Help now describes ctrl-q as "quit or restart"
- Update crash tutorial log message with hint about the static we will see if we salvage the currently viewed robot
2024-04-28 17:12:22 +00:00
Brent Yorgey
917ee5cd7f
Replace unification-fd with a custom implementation of unification (#1802)
Closes #1661; towards #154.

`unification-fd` is very powerful, and extremely fast, but it was written a long time ago and its age shows.  It was not possible to incorporate it into our effects system in a nice way, necessitating the use of concrete monad transformers in the typechecking code.  In addition it is impossible to customize, and we have been contemplating new type system features such as #153 and #154 that turn out to require hooking into the way the unification algorithm works (see https://github.com/swarm-game/swarm/issues/154#issuecomment-1822877487 for more details).

This PR thus removes the dependency on `unification-fd` and implements our own version of unification.  It is not quite as fast as `unification-fd` but I consider the slowdown acceptable in order to gain e.g. recursive types.  And of course there is also room to optimize it.

The custom `UTerm` from `unification-fd` is replaced with the standard `Free` (free monad) construction from the `free` package, and the custom `Fix` from `unification-fd` is replaced with the one from `data-fix`.

We also get rid of the `unifyCheck` function, which used to be a quick short-circuiting way to check whether two types definitely did not unify or might unify, allowing us to give better error messages more quickly.  Now, the `=:=` unification operator itself just does this.
2024-04-27 21:52:31 +00:00
Karl Ostmo
d749c5e473
Upload and parse scenarios (#1798)
Towards #1797

Hosts an online repository of scenarios, against which solutions may be submitted.  This is the foundational layer that may support more structured "tournaments", scenario ranking, or other social activity.

# Demo

## Live server

http://swarmgame.net/list-games.html

One can use the [`submit.sh`](https://github.com/swarm-game/swarm/pull/1798/files#diff-450877e3442a0ec1c5cbe964808a263d67f1e680d3aa3c3bf9ae6f51eca682fb) script and see valid uploads reflected live on the website.

## Local testing

### Automated tests

These are database-agnostic.

    scripts/run-tests.sh swarm:test:tournament-host

### Manual tests

These test database interactions.  It requires first setting up a local Postgres server.

1. Start `tournament/scripts/demo/server-native.sh` in one console
2. Run `tournament/scripts/demo/client/test-cases/local/good-submit.sh` in another

# Features

* Upload and validates scenarios
* Download scenarios with solution redacted
* Submit, validate, execute, and score solutions

# Key components

* Servant server
* Hosted on AWS in a Docker container
* Stores to a Postgres database in Amazon RDS
* Shares some code with the integration tests for evaluating scenarios and solutions

The production database uses IAM to manage logins.  The web app uses the AWS API to fetch a "token" which can be used to log in instead of a password.  This avoids having to store a password on the server.

# TODO
- [ ] User authentication (GitHub OpenID?)
2024-04-25 20:11:11 +00:00
Karl Ostmo
f5ecd3fa53
Capability exercise cost (#1777)
Closes #1684
Closes #1262

# Demo

A simple "puzzle" that makes use of consumables:

    scripts/play.sh -i data/scenarios/Testing/1777-capability-cost.yaml --autoplay

Demo of enabled commands and costs display in left pane:

    scripts/play.sh -i data/scenarios/Testing/1262-display-device-commands.yaml

![Screenshot from 2024-03-01 22-39-12](https://github.com/swarm-game/swarm/assets/261693/03fc0e4f-d219-4aa1-8775-cb5112eb0b90)


# In this PR

* Supports specifying capabilities both as plain lists and as maps from capabilities to ingredients in YAML
* JSON Schema support for both capability specification styles
* New integration test
* Removed redundant `tshow` implementation from `Swarm.Doc.Util`

# Entity lookup approaches

The cost of exercising a capability in terms of "ingredients" is specified by the `_entityCapabilities` field within an `Entity` definition.  Each ingredient itself is an entity, specified by name.
For many purposes, having ingredients just of type `EntityName` is sufficient.  But for `Swarm.Game.Recipe.findLacking` in particular, the ingredients list must be actual `Entity` objects, not just names of entities.  So at some point the names need to be looked up in the global entity map to be promoted to `Entity` objects.

The full list of entities is not available at `Entity` parse time to look up an ingredient entity by name, so we cannot store ingredients lists of type `(Count, Entity)` within a parent `Entity` object.

Approaches considered were:

* Store a copy of the `entityMap` in `RobotR`, for use by the `equippedDevices` lens
* Introduce a type parameter to `Entity` representing a "parse phase"
* **Allow a redundant "entity lookup" (and validation) at command execution time**

## Store `entityMap` in `RobotR`

One approach explored was to add a field to `RobotR`:
```
  , _globalEntityMap :: EntityMap
```

This allowed the `equippedDevices` lens implementation to promote the `EntityName`s to `Entity`s when setting the value of the `_robotCapabilities` field.  However, it was rather invasive as it entailed threading the `EntityMap` through many new code paths.

## `Entity` type parameter

Currently, `Entity` has a field:
```
_entityCapabilities :: SingleEntityCapabilities EntityName
```

This would entail a huge refactoring, with:
```
data Entity e = Entity
  ...
  , _entityCapabilities :: SingleEntityCapabilities e
```

At initial parse time we would obtain a list of `Entity EntityName`, but somewhere later during `Scenario` parse time, we can do another pass to obtain `Entity Entity` objects.

This would at least have the advantage of doing the entity lookup/validation on ingredient lists in exactly one place, at parse time.

## Defer `EntityName -> Entity` promotion to command execution time

This is what is implemented in this PR.  The global set of capability costs is validated at scenario parse time.  But it is also redundantly validated in the `payExerciseCost` function, which is not ideal.
2024-04-25 19:39:54 +00:00
Karl Ostmo
62375ebf2d
Refine unit test dependencies (#1804)
This is a random refactoring that does two things:

* Improves speed of `scripts/gen/render-sublibrary-dependencies.sh` script
* Refine imports of the `TestModel.hs` (renamed to `TestRepl.hs`) unit test

It appears that the only reason that the `swarm-unit` test suite imports the entire `swarm` sublibrary (hence the `brick` package), is due to `TestRepl`, which (now) imports `Swarm.TUI.Model.Repl`.  Perhaps it would make sense to separate these at some point?
2024-04-25 19:20:31 +00:00
Karl Ostmo
a739b142f3
refactoring towards tournament server (#1801)
Prerequisite to #1798 

## Changes

* Pass the final `TickNumber` count as a member of `Won` constructor so that it can be used in scoring submitted solutions
* Extract a helper function `codeMetricsFromSyntax` that can be reused by tournament server
* `ToJSON` instance for `ScenarioMetadata`
* New script `list-sublibraries.sh` to list the sublibraries defined in a package
2024-04-22 18:55:06 +00:00
Karl Ostmo
fd88a4b31a
organize scripts with subfolders (#1800)
There is getting to be a lot of files in the `scripts/` dir.  Add a layer of directories for organization.
2024-04-11 02:20:45 +00:00
Karl Ostmo
326305653d
Refactor hierarchy of state inputs (#1799)
Towards #1797

Combines `TerrainEntityMaps` and `WorldMap` into a single record, `ScenarioInputs`.

Establishes a Matroska-style arrangement of records to represent various scopes of state, eliminating several redundant fields.
2024-04-10 19:02:51 +00:00
Karl Ostmo
6813c3bfd5
direction rendering (#1793)
Code consolidation.
2024-03-16 14:29:48 +00:00
Karl Ostmo
55271c0003
refactor word search using structure recognition (#1792)
Makes use of rotation-aware structure recognition (#1678) to simplify goal checking for word search (#999).

![Screenshot from 2024-03-13 18-48-53](https://github.com/swarm-game/swarm/assets/261693/6fc9e62e-d9e2-4a13-8969-32dbee695e0a)

# Benchmarks

Using the following command (GHC 9.6.4):

    scripts/run-tests.sh --test-arguments '--pattern "word-search"'

| Before | After |
| --- | --- |
| `0.98s` | `0.82s` |
2024-03-15 15:06:49 +00:00
Karl Ostmo
02eecba832
fix watch wakeup test (#1791)
This improves the test introduced in #1736 in a few ways:
* Place the system robot's code inline in the `program` field
    * even though the system bot had been using `instant`, the `run` command itself incurs a delay.  So this ensures the system robot is ready to monitor the cell immediately
* System robot uses exclusively `Intangible` commands in its monitoring loop
    * This allows removal of the `instant` command.
    * `Surveil`, which does not appear in any scenario yet, is made `Intangible`.
* Remove the initial `wait 2` in the player robot's solution.

Tested to ensure that this still exercises the problem that #1736 set out to solve, by commenting out this line (causing the scenario to fail).

01ae0e45d7/src/swarm-engine/Swarm/Game/State/Robot.hs (L396)

## Demo

    scripts/play.sh -i data/scenarios/Testing/1598-detect-entity-change.yaml --autoplay --speed 1
2024-03-15 14:34:26 +00:00
Karl Ostmo
01ae0e45d7
react immediately to wakeups (#1736)
Fixes #1598

## Demo

Illustrates immediate (same-tick) reaction to a change of a `watch`ed cell:

    scripts/play.sh -i data/scenarios/Testing/1598-detect-entity-change.yaml --autoplay --speed 1

## Background
Robots can be **scheduled** to wakeup from a `watch` by the `wakeWatchingRobots` function.
Robots may be **actually awakened** by the `wakeUpRobotsDoneSleeping` function.

Previously, `wakeWatchingRobots` would only ever schedule wakeups at `currentTick + 1`.  Then, once the next tick is reached, in `wakeUpRobotsDoneSleeping` only robots that had been scheduled to wake on precisely the **current tick** could actually be awakened.

But this made it impossible for one robot to cause another robot, which had been sleeping, to actually wake up within the same tick that scheduling of the wakeup is performed.

The importance of this comes into play for system robots that are `watch`ing a cell and intended to react instantaneously to player actions (usually by running code in an `instant` block).

During each "tick", every active robot gets exactly one "turn" to execute code.  Given the following ID assignments:
| Robot ID | Robot name |
| --- | --- |
| `0` | `base` |
| `1` | `systemBot` |

the `systemBot` will always execute *after* the `base` robot in a given tick.

If the `systemBot` is `watch`ing a given cell, a modification of that cell by the `base` will schedule a wakeup of the `systemBot`.  If the scheduled wakeup tick is `currentTick + 1`, then the `base` will have **another execution turn** before the `systemBot` gets an opportunity to react to the `base`'s action at the current tick, causing the `systemBot` to overlook actions that may be relevant to a goal condition.

## Solution

In contast, if we schedule the `systemBot` wakeup for `currentTick` instead of `currentTick + 1`, then it should have an opportunity to wake, run, and react to the `base`'s action before the `base`'s next turn.

But in the status quo, the selection of which robots to run in a given tick is made only once, before iteration over those robots begins.  We need instead to update the robots-to-run pool dynamically, after each iteration on an individual robot.  The most appropriate data structure for the iteration pool is probably a [Monotone priority queue](https://en.wikipedia.org/wiki/Monotone_priority_queue), but we approximate this with an `IntSet` of `RID`s and the [`minView`](https://hackage.haskell.org/package/containers-0.7/docs/Data-IntSet.html#v:minView) function.

Being able to alter the list of active robots in the middle of a given tick's robot iteration has required a change to the `runRobotIDs` function.  Instead of using a `forM_` to iterate over a static list of `RIDs`, we have a custom iteration function `iterateRobots` to handle the dynamic set.

## Performance

Benchmarks were performed locally with `stack` and GHC 9.6.

I had tested the replacement of the `forM_` loop with `iterateRobots` in isolation, and it had zero effect on benchmarks.  But some other trivial changes tested in isolation, such as the addition of docstrings, yielded a +6% increase in benchmarks.  So there seems to be some instability in the ability of the compiler to perform certain optimizations.

With this PR, increases in benchmark times ranging from 7% to 11% were observed.  The obvious culprit is that `wakeUpRobotsDoneSleeping` is now called N times per tick, rather than once per tick, where N is the number of robots that are initially (or become) active during that tick.

### Mitigating with an "awakened" set

In the common case (i.e. when there are *no* watching robots), the `wakeUpRobotsDoneSleeping` that is now executed `N` times per tick (instead of once per tick) incurs a `Map` lookup, which is `O(log M)` in the number of distinct future wakeup times across all robots.

However, those extra `N` invocations only exist to serve the purpose of `watch`ing robots that may need to wake up at the current tick.  It may be more efficient to have a dedicated `Set` in the `GameState` for such robots that gets populated parallel to this insertion:

ad5c58917e/src/swarm-engine/Swarm/Game/State/Robot.hs (L387)

Then if this set remains `null`, we can avoid paying for an additional `O(N * log M)` operations entailed by the `Map` lookups into `internalWaitingRobots`.

#### Result

Indeed, storing awakened bots in a new `currentTickWakeableBots` set restored the benchmarks nearly to the baseline.  Instead of the regressions in the 10-20% range observed before, now only a few benchmarks had at most 3-4% increases.

### CI regressions

In CI, (`snake`, `powerset`, and `word-search`) exceeded their timeout thresholds in GHC 9.2 and GHC 9.4.  No regressions were observed with GHC 9.6.  To accommodate the lowest common denominator, I bumped the thresholds for those three scenarios to get a passing build.

I don't believe it is worth further effort or investigation to optimize for GHC 9.4, since such efforts will be moot for GHC 9.6 and onward.

Test invocation:

    cabal test swarm-integration --test-show-details streaming --test-options '--color always --pattern "word-search"'

| **Scenario** | GHC 9.4.8 | GHC 9.4.8 | GHC 9.6.4 | GHC 9.6.4 | 
| --- | --- | --- | --- | --- |
|  | Before | **After** | Before | **After**
| `snake` | 1.84s | **5.38s** | 1.62s | **1.67s** |
| `powerset` | 1.66s | **5.09s** | 1.56s | **1.66s** |
| `word-search` | 0.56s | **1.91s** | 0.44s | **0.48s** |

### Potential improvements

#### `TickNumber` as `Map` key

`waitingRobots` is of type `Map TickNumber [RID]`.  Instead of `Map`, we could have a `newtype` that encapsulates a `IntMap` to make lookups by `TickNumber` more efficient.
2024-03-11 02:48:26 +00:00
Karl Ostmo
7d3f2635e1
whitelist walkable entities (#1721)
A walkability "blacklist" had already been implemented in #1536.  The whitelist shall **only** permit walking on the specified entities; blank cells become unwalkable.

This feature would allow use of the `path` command to check for "connectivity" by way of a "trail" of entities.

## Use cases

* system robots or goal conditions can use this to check whether the player has connected two points with a road, cable, aqueduct, etc.
* monkeys, which can only move along `tree`s
* sea life, which should only be able to move in `water`

## Testing

    scripts/run-tests.sh --test-arguments '--pattern "walkable-entities"'
2024-03-10 01:31:35 +00:00
Brent Yorgey
bb42e34b58
Allow blaze-html-0.9.2 (#1789) 2024-03-08 13:15:39 -06:00
Karl Ostmo
3f2a8fd5be
docstring for grantAchievement (#1785)
See https://github.com/swarm-game/swarm/pull/1751#discussion_r1469963881
2024-03-06 19:17:30 +00:00
Karl Ostmo
936b30d22a
extensible terrain (#1775)
Closes #1641

The `data/terrain.yaml` file is now the authoritative source of terrains, though `BlankT` is still a hard-coded special case.

I have not changed the underlying integer representation of terrain in the world function, which means that the `terrainIndexByName` Map in the `TerrainMap` record is needed for translating between `Int` and `TerrainType`.

# Demo

    scripts/play.sh -i data/scenarios/Testing/1775-custom-terrain.yaml

![Screenshot from 2024-02-22 16-51-53](https://github.com/swarm-game/swarm/assets/261693/1d263c8b-4e9c-40bf-bdc8-bf5ba8e33c4d)

# Changes

* There used to be a function called `integrateScenarioEntities` that combined the `EntityMap` stored in the `Scenario` record with the global entity map.  However, the global entity map is accessible at parse time of the `Scenario`, so we do the combining there and only ever store the combined map in the `Scenario` record.
* JSON Schema for terrain
* Removed the distinction between "World" attributes and "Terrain" attributes
* Unit tests for scenario-defined terrain and related validations
    * Validate existence of referenced terrain at scenario parse time
    * Validate attributes referenced by terrains at parse time
2024-02-29 06:22:21 +00:00
Karl Ostmo
0d65a0497c
Use entityAt instead of getContentAt (#1774)
Follow-up to #1724.
2024-02-20 01:42:01 +00:00
Karl Ostmo
7c991f7392
add scrollbar to scenario menu (#1770)
Closes #1687

![Screenshot from 2024-02-18 17-53-28](https://github.com/swarm-game/swarm/assets/261693/86fc4ea5-23f8-4cc5-b676-ae17d81b1b34)
2024-02-19 20:32:22 +00:00
Karl Ostmo
95a90147a5
fishing scenario (#1628)
This scenario makes use of several relatively recent features/commands:
* structure placement
* structure queries (for goal checking)
* density command (for goal checking)
* combustion
* tags
* goal prerequisites with boolean expressions

## Demo

    scripts/play.sh -i Challenges/Ranching/fishing.yaml --autoplay

![image](https://github.com/swarm-game/swarm/assets/261693/a9f932a2-7481-4ee4-992a-a4dcd8b7cfd5)
2024-02-19 20:19:39 +00:00
Karl Ostmo
e851f445a8
autoformat cabal file (#1769)
Closes #1709.
2024-02-19 20:07:15 +00:00
Karl Ostmo
9253b0eb94
decompose scenario record (#1771)
Peripheral to #1715.
2024-02-19 19:53:43 +00:00
Karl Ostmo
ad9bdf2b09
Scenario description in goals dialog (#1766)
Closes #1735.

# Demo

    stack exec swarm -- -i data/scenarios/Challenges/bridge-building.yaml

## Before

![Screenshot from 2024-02-17 15-27-32](https://github.com/swarm-game/swarm/assets/261693/02eee0e4-c873-49bb-929b-2c87ddc4f3bf)


## After

![Screenshot from 2024-02-17 15-25-24](https://github.com/swarm-game/swarm/assets/261693/7d9eb956-db34-4186-8596-e6fb5c9a4366)
2024-02-19 00:55:11 +00:00
Karl Ostmo
084f3125d0
Decompose UIState record (#1767)
Introduced 3 new sub-records in `UI.hs`:
* `UIGameplay`
* `UITiming`
* `UIInventory`

This allows some functions (e.g. `populateInventoryList`) to operate on a narrower scope of state.

Also uses `Brick.zoom` in a few more places to mitigate the longer lens chains.
2024-02-18 22:31:48 +00:00
Brent Yorgey
a1bab6d16c
Dependency updates (#1765)
Some dependency updates, to allow:
- `vty-6.2`
- `brick-2.3`
- `warp-3.4`
- `bytestring-0.12`
- `text-2.1`
2024-02-12 20:04:28 +00:00
Brent Yorgey
c4a6e273c1
Update to depend on lsp-2.4.0.0 (#1762)
Update to use the `lsp-2.4` API.  Closes #1350.

Initially I hoped that any `lsp-2.x` would work.  However, the `SeverDefinition` record changed in `2.2` so I initially set that as a lower bound.  But then it turns out that `2.4` changed which module it is importing `Rope` from; since we work with ropes in the `Hover` module it matters since we have to import the matching module.  Updating to the new `Rope` type also required some changes as the API provided by the new `Rope.Mixed` module is a bit different than the old module, so we would not even be able to easily put in CPP to conditionally depend on the right rope module depending on the `lsp` version.  Finally, this means dropping support for GHC 9.0 since `lsp-2.4` does not support it.

Along the way I also fixed a minor issue related to showing type information returned by the LSP server, so that it uses `prettyTypeLine` to display the type on a single line (in my editor, when the type does not use a single line it gets cut off).  For comparison see also #1610. 

This refactoring was a big pain because a lot of things (names of types and constructors, locations of exports, etc...) changed from 1.x to 2.x, but there was not much in the way of documenting what had changed. =(   I am pretty sure that all functionality has been preserved but I would appreciate independent confirmation.

This is also a prerequisite for updating other dependencies such as the `base` version (I will open a follow-up PR soon) since the old `lsp-1.x` versions do not allow many newer versions of various dependencies.
2024-02-12 11:05:39 -06:00
Karl Ostmo
bce45cc0fe
gallery scenario (#1760)
![Screenshot from 2024-02-04 22-25-24](https://github.com/swarm-game/swarm/assets/261693/6541523c-4279-4fdf-a8fe-c3c8af1aa169)

    scripts/play.sh -i data/scenarios/Challenges/gallery.yaml --autoplay

## Code changes

In addition to the new scenario, this PR includes a code change to allow the order of items returned by the `tagmembers` to be specified by the scenario author.
2024-02-05 17:17:33 +00:00
Brent Yorgey
a3d6e5b10a
Refactor ObjectiveCompletion to use lenses (#1757)
Closes #1037.

The main changes are in `Swarm.Game.Scenario.Objective`.
- No longer export the `CompletionBuckets` type, nor the constructor or record accessors of the `ObjectiveCompletion` type
- Export folds such as `incompleteObjectives` (a `Fold` is like a read-only `Traversal`, i.e. it has multiple targets but does not allow setting/modification), as well as `allObjectives`.
- Export some custom functions such as `addCompleted` which properly maintains the internal invariants of `ObjectiveCompletion`.

The rest of the changes are simply adapting to use these new lenses + folds instead of directly accessing `CompletionBucket` values or using the underscored record field projections.

This simplifies the code in `Swarm.Game.Scenario.Objective` and hopefully makes the code safer (previously, it was possible in theory to violate `CompletionBuckets` invariants by directly modifying its fields).
2024-02-04 02:58:09 +00:00
Karl Ostmo
30f6f59385
preview rendered world with inotify (#1756)
Opens a live-reloading preview of the world in VS Code.

The renderer has been modified to optionally render a blank image instead of crashing upon invalid YAML.

## Prerequisites:
Install inotify tools:

    sudo apt install inotify-tools

## Usage:

    scripts/preview-world-vscode.sh data/scenarios/Fun/horton.yaml

Once the VS Code editor tabs are opened, one can press <kbd>CTRL</kbd> + <kbd>\\</kbd> (backslash) with the image selected to split the editor pane horizontally.
One may then navigate to the left-pane's copy of the image preview with <kbd>CTRL</kbd> + <kbd>PageUp</kbd>, and then <kbd>CTRL</kbd> + <kbd>w</kbd> will close the redundant image preview.

## Screenshot

![Screenshot from 2024-01-29 18-53-55](https://github.com/swarm-game/swarm/assets/261693/63a4728c-0ccb-4c08-8cde-61d65e8322b4)
2024-01-31 19:23:43 +00:00
Karl Ostmo
8181cea944
simplify spellchecker words script (#1755)
Found the `tr` command to replace the extra `split-module-names.hs` script.
2024-01-29 19:05:35 +00:00
Karl Ostmo
0c45811755
tweak benchmarks (#1754)
In support of #1598 (for #1739).

Runs the `idle` benchmark for many more ticks and with many more robots to try to emphasize the effect of regressions and  mitigate jitter.

Also factors out common code from the `benchmark-against-parent.sh` script.
2024-01-29 18:38:57 +00:00
Karl Ostmo
e7b8cfba31
check achievement robot requirements (#1751)
Closes #1726

There are now two entry points to obtain a `GameplayAchievement`:
* `grantAchievementForRobot`
* `grantAchievement`

The latter enforces that the achievement is applicable to the current game mode (i.e. creative), while the former makes an additional check for validity of system robots.

This is an improvement over the status quo, but note that it is still currently possible to make a coding error in which an achievement specifies a requirement of **not** being a system robot, but the site at which the achievement is granted only calls `grantAchievement`, bypassing the robot validity check.
2024-01-29 18:26:54 +00:00
Karl Ostmo
a18258c20d
extract scene renderer to its own binary (#1752)
Closes #1715

Extract scene renderer to its own binary with `swarm-scenario` as its only dependency.

This was mainly enabled by moving the `Landscape` sub-record out of the `swarm-engine` sublibrary and into `swarm-scenario`, and refactoring rendering functions to only depend on `Landscape` rather than the entire `GameState`.

# Demo

    stack build --fast swarm:swarm-scene && stack exec swarm-scene -- data/scenarios/Fun/horton.yaml --png -w 180 -h 150

![output](https://github.com/swarm-game/swarm/assets/261693/e2df3aad-3b65-46bf-8485-352facdffc76)
2024-01-29 18:01:56 +00:00
Karl Ostmo
9f5c165fd8
autopopulate spellchecker (#1749)
Builds upon #1587.

Extract all symbol names that are not native to the current project and insert them into our own custom spell checking dictionary's "words" list.

The premise is that symbols that *are* native to our project should be spellchecked, but foreign symbols that constitute unrecognized dictionary words are presumably intentionally spelled that way.

# Convention

Manually-added words (i.e. for names in code that we've written for this project) will go into `.vscode/settings.json`.
The automatically generated word list from third-party packages goes into `cspell.json`.

# Usage

    scripts/spellcheck/autopopulate-spellchecker.sh
2024-01-28 01:54:13 +00:00
Karl Ostmo
42d4e54797
volume command (#1747)
Measures the volume of an enclosed space.
A useful alternative to the `path` command for goal checking.

## Demo

    scripts/play.sh -i data/scenarios/Testing/1747-volume-command.yaml --autoplay --speed 2
2024-01-28 01:02:08 +00:00
Karl Ostmo
aacdbf3473
Remove Benchmark dependence on AppState and TUI (#1746)
`stack bench` is now independent of the TUI and `AppState`.
2024-01-26 17:56:39 +00:00