swarm/data
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
..
scenarios Capability exercise cost (#1777) 2024-04-25 19:39:54 +00:00
schema Capability exercise cost (#1777) 2024-04-25 19:39:54 +00:00
test/language-snippets Record best code size (#974) 2023-05-02 07:06:01 +00:00
worlds infinite improbability drive device enabling teleport command (#1724) 2024-01-14 00:31:12 +00:00
about.txt Update about to 2023 (#1384) 2023-07-20 13:04:56 +00:00
adjectives.txt Use a new opaque type for robots instead of strings (#303) 2022-03-02 03:00:44 +00:00
entities.yaml infinite improbability drive device enabling teleport command (#1724) 2024-01-14 00:31:12 +00:00
logo.txt switch from U+2591 Light Shade to U+2592 Medium Shade (#449) 2022-06-20 17:56:55 +00:00
names.txt Use a new opaque type for robots instead of strings (#303) 2022-03-02 03:00:44 +00:00
recipes.yaml infinite improbability drive device enabling teleport command (#1724) 2024-01-14 00:31:12 +00:00
terrains.yaml extensible terrain (#1775) 2024-02-29 06:22:21 +00:00