Commit Graph

96 Commits

Author SHA1 Message Date
Brent Yorgey
4be0f7359d
Refactor: move ResourceLoading to swarm-util (#2162)
Now that `Failure` is moved to `swarm-util` (#2155), that was the last remaining dependency of `Swarm.Game.ResourceLoading` which prevented it from moving as well.  The `ResourceLoading` code is not specific to Swarm scenarios; this PR moves it to `swarm-util` to make it more generally applicable.

In fact, the `ResourceLoading` code is already being used to load `.sw` files when executing the `Run` command; in order to implement #495 we will need to do that loading in order to resolve `import` expressions, but that code will live in `swarm-lang`, which cannot import `swarm-scenario`.
2024-09-30 18:12:34 +00:00
Brent Yorgey
02b151f0ff
Refactor: move pretty-printing and failure code to swarm-util (#2155)
`Swarm.Language.Pretty` (in the `swarm-lang` package) had a bunch of generic pretty-printing infrastructure along with a bunch of specific instances for terms and related things.  However, the generic pretty-printing code infrastructure is not specific to swarm-lang.  This PR:

- Moves the generic pretty-printing infrastructure + utilities to `Swarm.Pretty` in `swarm-util` to make it more generally applicable.
- Distributes all the actual `PrettyPrec` instances to live next to the declarations of the corresponding data types.

In addition, `Swarm.Game.Failure` (in the `swarm-scenario` package) also had no dependencies on anything else in `swarm-scenario`, so this PR also moves it to `Swarm.Failure` in `swarm-util`, to make it more generally applicable.

Along the way I also removed `DelayType` and `Prec` since they are no longer being used.
2024-09-29 22:04:10 +00:00
Ondřej Šebek
65c5ef94ec
Pause on objective completion (#2096)
* add a new option `--hide-goal  Do not show goal modal window that pauses the game.`
* pause the game once an objective is finished - can be disabled by `--hide-goal`
* show the goal modal window (and autopause) even when running with `--autoplay`
  * previous behavior can be achieved with `--autoplay --hide-goal`
  * removes the debug option `autoplay_goals`
* closes #2073
2024-09-09 10:56:15 +00:00
Ondřej Šebek
589e2665b5
Refactor App using standalone functions (#2130)
* Make `appMain` fit on the screen.
* Replace state `s1` and `s2` versions with `modifyIORef`.
2024-09-02 15:39:42 +00:00
Ondřej Šebek
aeedebf8ac
Move App version to app (#2121)
* move app version from `swarm-engine` library to `swarm` executable
  * this removes `githash` dependency from the library
* part of #2109
2024-08-31 17:22:30 +00:00
Ondřej Šebek
a24b6a8413
Remove Brick dependency from Web (#2120)
* use the IO wrapper trick again for fun and profit ™️
* part of #2109
2024-08-15 20:38:19 +00:00
Ondřej Šebek
f82a544cc5
Replace ReadableIORef with IO (#2098)
* replaces the `ReadableIORef a` with an `IO a`, by pre-applying `readIORef` to the `IORef a`

The result of `IO a` is immutable `a`, so this is even safer than a newtype that needs a carefully chosen export list.

Basically this removes one file and some boilerplate from `Web.hs`.
2024-08-08 20:48:58 +00:00
Ondřej Šebek
08045793b1
Split debug options (#2094)
* replace `_uiCheatMode :: Bool` with `_uiDebugOptions :: (Set DebugOption)`
  * replace `uiHideGoals` with `uiIsAutoPlay` and debug option `ShowGoalDialogsInAutoPlay` 
* add command line flag `--debug` and make `--cheat` an alias for `--debug=creative` only 

```
  -x,--cheat               Enable cheat mode. This is an alias for --debug=creative
  -d,--debug OPTS          Use 'all' or a comma separated list of options:
                             * creative           allow toggling creative mode on/off
                             * editor             allow toggling the world editor mode on/off
                             * cesk               allow toggling the CESK debug view on/off
                             * all_robots         list all robots (including system robots) in the robot panel
                             * robot_id           list robot IDs in the robot panel
                             * hidden_goals       show hidden objectives in the goal dialog
                             * autoplay_goals     show goal dialogs when running in autoplay
                             * testing            show Testing folder in scenarios menu
```

It even has shell completions:
```bash
swarm --zsh-completion-script `which swarm` > ~/.oh-my-zsh/completions/_swarm
swarm --debug  # press Tab
# all  all_robots  autoplay_goals  cesk  creative  editor  hidden_goals  robot_id  testing
```

* closes #1324
2024-08-08 19:52:29 +00:00
Ondřej Šebek
fe5fdf1c27
Update the UI on game start (#2095)
* update UI even when paused
* send frame events earlier
* closes https://github.com/swarm-game/swarm/issues/2081

You can test it with:
```bash
cabal run swarm -O0 -- --scenario Tutorials/move  # and a combination of --paused --autoplay --cheat
```
2024-08-06 05:43:59 +00:00
Karl Ostmo
f3a15c69c5
remove pandoc dependency from main game (#2084)
Closes #2083

Rendering a matrix of command attributes was originally implemented in #1658.  But this generated the data to drive the table at runtime, which pulled in an unfortunate Pandoc dependency.

To work around this, let's just pre-generate the data offline.

# Demo

1. `scripts/play.sh`
2. Visit http://localhost:5357/command-matrix.html
2024-07-30 00:57:36 +00:00
Ondřej Šebek
603d7cbb70
Clarify speed option help text (#2082)
* update CLI option help: 
  ```
  -m,--speed N             Initial game speed. Counted as 2^N ticks per second,
                           default is 4 meaning 16.0 t/s.
  ```
* closes #2078
2024-07-29 20:41:42 +00:00
Ondřej Šebek
e98660b0e4
Add CLI option to start the game paused (#2080)
* add CLI option:
  ```
  -p,--paused              Pause the game at start.
  ```
* closes #2076

---

You can test it with:
```sh
cabal run swarm -O0 -- --scenario Tutorials/move --paused
```
After one step (<kbd>Ctrl</kbd>+<kbd>O</kbd>) the Goal dialog will show up along with the rest of the UI.
2024-07-29 20:27:16 +00:00
Karl Ostmo
35975bb1c8
use weeder (#2044)
Closes #2043

# Local usage notes

I suspect that HLS in VS Code spontaneously pollutes the `.hie` directory, because after a few successful invocations, `weeder` started complaining with:
```
incompatible hie file: /home/kostmo/github/swarm/.hie/Swarm/Web/Auth.hie
    this version of weeder was compiled with GHC version 9064
    the hie files in this project were generated with GHC version 9048
    weeder must be built with the same GHC version as the project it is used on
```

## Fixing false positives

Previously, for each `library` and `executable`, the HIE directory was always the same:
```
ghc-options:
    -hiedir=.hie
```
However, most of the executables have at least one module path that is the same relative to their `hs-source-dirs` base: namely, `Main.hs`.  This resulted in all but one of the `Main.hie` files being overwritten in the end.

To avoid this, I have specified a different `-hiedir` for each `library`/`executable`/`test` that parallels its `hs-source-dirs` base.  This way, so long as `hs-source-dirs` are unique across these targets, all of the `*.hs` files across the entire project will have unique `*.hie` paths.

## Whitelisting exceptions

There are some known limitations with `weeder` regarding support for Template Haskell and type families.  Exceptions are specified in the `roots` list in `weeder.toml`.

After removing a handful of dead functions myself, there are approx. 30 "true positive" weeds that I have listed explicitly in `weeder.toml`.  Maintenance of this list of exceptions should eventually be easier with https://github.com/ocharles/weeder/issues/146.

# Integration with CI

I found a ready-made GitHub Action for weeder: https://github.com/freckle/weeder-action
I hacked support directly into the generated `.github/workflows/haskell-ci.yml` file.

Ideally, the generator would have an option for a `weeder` step.  Indeed, there is an open issue for supporting `weeder` in `haskell-ci`: https://github.com/haskell-CI/haskell-ci/issues/132

A separate but related functionality that would be nice in `haskell-ci` is to specify **one** of the GHC versions in the matrix to do additional validations/builds that would be redundant if performed on the other matrix entries.  I suppose `weeder` is inexpensive enough to redo four times, but the `weeder` binary is not available for download for all GHC versions (e.g. ghc `9.8.2`).  Something like `haddock` we probably only need to build once.
I have hacked this in to the generated file for `weeder` with a simple [`if` condition](https://github.com/swarm-game/swarm/pull/2044/files#diff-73f8a010e9b95aa9fe944c316576b12c2ec961272d428e38721112ecb1c1a98bR227).
2024-07-17 22:00:24 +00:00
Noah Yorgey
c6288e53cb
Fix the cheat sheet options (#2047)
Closes #2045.
2024-07-15 14:55:32 +00:00
Ondřej Šebek
363f1085c9
Filter recipe graph (#2033)
* add filter options to the recipe graph to cut down the noise
2024-07-14 02:20:51 +00:00
Ondřej Šebek
905ddf5415
Fix keybindings initialisation when directory is missing (#2031)
* Closes #2026
2024-07-13 19:53:45 +00:00
Ondřej Šebek
687bad8610
Customizable keybindings (#1979)
* create a new `SwarmEvent` enumeration
  * define configuration names (`swarmEvents`)
  * define default keybindings (`defaultSwarmBindings`)
* add `KeyConfig` and `KeyDispatcher`s to `AppState`
  * load custom bindings from an INI file
* migrate key event controller code to use `onEvent`
  * call `handleKey` with handlers
* show the shortcuts in TUI
* check for conflicts between parent/child handler (right now `mainHandler` and the rest)
* generate the INI file (`keybinding --init`) with commented-out (`;`) settings
* allow `brick` version 2.4 to get uppercase keybindings fix

---

* Closes #523
* Closes #1962
2024-07-08 11:43:37 +00:00
Nitin Prakash
4dc0976fc1
Generate operators for all editors (#1950)
Currently, operator names are generated only for vscode only using the command `cabal run swarm:swarm-docs -- editors --code`.
With this PR, I intend to bring that behaviour to all the editors.

Changes include:
- `cabal run swarm:swarm-docs -- editors` command now supports `vim` as well.
- `operatorNames` can generate operator list catering to all the editors supporting Swarm.
- Update operator list in `swarm-mode.el`, `swarm.vim` and `swarm.tmLanguage.yaml`.

How to test emacs syntax:
- Open `editors/emacs/swarm-mode.el` in emacs.
- Then `M-x eval-buffer`
- Open up any of the `.sw` file under `examples`.
- Then `M-x swarm-mode`

How to test vim syntax:
- Copy swarm.vim to vim directory using `cp editors/vim/swarm.vim ~/.vim/syntax/sw.vim`
- Setup auto detect in vim. `echo 'autocmd BufRead,BufNewFile *.sw set filetype=sw' > ~/.vim/ftdetect/sw.vim`
- Open up any of the `.sw` files under `examples`. (Also ensure that you have syntax on in vim. `ESC :syntax on`)
2024-06-18 17:01:37 +00:00
Karl Ostmo
82e8ac95ad
Implement GitHub authentication (#1856)
Closes #1847.

## Demo

### Production
https://swarmgame.net/list-games.html

### Local testing
```
tournament/scripts/demo/server-native.sh
```
and

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

## Authentication flow

1. Users are represented by a GitHub username (primary key) and an "authentication cookie" in the SQLite database.
2. Site prompts user to login when the client's cookie is nonexistent or does not match any user in the database.
3. GitHub flow:
    1. Clicking the "Login" link redirects user to the GitHub login page.
    2. GitHub sends a `code` to our callback URL.
    3. use that `code` to get an "access token"
    4. use the "access token" to look up the username of the person who is logging in.
    5. generate and store a new cookie in the database row for that username
    6. set the cookie value on the user's client.
4. As long as the client keeps sending the cookie value known to the server, all uploads/activity will be attributed to their GitHub username.

## New features

* Login/Logout
* All uploaded content is attributed to an authenticated GitHub user
* Separate pages for scenario lists and solution lists
* Download a solution file
2024-05-22 00:27:21 +00:00
Brent Yorgey
e071252d72
Add format --v0.5 option to port code from older syntax (#1851)
This is a followup on top of #1583 which turns `swarm format` into a tool for porting existing Swarm code into the newest syntax, via an extra `--v0.5` argument.  In particular, this PR:

- Generalizes the parser to take a configuration record, which among other things contains the language version being parsed.
- Adds code to allow the parser to parse either the current syntax or one version ago (when types did not start with capital letter) depending on the version in the configuration.
    - The idea is to have the parser always support the current version and one older version, so we can always upgrade version n to version n+1.
- Adds a new flag `--v0.5` to the `format` subcommand which causes the input to be parsed in v0.5 mode.  However, the output of `format` will always use the latest syntax.  Thus, `swarm format --v0.5` reads code in v0.5 format and prints it in the latest format, so this can be used to automatically port existing `.sw` files.

This PR also makes a few minor improvements to pretty-printing.
2024-05-22 00:09:31 +00:00
Brent Yorgey
76958a4639
Insert parsed comments back into the AST and pretty-print with comments (#1845)
This PR does three main things:
1. Insert parsed comments into the AST
2. Extend pretty-printing to include comments
3. Extend the `format` subcommand with a few additional options and move the code to `Swarm.Language.Format`.

The pretty-printed code-with-comments is OK but not great.  It does a reasonable job with comments in standard-ish places; for example, it turns
```
// This function increments a number
def incr : int -> int =
  \n. n + 1
end

/* This command does some stuff.  It is super
   cool and important. */
def stuff : cmd unit =
  move;
  move;
  move;  // the third move is important
  move;
end
```
into
```

// This function increments a number
def incr: int -> int = \n. n + 1 end;

/* This command does some stuff.  It is super
   cool and important. */
def stuff: cmd unit =
  move;
  move;
  move // the third move is important
  ;
  move
end
```
which is good other than the fact that it moves the inline comment after `move;` to before the semicolon.

However, it turns this:
```
// This function does a cool math thing
def foo : int -> int =     // This is an optional type signature
  // pre
  \n. n + 1    // add one
end

/* This is a
   block comment which
   spans multiple lines */

def bar : int -> int   // Another type signature, = on the next line
  = \x. foo /* very important to use foo here */ (foo x)   // very cool implementation
end

def baz : cmd unit =
  move;
  move;
  turn left;   // don't forget to turn left!
  move
end

// And one last thing
```
into this:
```

// This function does a cool math thing
def foo: int -> int 
  = \n.
  n + 1 // add one

end // This is an optional type signature
;

/* This is a
   block comment which
   spans multiple lines */
def bar: int -> int 
  = \x.
  foo /* very important to use foo here */ (
    foo x // very cool implementation

  )
end // Another type signature, = on the next line
```
which has several obvious problems.  I think I know what the problem is in most cases; it will just require more engineering and special cases to get the output to look nicer, but I honestly don't really want to spend more time on this right now.  I'm hoping we can merge this as is (since it is still better than the status quo, namely, deleting all comments) and continue to improve it in the future.

The important point is that I ran the code formatter on every single `.sw` file in the repository and then re-ran the test suite; all the tests passed. So at least `swarm format` does not seem to break anything even if the output does not look the best.

Closes #1467 .
2024-05-14 11:32:03 +00:00
Karl Ostmo
c993d9dfdd
Use sqlite and static binary (#1837)
This is a rework of #1798 to facilitate a simpler web stack.

# Demo

View http://swarmgame.net/

NOTE: Requires IPv6

# Motivation

Hosting cost is a main motivation.  Cost per month for an EC2 instance, RDS, and the requisite other services approaches >$50 per month.  In contrast, the lowest-tier Lightsail instance is $3.50/month.

The deployment process is of course simplified.

An incidental benefit to using SQLite is reduced latency of web requests; we no longer need to fetch credentials from an AWS API to connect to Postgres.

## Changes

Major changes:
* Use `sqlite` instead of `postgres`
* Use Docker to build a statically-linked deployable binary, rather than deploying the app within a Docker image

Fortunately, the API of `sqlite-simple` is near-identical to that of `postgresql-simple`, so most of the code change there is just to rip out AWS-specific stuff and Postgres connection info.  I have no hesitation to delete this code since if we ever want to use the previous stack again, we can just look at #1798.
2024-05-12 20:45:08 +00:00
Brent Yorgey
bc0c4040c5
Split the parser into submodules (#1841)
I noticed the parser was getting kind of unwieldy, and I'm going to be adding even more code to it as part of #1467, so I decided to take the opportunity to refactor first.

This PR introduces no behavior changes, it is purely refactoring.
2024-05-12 01:31:54 +00:00
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
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
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
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
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
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
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
9253b0eb94
decompose scenario record (#1771)
Peripheral to #1715.
2024-02-19 19:53:43 +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
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
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
Karl Ostmo
669163384e
apply hlint 3.8 suggestions (#1744)
As title
2024-01-26 01:36:13 +00:00
Karl Ostmo
5f53082971
Render command matrix (#1658)
## Demo

1. Run `scripts/play.sh`
2. Load http://localhost:5357/command-matrix.html

The rows are sortable by column.

### Also

    stack build swarm:swarm-docs --fast && stack exec swarm-docs -- cheatsheet --matrix



## Screenshot

![Screenshot from 2024-01-21 21-32-56](https://github.com/swarm-game/swarm/assets/261693/f92f5ac9-8440-4aac-9a4b-9e5edac616f2)
2024-01-26 01:02:14 +00:00
Karl Ostmo
3d87e71939
Use type family for robot CESK machine field (#1729)
Towards #1715 and #1043.

This refactoring step is a prerequisite for #1719 to extricate references to the `CESK` module from the base `RobotR` definition.

In this PR:
* `Swarm.Game.CESK` is imported qualified to more easily track usages
* A new `RobotMachine` type family is added to parameterize the `_machine` field.
* `CESK` is a new parameter to `addTRobot`
2024-01-14 20:11:44 +00:00
Brent Yorgey
ded3c24223
Depend only on vty-crossplatform (#1727)
Closes #1623.

Note that we still have to list both `vty-unix` and `vty-windows` in `stack.yaml` but that's OK; it just means they are both made available as extra dependencies, but only whichever is needed will actually be installed.  In the codebase itself, we now get to avoid CPP on imports, and the code is quite a bit simpler.
2024-01-13 23:47:17 +00:00
Karl Ostmo
47a8ffe115
rename 'portable' to 'pickable' (#1706)
Closes #1695.

Updating occurrences was pretty easy:

    yq --inplace '(.[].properties[] | select(. == "portable")) |= "pickable"' data/entities.yaml

and

    find data/scenarios -type f -name '*.yaml' -print0 | xargs --max-args 1 --null yq --inplace '(select(has("entities")) | .entities[] | select(has("properties")) | .properties[] | select(. == "portable")) |= "pickable"'
2024-01-05 19:58:19 +00:00
Karl Ostmo
1da74a79dd
move ReadableIORef to util sublibrary (#1700)
As title.
2024-01-01 02:29:07 +00:00
Karl Ostmo
f6f01b264c
web sublibrary (#1697)
Towards #1043

Creates a new sub-library for the web service.  Also moved the `Swarm.App` module from the `swarm` library to the `swarm` executable.
2024-01-01 02:06:58 +00:00
Karl Ostmo
b8d37a9364
extract doc generator to separate executable (#1671)
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
2023-12-04 03:45:07 +00:00
Karl Ostmo
01a5b070e7
render map to PNG format (#1632)
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)
2023-11-20 04:37:49 +00:00
Karl Ostmo
4e886e0c3c
Autogenerate scenario schema doc (#1441)
Closes #1436.

The schema `.json` files are now the authoritative source of truth for documentation.

Wrote a very simple parser for JsonSchema to extract the documentation from JSON.

Split the README.md into [static](c314cc50a1/data/scenarios/README.md) and [auto-generated](c314cc50a1/data/scenarios/doc-fragments/SCHEMA.md) parts.

Added a custom `"footers"` key to schema files to support inclusion of other markdown files for each object description.

# Schema doc regeneration

    ./scripts/regenerate-schema-docs.sh
2023-10-09 02:11:30 +00:00
Ondřej Šebek
24ef7c21dc
Web API docs improvements (#1529)
* generate Web API endpoint docs in CLI - `swarm generate endpoints`
* use default port in API docs using `renderCurlBasePath`
* fix code rendering in Web API so that the tree nodes try to fit one line
* try adding some API samples
* hand craft `ToJSON Robot` instance to match `FromJSONE` more closely
  * default values are skipped
  * inventory and devices are shortened to names and counts
2023-09-28 11:04:40 +00:00
Karl Ostmo
a9ded587eb
Render map preview on scenario selection screen (#1515)
Closes #353

Also adds a new top-level command to render a scenario map to the console.

Most of the work for this feature entailed identifying the subset of `GameState` that is actually needed for rendering the world, so that the required information can be retrieved from just the `Scenario` rather than having to instantiate an entire `GameState`.

# Potential follow-ups

- [ ] There is some noticeable lag when using the up/down arrow to navigate to any of the largely "procedurally generated" scenarios, e.g. `classic` or `creative`.  May want to do caching of some kind.  The other "challenge scenarios" render without perceptible delay.
- [ ] The heuristic for choosing the view center could be improved, possibly by defining new "hints" as part of the scenario schema.
- [ ] Rendering to the console could be augmented with color.
- [ ] Could render to other image formats like PNG or SVG
- [ ] account for a user-selected seed in the scenario launch parameters dialog

# Demos
## Scenario selection preview
![image](https://github.com/swarm-game/swarm/assets/261693/7c54c6bb-fb02-461f-98a1-06eccbbfc450)

## Command-line map rendering
```
~/github/swarm$ scripts/play.sh map data/scenarios/Challenges/ice-cream.yaml
              
              
              
              
           OO 
▒▒▒ ▒▒▒▒  OOOO
┌─┐▒┌──┐  MMMM
│B   V6│  \ZZ/
└──────┘   \/ 
```

and
```
stack run -- map data/scenarios/Challenges/hackman.yaml
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒••••••••••▒••••••••••▒
▒o▒▒▒•▒▒▒▒•▒•▒▒▒▒•▒▒▒o▒
▒•▒▒▒•▒▒▒▒•▒•▒▒▒▒•▒▒▒•▒
▒•••••••••••••••••••••▒
▒•▒▒▒•▒•▒▒▒▒▒▒▒•▒•▒▒▒•▒
▒•••••▒••••▒••••▒•••••▒
▒▒▒▒▒•▒▒▒▒ ▒ ▒▒▒▒•▒▒▒▒▒
    ▒•▒         ▒•▒    
▒▒▒▒▒•▒ ┌──=──┐ ▒•▒▒▒▒▒
     •  │     │  •     
▒▒▒▒▒•▒ └─────┘ ▒•▒▒▒▒▒
    ▒•▒         ▒•▒    
▒▒▒▒▒•▒ ▒▒▒▒▒▒▒ ▒•▒▒▒▒▒
▒••••••••••▒••••••••••▒
▒•▒▒▒•▒▒▒▒•▒•▒▒▒▒•▒▒▒•▒
▒o••▒•••••••••••••▒••o▒
▒▒▒•▒•▒•▒▒▒▒▒▒▒•▒•▒•▒▒▒
▒•••••▒••••▒••••▒•••••▒
▒•▒▒▒▒▒▒▒▒•▒•▒▒▒▒▒▒▒▒•▒
▒•••••••••••••••••••••▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

```
2023-09-15 06:11:47 +00:00
Ondřej Šebek
2fe7181fc4
Allow specific format width (#1476)
* 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.
2023-08-28 19:11:26 +00:00
Ondřej Šebek
09f8aee9fc
Make CLI format format (#1459)
- closes #1185
2023-08-26 17:47:17 +00:00
Karl Ostmo
03a5f14694
CLI option to set initial speed (#1255)
When supplying initial code with `--run` or `--autoplay`, a lot can happen in the first few moments of play such that it can be a tricky feat to smash CTRL+z fast enough to slow down the game to observe.

Now, one can pass e.g. `--speed 0` to begin the game at 1 tick per second:

    scripts/play.sh --scenario data/scenarios/Challenges/maypole.yaml --autoplay --speed 0
2023-05-14 04:00:14 +00:00