This change introduce a new web API for the game.
The initial goal is to expose the internal state using the
`/robots` and `/robot/$id` endpoint to query the json representation
of the robots.
A new command line argument is added:
- When `--port 0` is set, the web service is disabled.
- When `--web port` is set, the game won't start if the web service fail to bind the port.
- Otherwise, when `--web` is not set, the service may start on 5357 if the port is available.
Example usage:
```
swarm --web 5357
curl localhost:5357/robots | jq
```
Future improvement may include:
- Ability to load program to the base (to send command from external text editor)
- Serve a html interface for alternative visualization
Add new special syntactic forms `require <string literal>` to require a device to be installed, and `require <int literal> <string literal>` to require a certain number of a given entity in the inventory.
- Replace `Set Capability` with a new `Requirements` type which records various types of requirement.
- Refactor requirements checking into a new function `checkRequirements` which also does device set minimization (#508).
- `reprogram` will now install extra devices or transfer extra inventory as necessary.
- Add a bunch of tests.
- Add new `installed` command, similar to `has`, which checks whether a given device is installed.
Closes#201.
Closes#508.
- add `generate` subparser to the executable
- create a generator for a Graphviz entity dependencies graph
- part of #344
You can interactively test this with:
```bash
$ cabal run swarm:swarm -- generate recipes \
| sed -n '/^digraph/,$p' > docs/recipes.dot
$ xdot docs/recipes.dot
```
- add winning solutions to scenarios
- test the winning solutions
- fail if any robot has a `Fatal error` in its log
- timeout in X seconds (default 1)
- add a Testing scenario collection hidden without the `--cheat` flag
- add a test case for #394
- closes#388
* Fix doctests
* Regenerate haskell-ci with config
- use latest haskell-ci
- configure haskell-ci to use doctest
* Update tested with compiler
- update cabal tested-with field
- update .mergify.yaml to new compiler
- restore note about mergify in haskell-ci
Generalize challenges + various modes to all be "scenarios" which are described by `.yaml` files in `data/scenarios`.
- Both challenges and classic/creative modes are now subsumed under the more general notion of "scenarios".
- A scenario describes how to set up the world etc. when starting a game; all scenarios are stored in a `.yaml` file in `data/scenarios`.
- "New game" menu item now lets the user choose a scenario.
- Some small improvements to the way seeds are handled.
See #296. This will enable #35 and #25 .
Lots of refining, adding more menu options, etc. that still needs to happen, but this adds a basic menu. Quitting a game now quits to the menu rather than quitting the entire application.
The basic idea of this change is to create a new `robot` type and use it to identify robots instead of `string` names. Internally, a `robot` value is just a (unique) `Int`.
Closes#212 .
This ended up turning into a sort of constellation of related changes.
- Add the `robot` type and change the type of various built-in functions which used to take a robot name so they now take a `robot` (`give`, `install`, `reprogram`, `view`, `upload`) and change `build` so it returns a `robot`.
- All internal data structures that store robots are now keyed by a unique (`Int`) robot ID rather than by name.
- Add a `setname` command for setting a robot's display name (which no longer needs to uniquely identify a robot).
- Import a big list of words which we can use to randomly pick names for robots, just for fun. This is why the diff says "+31,050 -265"; I did not write 31 thousand lines of code.
- Add constants `base`, `parent`, and `self` for getting a `robot` value referring to the base, one's parent, and one's self, respectively.
- Top-level binders like `r <- build {move}` now export a variable binding which can be used in later expressions entered at the REPL; additionally, unlike Haskell, a binder can now appear as the last statement in a block.
- Fix the pretty-printer for `Value` by doubling down on our current strategy of injecting `Value`s back into `Term`s and then pretty-printing the result. I am now convinced this is the Right Way (tm) to do this; it only required adding a couple additional kinds of `Term` which represent internal results of evaluation and cannot show up in the surface language (`TRef`, `TRobot`).
- Update the tutorial.
- While updating the tutorial, I noticed that #294 had introduced a bug, where the inventory display no longer updated when 0 copies of an entity are added to the inventory (as with `scan` + `upload`), so I fixed that by changing the way inventory hashes are computed.
I tried running the benchmarks both before & after this change. I was hoping that it might speed things up to be using `IntMap` and `IntSet` instead of looking things up by `Text` keys in a `Map` all the time. However, if I'm interpreting the results correctly, it seems like it didn't really make all that much difference, at least for the particular benchmarks we have.
The hash for an inventory is now the sum of the hashes of its contents. As discussed in #229 , the point of this is that inventory hashes can now be maintained incrementally, which could be a big win if there are robots with big inventories. It is less "secure" but we don't really care about that.
Closes#229.
- fixes#136
- changes the history file format to simple text line per `REPLEntry`
- refactors out a `REPLHistory` type and its pure functions
- adds tests for REPL logic (move to different previous entry,...)
Make explicit in the type system when evaluation of a computation should be delayed. This gives the user fine-grained control over selective laziness (for example, once we have sum types and recursive types, one could use this to define lazy infinite data structures). It also allows us to guarantee that certain commands such as `build` and `reprogram` delay evaluation of their arguments, and lets the user e.g. define their own modified versions of `build` without compromising those guarantees.
- Delay is indicated by curly braces both at the value and type levels, that is, if `t : ty` then `{t} : {ty}`.
- `force : {ty} -> ty` is now exposed in the surface language.
- Change from a CEK machine to a CESK machine. Recursive `let` and `def` delay via allocating a cell in the store. For now, there is no other way to allocate anything in the store, but see discussion at #150 for some possible future directions.
- change the types of `build` and `reprogram` to require a delayed program, e.g. `build : string -> {cmd a} -> cmd string`
- `if` and `try` also require delayed arguments.
- don't elaborate Build and Reprogram with extra Delay wrappers since one is now required by the type
- Division by zero, negative exponents, and bad comparisons now throw exceptions.
Closes#150. Closes#226.
Resolves#228.
I've redefined the missing lens operators in `Utils.hs` in order to keep the diff of the function bodies minimal. Hopefully that will make merges and rebases less painful. Most of the type signatures are modified though, we can't avoid this.
Closes#180
Add `Integration.hs` which reads files from `example` folder and runs `processTerm` on the contents. The test passes if creating a term is successful.
Currently only one example i.e. `zigzag.sw` is failing.
Adds sum types (e.g. `int + bool`) along with constants `inl : a -> a + b`, `inr : b -> a + b`, and `case : a + b -> (a -> c) -> (b -> c) -> c`.
I considered whether to automatically wrap the arguments to `case` in `delay`, like the arguments to `if`, but they are already functions anyway so we get a lot of laziness for free. It would only make a difference if you wrote something like `case foo (let x = blah in \y. ...) (...)` in which case the `let x = blah` is going to be evaluated eagerly, *before* we know which branch we are going to take. I don't think it's worth bothering about. In the normal case that you write `case foo (\y. ...) (\z. ...)` then only one of the two functions gets run at all, without us having to do anything special with `delay`.
I also considered whether to make special syntax for case expressions, like `case foo of { inl x -> ... ; inr y -> ... }` but doing it as a simple built-in function is both easier to implement and feels like it fits better with the aesthetic of the language so far.
Closes#46 .
This change improves the user experience when editing swarm code outside of the REPL with:
- CLI for a `format` command to quickly parse and type check a file.
- Basic LSP server to provide IDE feedback on save, e.g. visual squiggly for errors.
- Initial emacs mode.
Fixes#82#110
The `tmQ` quasiquoter now runs the entire processing pipeline on a
term instead of only parsing. This is 100% better since now the
typechecking will fail at compile time instead of runtime. I'm very
glad I took the time to figure out how to make this work. In the end
it wasn't that difficult, but it did require making a bunch more
`Data` instances for things, and adding cases for `TAntiString` in
more places (e.g. the typechecker and capability checker), since now
an antiquoted string variable has to go all the way through the
pipeline before finally getting a Haskell variable substituted for it
when the resulting `ProcessedTerm` is lifted into an AST.
Now do a variable number of ticks per frame, depending on how long it
took to draw the previous frame. This means we always maintain the
target ticks/second rate, regardless of the actual frame rate.
Logic taken from https://gafferongames.com/post/fix_your_timestep/ .
Still to do is to somehow deal with the "spiral of death" mentioned in
that post, which I have in fact observed when pushing the tick/s rate
high enough.