Provide a new `atomic` construct; when a robot is executing `atomic c` it is guaranteed that no other robots will execute any commands while the robot is executing `c`. Maybe this isn't all that plausible physically, but I guess we can imagine that the base is in communication with all robots and implements some kind of global lock mechanism.
- Closes#479. `grabif`, `harvestif`, and `placeif` can all be implemented simply in terms of `atomic`. For example:
```
def grabif : string -> cmd bool = \thing.
atomic (
b <- ishere thing;
if b {grab; return true} {return false}
)
end
```
```
def placeif : string -> cmd bool = \thing.
atomic (
res <- scan down;
if (res == inl ()) {place thing; return true} {return false}
)
end
```
- The argument to an `atomic` block must have type `cmd a` for some type `a`.
- `atomic` blocks have some restrictions to ensure they can't run for a long time:
- No `def`, `let`, or lambdas are allowed
- Variables can only be referenced if they are bound locally or have a "simple type" (= sums and products of base types; no `cmd`, `delay`, or function types)
- Taken together, these ensure that computations can't be duplicated, and any variables referenced must contain simple data values which have already been evaluated, which means that an argument to `atomic` will have an execution time no more than linear in its length.
- `atomic` blocks also can't be nested, just because that seems weird and I don't know what the purpose would be
- `atomic` blocks may contain at most one "external" command which normally requires a tick to execute. Allowing *e.g.* multiple `move` commands in an `atomic` block would be problematic: it would either mean that robots could use `atomic` blocks as a way to execute faster than normal, or that we would have to freeze other robots for multiple ticks while some robot executed its atomic block. But typically, we want to do some kind of sensing command (which is an internal command that doesn't require a tick) + some external command.
- Relatedly, also refactored the notion of external/internal commands so that information is now stored in the `ConstInfo` record. This means from now on we will be required to declare whether each new constant is internal or external; we hadn't been keeping up with the old definition of `takesTick` at all.
- Add the `rubber band` device which allows doing `atomic`, and make a recipe for it (`rubber` + `strange loop`).
- This is a fairly simple recipe, but being able to do `atomic` early can be helpful for setting up automatic resource production pipelines.
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.
When the prompt was blank, it didn't tab complete; however, when there
were any characters typed at all, it found the "last word" (all
identifier characters at the end) and tried to match on it. However,
if there were no identifier chars, the resulting empty "last word"
matched everything.
This fix now has a special case to check whether the `lastWord` is
blank, which also takes care of the original special case when the
prompt is completely empty.
Fixes#518.
Fixes#528. I was being silly. No user will pass `--flag=swarm:ci`
when building with `stack`; I was doing so locally to get `-Werror` but
there's no particular reason I need to do that.
Just tweak the description for the GPS device so its hash changes, and
hence the order of the `GPS` and `Tardis` entities in a `Set Entity`
of devices that provide the `senseloc` capability. When `GPS` comes
first, it will be chosen to provide the capability instead of
`Tardis`.
Make a new `harvester` device + `harvest` command. The recipe for a `harvester` is 2 `board` + 2 `wooden gear` + 1 `box`, hence it can be made completely out of 3 `tree`s. (3 trees make 12 `board`s; 6 `board`s are for the `box`, 4 are to make the 2 `wooden gear`s).
The `harvester` device provides the `harvest` and `grab` capabilities, hence it supports both the `harvest` and `grab` commands.
The `harvest` command now does exactly what the `grab` command used to do; the `grab` command works identically except that it never leaves behind a growing seed.
As an aside, I am actually not sure what happens if you try to `build` a robot that uses both `grab` and `harvest` (but none of the other capabilities provided by a `grabber`). Is the capability analysis smart enough to realize that it should just install a `harvester`, or might it end up installing both a `harvester` and a `grabber` unnecessarily?
Closes#490 (I split out another part of that issue into #502). @xsebek , I know in #490 you expressed an objection to adding a `harvester` device so I'm curious what you think about this.
- Tab no longer cycles between panels (closes#316). Now that we have keyboard shortcuts *and* you can click to move the panel focus, that seems sufficient.
- Basic REPL tab completion (closes#207). Currently tries to complete against all reserved words and all in-scope names. Cycles through multiple completions when hitting Tab repeatedly.
- `I/O cable` device (idea: for communicating with adjacent robots; still need to design some commands to go with it)
- recipe for `grabber` device
- add `flash memory` recipe, adjust recipe for `counter`. Closes#498 .
- add `3D printer` recipe. Closes#496 .
- Progress towards #116 :
- add `paper` and `PhD thesis` entities.
- add `printer` device and recipe.
- Add recipe for `dictionary`.
- Always have `uiMenu` store the current menu; while playing, it represents the menu we should return to if we quit
- Get rid of `uiPrevMenu` which is thus no longer needed
- `NoMenu` is now only used to represent the scenario when we started via command-line options and thus should not return to a menu when we quit
- Add `uiPlaying` to denote whether we are playing the game or displaying a menu (`NoMenu` used to be used for this purpose)
- Only advance to the next scenario in the menu when actually completing the previous one. For example if we start a scenario then quit before completing it, the menu will still be highlighting the same scenario. But if we complete a scenario and then quit to the menu, the next one will be highlighted.
- Closes#355. As [explained in a comment there](https://github.com/swarm-game/swarm/issues/355#issuecomment-1166343849), I think true "meta-scenarios" as originally described are needlessly complex. This PR gives us something that should be good enough: scenarios that have win conditions, placed in the same folder, can now be played sequentially without ever returning to the menu in between.
- Put the robot doing the checking in the robot map so it (or other
robots) are able to look it up. Fixes#504.
- Execute the win condition check *hypothetically*, in a copy of the
game state which is discarded afterwards. I kind of can't believe
we weren't already doing this. It used to be possible for the win
condition check to actually modify the world! Thankfully none of
the current tests actually used this evil power.
The action presently runs twice because both `on` conditions matche
every contributions. With this change, the push action only triggers
for the final push to the main branch, and the pull_requeste action
only triggers for PR made for the main branch.
That also means restyled PR should not trigger CI as they are made
for non main branches.
This change adds a new help panel with the list of recently acquired commands. The panels currently shows `command name :: command type signature`, for each newly available command.
Fixes https://github.com/swarm-game/swarm/issues/436
- 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
```
When adding an `FUnionEnv` frame to the stack, if there is already
another `FUnionEnv` frame present, combine them into a single
`FUnionEnv` instead of pushing another one.
Fixes#468.
- Reset REPL state when starting a new game.
- Change creative mode cheat shortcut to `^V`, so `^K` can again be used in the REPL to delete everything from the cursor position to the end of the line.
- remove `raise` command
- rename `error` to `fail` - should suggest both that it is:
- recoverable - can be caught with `try`
- pure - `fail: string -> a` - so it can be used outside `cmd`
---
The problem with `raise` was that it was merely a specialized version of `error` (which was not limited to `cmd a`):
```
let raised: string -> cmd a = error in raised "ha"
```
I noticed this while making the list for #26.
On a meta-level, it also conflicts with the `raise` Haskell function we use to throw an error when a command (like `build`) fails.
This PR solves #85. It's still a little bit rough since it only shows the last entry in history with the given text.
The solution if found is making the prompt a sum type. This allow to handle reple events differently depending on which mode the repl is. I've found this more difficult to implement than expected. The main problems I've found are
- `UIState` is a huge data type. Maybe putting al repl-related stuff within the same record could improve things a little bit
- I think we can define a more complex Lenses, like `promptUpdateL` which can handle many parts of the logic. I think this is better than having a huge `handleREPLEvent` function.
All of this would imply a big refactor tough.
When grabbing entities that have `yield` property, I want to use what I obtained.
But `t <- grab` would give me "wavy water" instead of "water".
I noticed this because of our hack with known entities, which also use yield (#387).
And also enable modal view toggle using the same key.
* Unpause the game after quitting a modal with Esc
* Handle FKey event before `uiModal` event to enable toggle through Fkey
Some terminals (*e.g.* `gnome-terminal`) use the character to decide
how dark or light the color should be, rather than showing the
character itself (like *e.g.* `rxvt-unicode`). Light Shade looks OK
in terminals that display the actual character, but too dark in
terminals that use it as a brightness hint. Medium Shade seems to
look good (at least, IMO) in both.
See https://github.com/swarm-game/swarm/issues/196#issuecomment-1147298159 .