Commit Graph

1175 Commits

Author SHA1 Message Date
Brent Yorgey
4ec9770d6f
mergify: forgo 'Enforce issue references' for non-.hs (#1265)
Closes #1264.
2023-05-16 13:12:24 -05:00
Karl Ostmo
0e286c0133
Pig capturing scenario (#1258)
scripts/play.sh --scenario data/scenarios/Challenges/capture.yaml

![Screenshot from 2023-05-13 15-17-31](https://github.com/swarm-game/swarm/assets/261693/f849a946-f51a-4f49-abd6-c2b59448c3db)
2023-05-15 22:34:58 +00:00
Karl Ostmo
167a797d0f
canonical devices for push and watch (#1263) 2023-05-15 14:29:02 -07:00
Karl Ostmo
e040264070
decouple relative and absolute time capabilities (#1261)
`time` now requires `CTimeabs`, and `wait` now requires `CTimerel`.
Introduced a new `hourglass` device to provide `CTimerel` capability.

The `clock` device remains backward compatible, providing both relative and absolute time capabilities.
2023-05-15 19:27:31 +00:00
ussgarci
ea0f9135fc
Make panes collapsible (#1076)
Add Ctrl-s shortcut to collapse/expand REPL panel

closes #813
2023-05-15 18:26:33 +00:00
Brent Yorgey
4384e1b747
Better type variable names (#1252)
Uses type variable names like `a`, `b`, `c`, ... instead of using `aNNN` with numbers based on the internal numbers used for fresh type variables. Closes #1050.
2023-05-14 22:26:24 +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
Karl Ostmo
a6abebda52
Display higher clock resolution at lower speeds (#1253)
Useful for understanding what is happening in each tick.
2023-05-13 19:03:14 +00:00
Brent Yorgey
07fc47e619
Inventory search/filter mode (#1250)
When the inventory panel is focused, hit `/` to enter search mode (maybe "search" is a bit of a misnomer, it's really more of a "filter" mode).  Then type stuff to modify the current search term, shown at the bottom of the inventory panel.  You can still navigate the filtered inventory list with arrow keys etc. Hit Esc to exit search mode or Enter to pop out the focused item (and also exit search mode).

Closes #126.
2023-05-12 10:02:08 +00:00
Brent Yorgey
305867a58c
add new give tutorial (#1249)
Fixes #1086.
2023-05-12 09:45:35 +00:00
Karl Ostmo
271b485254
Do not show static when no robots exist in creative mode (#1248)
"Stub" maps generated by the World Editor (#873) do not define any robots.

It is convenient to view these via:

    scripts/play.sh --scenario stub.yaml --cheat

However, the static needs to be suppressed in creative mode when robots do not exist.
2023-05-07 23:16:13 +00:00
Karl Ostmo
f4776e25c6
reduce lag in monitor bot for Maypole scenario (#1244) 2023-05-05 12:32:53 -07:00
Karl Ostmo
6555a41274
Fix scenario menu update after quitting to menu (#1243)
Ensures that the "played" status and the "best scores" get updated in the scenario menu after "Quit to menu" is selected from within a scenario.

This bug appeared after merging #974.
2023-05-03 18:42:50 +00:00
Brent Yorgey
f2ae7dd6da
finer texture for static (#1241)
Closes #1145.

Instead of using simple black or white cells to display static, use cells with any one of the 16 possible arrangements of on/off quarter-blocks.  This makes static appear at almost 2x resolution as before (though there is still a bit of blockiness since the quarter-blocks can't occur independently). See https://asciinema.org/a/582095 for a demonstration.
2023-05-03 18:15:41 +00:00
Karl Ostmo
0e63c7afc1
Record best code size (#974)
towards #866

NOTE: #1116 should be merged first so that the schema change of save files is less disruptive.

## Examples

Different criteria can have their own best score:
![image](https://user-images.githubusercontent.com/261693/219904496-fcd23ca0-b208-43e1-afc6-188acfe327cf.png)

All criteria share the same single best score:
![image](https://user-images.githubusercontent.com/261693/219904553-abe3011c-41b0-469c-b34d-95d84b91697a.png)

## Behavior notes

* As currently designed, the code size will only be scored if the the player has specified their code **before** the scenario begins.  Furthermore, any input into the REPL will invalidate code size scoring for the current game.
* Because of this, the only way to score code so far is with a command-line argument of `--run` or `--autoplay`.  However, #1010  shall implement code size scoring when a scenario is launched from the UI.
* In the "best scores" display, if multiple "best score" criteria were all from the same game, they will be consolidated.  If all criteria are for the same game, the criteria labels will be omitted.
* The code size metrics will not be displayed if a "best score" was not obtained via `--run`.

## Caveats

### `run` command

Currently, the code entailed in a `run "somescript.sw"` command is not transitively included, so using `run` make the code size score meaningless.

## Testing

### Unit tests

Run the subset of unit tests:

    scripts/run-tests.sh --test-arguments '--pattern "Tests.Precedence"'

### Manual integration tests

First, reset the score:

    rm -f ~/.local/share/swarm/saves/Tutorials_grab.yaml

Saving the following to `grab-soln.sw`:
```
move;
move; grab; turn back; move; turn back; move;
move; grab; turn back; move; turn back; move;
move; grab; turn back; move; turn back; move;
move; grab; turn back; move; turn back; move;
move; grab; turn back; move; turn back; move;
move; grab;
```
Run as follows:

    scripts/play.sh --scenario Tutorials/grab.yaml --run grab-soln.sw

This should establish a record for code size.

Then, play the Grab tutorial and immediately paste and run this in the REPL:

    move; move; grab; move; grab; move; grab; move; grab; move; grab; move; grab;

This solution is faster in terms of time, but should not displace the code-length record, since no code length should be recorded from a REPL solution.
2023-05-02 07:06:01 +00:00
Karl Ostmo
8d2b523658
place hanoi files in subdirectory (#1236) 2023-04-29 14:49:47 -07:00
Karl Ostmo
da7190a0b4
Implement push command (#1235)
Closes #1234

A `"dozer blade"` is defined locally to provide `push` capability.  To decouple this PR from bikeshedding, will defer the definition of a global entity that offers `push` capability to another PR.
2023-04-29 20:57:55 +00:00
Karl Ostmo
2dddea136e
unrestricted variant of atomic (#1231)
Closes #1227.

Demo:

    scripts/play.sh --scenario data/scenarios/Challenges/word-search.yaml --autoplay
2023-04-29 16:23:51 +00:00
Karl Ostmo
5fd852461e
Immersive multimedia experience (#1233)
Emits a terminal beep upon winning or losing a scenario.
2023-04-29 15:52:36 +00:00
Brent Yorgey
e2b4eaa1da
mention unit and void types in ADT calculator description (#1226)
Closes #753.
2023-04-27 07:05:24 -05:00
Karl Ostmo
eb90bfbe9b
web api to parse, render, and run code (#1142)
Closes #625.

# Demo

## Running code

Start a creative game:

    scripts/play.sh --scenario data/scenarios/creative.yaml

In another terminal window:

    curl -H "Content-Type: text/plain; charset=utf-8" -i http://localhost:5357/code/run --data "move;"

Observe that the robot has moved, and that the command sent via `curl` has been added to the REPL history.

## Parsing and rendering code

Start swarm:

    scripts/play.sh

Run curl:

    curl --silent -H "Content-Type: text/plain; charset=utf-8"  -i http://localhost:5357/code/render --data @data/test/language-snippets/warnings/unused-vars/multiple-lambda-first-unused.sw

See output:
```
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Mon, 06 Mar 2023 10:16:12 GMT
Server: Warp/3.3.23
Content-Type: text/plain;charset=utf-8

def put = \x. \y. place y end
|
`- \x. \y. place y
   |
   `- \y. place y
      |
      `- place y
         |
         +- place
         |
         `- y
```
2023-04-25 21:15:40 +00:00
Karl Ostmo
ffafb8bfa6
implement stride command (#1219)
Closes #1218

    scripts/play.sh --scenario data/scenarios/Testing/1218-stride-command.yaml --autoplay

I decided to implement this command with the same exception behaviors as the `move` command.
If any obstructions exist on the path, then an exception is thrown and no movement is made.

The implications of this are:
1. With `try`, one can learn in `O(1)` time whether any obstructions exist along a line of up to 64 units long
2. One can learn in `O(log N)` time the exact distance of the nearest obstruction along that line.
2023-04-25 17:35:33 +00:00
Brent Yorgey
599225f4d6
Key input handler (#1214)
Ability to code your own input handler routines.  Closes #102 .  Fixes #1210 .

* Adds a new type `key` to represent keypresses
* Adds a primitive function `key : text -> key` which can handle usual letters, numbers, etc. as well as special keys like `"Down"` etc, as well as modifier key prefixes like `key "A-C-Del"`.  `swarm generate keys` generates a list of all recognized special key names.
* New command `installKeyHandler : text -> (key -> cmd unit) -> cmd unit` which sets the "current key handler".  The `text` value is a hint line to display in the secondary key hints menu while the handler is running.  The global shortcut `M-k` toggles the currently installed handler.
* Add a `keyboard` device to provide these commands, as well as a `key` entity (the recipe for a `keyboard` is 16 `key`s + 1 `board`).
* Add a few examples in the `examples` folder.
* Add an installed `keyboard` to the `building-bridges` challenge.
2023-04-25 16:39:59 +00:00
Karl Ostmo
11165df7c0
More efficient gopher solution using 'watch' (#1216)
Tested using:

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

| Before | After |
| --- | --- |
| 6.28s | 1.33s |
2023-04-25 16:15:57 +00:00
Brent Yorgey
7df691688f
Immediately flag world for redraw when scanning/uploading (#1225)
Executing `scan` or `upload` may change the way the world is drawn, so we need to flag a redraw.  Fixes #758.

I also included a few updated/improved comments I made while trying to understand various bits of code (though they were ultimately unrelated to this issue).
2023-04-25 15:25:41 +00:00
Karl Ostmo
593ac937cb
enforce no duplicate entity names (#1223)
Closes #1221.

New test added:

    scripts/run-tests.sh --test-arguments '--pattern 1221-duplicate-entities'
2023-04-25 14:35:40 +00:00
Karl Ostmo
b793bd074f
add integration test for 'resonate' command (#1217)
Towards #1171.  Forgot to add this in #1204.
2023-04-20 05:32:15 +00:00
Karl Ostmo
1795e12f21
scout command (#1209)
Closes #1207

This PR also involves some refactoring that simplifies more return values in `Step.hs` with `asValue`.
2023-04-18 20:35:38 +00:00
Karl Ostmo
9477c10096
Fix objective management upon goal condition exception (#1215)
Fixes #1205.

Bug has existed since #927.
2023-04-18 04:54:37 +00:00
Karl Ostmo
2e6207e4aa
Implement 'watch' and 'surveil' (#1201)
Closes #687

## Demo

    scripts/play.sh --scenario data/scenarios/Testing/687-watch-command.yaml --autoplay

or use `run` instead of `--autoplay`, and monitor the state:

    curl -s http://localhost:5357/robot/0 | jq ._watchedLocations
2023-04-16 21:53:58 +00:00
Brent Yorgey
079ca0574f
Fix brick-list-skip versions (#1213)
* less restrictive upper bound on `brick-list-skip`

* switch to `brick-list-skip-0.1.1.2` in `stack.yaml`
2023-04-16 13:19:22 -05:00
Karl Ostmo
ffbb303b94
use brick-list-skip package (#1211)
Closes #1127
2023-04-13 16:51:06 +00:00
Karl Ostmo
dc90996db1
resonate command (#1204)
Towards #1171

The `resonate` command counts entities of a given type within a rectangle.

This PR also fixes a bug in `detect` when the rectangle coords are non-ascending.
2023-04-09 04:13:11 +00:00
Karl Ostmo
9e0e6fa666
Autogenerate web api docs (#825)
The docs are viewable from URL path that isn't already defined, e.g.:

    http://localhost:5357/

As an minor update to #821, the CLI invocation to dump REPL commands is now:

    curl http://localhost:5357/repl/history/full | jq .[].in -r

Implemented by following [this tutorial](https://docs.servant.dev/en/stable/tutorial/Docs.html).

![Screenshot from 2023-04-02 12-40-38](https://user-images.githubusercontent.com/261693/229375261-9845f410-2e0b-4fb2-ad89-4367c8f62ca8.png)
2023-04-03 22:35:35 +00:00
Karl Ostmo
65e3f2b4fa
Dump a list of tutorials and commands they first introduce (#1186)
May be able to reduce likelihood of #1086 by having a autogenerated table of the commands and the tutorials they are introduced in.

This work is related to #1106 in that robot commands should be given distinct markup (backticks).

## Demo

    scripts/play.sh generate pedagogy

**Updated:** See [rendered output](https://gist.github.com/kostmo/d4af3a6814e65fc6d455fd34b41552d3).

## New tests

    scripts/run-tests.sh --test-arguments '--pattern "Pedagogical soundness"'

Note that the test for `crash.yaml` is currently failing because the `Give` command (and some others) are utilized in this tutorial without having been mentioned in the description or in earlier tutorials.

Additionally, the "bug" described in [this comment](https://github.com/swarm-game/swarm/issues/1089#issuecomment-1418497686) **should** be caught by these tests (i.e. fail the tests) since the embedded `solution` code in the YAML file utilizes the `give` command.  That is, if it currently weren't for [this issue](https://github.com/swarm-game/swarm/pull/1186/files#r1152789153).
2023-04-03 14:49:45 +00:00
Brent Yorgey
e17d97c537
requirements command for viewing requirements of any expression (#1183)
Add a special built-in command `requirements` which can be applied to any expression.  Typing `requirements e` at the REPL will cause a log message to be generated listing the requirements for the given expression.  For example, `requirements (move; grab)` generates
```
Requirements for `(move; grab)`:
  Equipment:
    - fast grabber OR grabber OR harvester
    - solar panel
    - tank treads OR treads
```

Closes #922 .
2023-04-02 20:43:21 +00:00
Karl Ostmo
a089bfac7d
prefer dots over dollars (#1190)
See [this comment](https://github.com/swarm-game/swarm/pull/974#discussion_r1112381178).
2023-04-02 20:24:03 +00:00
Karl Ostmo
2efa0534dc
fix inversion bug with skippable list refactor (#1196)
Should have done some manual testing before merging #1193.  Works properly after this fix.
2023-04-02 18:23:17 +00:00
Karl Ostmo
650bb1c846
Pedagogy separate refactoring (#1194)
Simplify #1186 by offloading some refactoring.

See [this comment](https://github.com/swarm-game/swarm/pull/1186#discussion_r1155155111).
2023-04-01 20:22:29 +00:00
Karl Ostmo
33838f8b57
Simplify skippable list api (#1193)
The purpose of this refactoring is to decouple the key mapping from imperative list movement instructions.  In the new API (a function named `navigateList`), one supplies a declarative mapping of key events to a sum type that represents the desired movement.

As a client of the API, one's code reduces to this:
```
navigateList isSep e $ \case
    V.EvKey V.KUp [] -> Single Up
    V.EvKey V.KDown [] -> Single Down
    V.EvKey V.KHome [] -> Multi Up Max
    V.EvKey V.KEnd [] -> Multi Down Max
    V.EvKey V.KPageUp [] -> Multi Up Page
    V.EvKey V.KPageDown [] -> Multi Down Page
    _ -> None
```
2023-04-01 19:33:56 +00:00
Karl Ostmo
6702a8b50d
introduce boolexpr package to replace vendored module (#1188)
Closes #934.
2023-04-01 17:46:27 +00:00
Karl Ostmo
9e2f8b2961
sniff/chirp commands (#1181)
towards #1171

## New tests

Unit tests:

    scripts/run-tests.sh --test-arguments '--pattern "Relative direction"'

Integration tests for `sniff` and `chirp` demonstrate how to home in on an item using distance and orientation, respectively.

## Efficiency

For the sake of execution time, I have capped the max "diameter" (`N`) of both commands to `200` cells.  In the worst case (the entity is not present), `O(N^2)` cells are inspected, which manifests as a perceptible delay when the command is run.  I came across the `getElemsInArea` function that seems to suggest that an `O(N * log N)` search may be possible.  Is that the case?

Otherwise we may be able to add some new data structures to the game state for efficient entity location querying.
2023-03-29 05:51:53 +00:00
Karl Ostmo
dc8c21a7f1
Whack-a-mole scenario (#1026)
![image](https://user-images.githubusercontent.com/261693/213905811-0bb70b7c-dff1-4345-b86e-e8b523a14eb5.png)
2023-03-25 23:07:28 +00:00
Brent Yorgey
ce923d5ddf
actually join with spaces in failT, not newlines (#1179)
Fix bug introduced in #1148 .  See https://github.com/swarm-game/swarm/pull/1148#discussion_r1148410290
2023-03-25 18:31:49 +00:00
Brent Yorgey
29c931d4c9
add GHC 9.4.2 build and todo check to requirements for merging (#1177) 2023-03-25 13:12:24 -05:00
Brent Yorgey
af92865727
get rid of XXX comment (#1178)
Let's not worry about using reserved words as record fields for now. It would technically work OK but I'm not sure how important it is.

See #1177 for the fix to the root issue that let this through the merge process.
2023-03-25 18:11:49 +00:00
Brent Yorgey
a4c8057a28
Records (#1148)
Add record types to the language: record values are written like `[x = 3, y = "hi"]` and have types like `[x : int, y : text]`.  Empty and singleton records are allowed.  You can project a field out of a record using standard dot notation, like `r.x`.  If things named e.g. `x` and `y` are in scope, you can also write e.g. `[x, y]` as a shorthand for `[x=x, y=y]`.

Closes #1093 .

#153 would make this even nicer to use.

One reason this is significant is that record projection is our first language construct whose type cannot be inferred, because if we see something like `r.x` all we know about the type of `r` is that it is a record type with at least one field `x`, but we don't know how many other fields it might have.  Without some complex stuff like row polymorphism we can't deal with that, so we just punt and throw an error saying that we can't infer the type of a projection.  To make this usable we have to do a better job checking types, a la #99 . For example `def f : [x:int] -> int = \r. r.x end` would not have type checked before, since when checking the lambda we immediately switched into inference mode, and then encountered the record projection and threw up our hands.  Now we work harder to push the given function type down into the lambda so that we are still in checking mode when we get to `r.x` which makes it work.  But it is probably easy to write examples of other things where this doesn't work.  Eventually we will want to fully implement #99 ; in the meantime one can always add a type annotation (#1164) on the record to get around this problem.

Note, I was planning to add a `open e1 in e2` syntax, which would take a record expression `e1` and "open" it locally in `e2`, so all the fields would be in scope within `e2`.  For example, if we had  `r = [x = 3, y = 7]` then instead of writing `r.x + r.y` you could write `open r in x + y`.  This would be especially useful for imports, as in `open import foo.sw in ...`.  However, it turns out to be problematic: the only way to figure out the free variables in `open e1 in e2` is if you know the *type* of `e1`, so you know which names it binds in `e2`.  (In all other cases, bound names can be determined statically from the *syntax*.)  However, in our current codebase there is one place where we get the free variables of an untyped term: we decide at parse time whether definitions are recursive (and fill in a boolean to that effect) by checking whether the name of the thing being defined occurs free in its body.  One idea might be to either fill in this boolean later, after typechecking, or simply compute it on the fly when it is needed; currently this is slightly problematic because we need the info about whether a definition is recursive when doing capability checking, which is currently independent of typechecking.

I was also planning to add `export` keyword which creates a record with all names currently in scope --- this could be useful for creating modules.  However, I realized that very often you don't really want *all* in-scope names, so it's not that useful to have `export`.  Instead I added record punning so if you have several variables `x`, `y`, `z` in scope that you want to package into a record, you can just write `[x, y, z]` instead of `[x=x, y=y, z=z]`.  Though it could still be rather annoying if you wanted to make a module with tons of useful functions and had to list them all in a record at the end...

Originally I started adding records because I thought it would be a helpful way to organize modules and imports.  However, that would require having records that contain fields with polymorphic types.  I am not yet sure how that would play out.  It would essentially allow encoding arbitrary higher-rank types, so it sounds kind of scary.  In any case, I'm still glad I implemented records and I learned a lot, even if they can't be used for my original motivation.

I can't think of a way to make a scenario that requires the use of records.  Eventually once we have proper #94 we could make a scenario where you have to communicate with another robot and send it a value of some required type.  That would be a cool way to test the use of other language features like lambdas, too.
2023-03-25 11:58:34 +00:00
Karl Ostmo
d52c36d05c
Display scenario for obtained achievement (#1175)
# Before
![image](https://user-images.githubusercontent.com/261693/227453439-b08afe02-07f1-40dd-9688-9d77dcef7989.png)
# After
![image](https://user-images.githubusercontent.com/261693/227454441-925cecf8-042c-46a6-8fd3-ef749ad50fad.png)
2023-03-24 17:35:01 +00:00
Karl Ostmo
7d7f291450
Achievement for disorientation (#1173)
Inspired by #1105

![image](https://user-images.githubusercontent.com/261693/227453439-b08afe02-07f1-40dd-9688-9d77dcef7989.png)
2023-03-24 17:23:02 +00:00
Karl Ostmo
51b4bcd0e0
hackman (#1135)
# Demo
    scripts/play.sh --scenario Challenges/hackman.yaml --autoplay
![image](https://user-images.githubusercontent.com/261693/221466237-84c4137e-f9d5-4723-85cd-a0ec301caa45.png)


Makes use of both #1058 and #1023.
2023-03-23 19:09:05 +00:00