Add SITREP inspection feature#19
Conversation
Lay the Archetype-side groundwork for the situation report feature: - Extract 'ROLL CALL' as a reusable method on main, called after initialization and after each turn's events - Add 'INVENTORY NAMES' message to list_inventory, which gathers inventory item names into a list without printing them - Refactor 'INVENTORY' to use 'INVENTORY NAMES' internally, so the name-gathering and display logic are separated - Add 'SITREP' method on main that assembles exits, visible objects, and inventory as a structured PairValue list of key-value pairs - SITREP is not called automatically; it is available on demand Rewrite inspect_universe for proper RDF/Turtle output The --inspect flag now produces well-formed Turtle with: - Proper prefixes: archetype:, type:, object:, attr:, msg:, xsd: - Attribute values rendered via asRDF() (e.g., attr:desc "dank cellar") instead of just listing attribute names - Type hierarchy via rdfs:Class and rdfs:subClassOf - Instance typing via rdf:type (Turtle 'a' shorthand) - Vocabulary: verb/noun phrases as archetype:verbPhrase and archetype:nounPhrase predicates on each object - Proximate objects as archetype:proximate on archetype:situation - Methods (--full flag): archetype:respondsTo msg:MESSAGE_NAME with URI-encoded message names Without --full, only object identity, types, and attribute values are emitted — this is the "state-only" view suitable for external parsers or AI systems that need to understand the game situation without knowing the internal method implementations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> The SITREP must contain the same information a SystemParser uses: actual object references, not human-readable strings. A consuming program needs to know that the exit is object:south (an Archetype object it can reference), not the string "south". - Add 'INVENTORY OBJECTS' message to list_inventory, which gathers member objects (filtered by visibility) as a list of ObjectValues - Change 'SITREP' to use 'INVENTORY OBJECTS' instead of 'INVENTORY NAMES' for exits, visible objects, and inventory - Add player.location as the "location" key - Add it.referent as the "it" key when a pronoun is set The existing 'INVENTORY NAMES' and 'INVENTORY' (display) paths are unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Use type:/obj: prefixes to distinguish prototypes from instances Replace per-type instance prefixes (room:, wearable:, etc.) with a single obj: prefix for all instances. The type relationship is already captured by rdf:type triples, so encoding it in the URI is redundant. This gives a clean two-prefix scheme: type: for prototypes, obj: for instances. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Add TestInspectUniverse test suite Covers class/type emission for null-parent and typed instances, Turtle well-formedness of the vocabulary block (no stray leading semicolon), and the proximate list (no stray leading comma). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Brackets: list literals now use [...]; {...} is exclusively a compound
statement. Parser, PairValue::display, intrptr.arch sources, and tests
updated. See list_design.md for the rationale (spreadsheet-model
preservation, ending the list/block homoglyph).
REPL: results now print as `=> value` using display() only. Dropped the
trailing stringConversion tail, which duplicated scalar output (`8 8`)
for values whose display and string forms happen to match. Matches
Python/Ruby/Lisp convention.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR lays groundwork for a “SITREP” (situation report) feature and modernizes the --inspect output to emit RDF/Turtle, alongside a syntax change for Archetype list literals from {} to [].
Changes:
- Add an optional
--sitreppath to--updateto append a structured situation report (SITREP + parser context). - Rewrite
--inspectto emit Turtle with richer type/attribute/method modeling and parser vocabulary/proximity output. - Introduce
Value::asRDF()and switch list literal display syntax from{}to[], with updated/added tests.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/update_universe.hh | Extends update_universe API to optionally append sitrep output. |
| src/update_universe.cc | Implements sitrep emission and parser-context dump after UPDATE. |
| src/main.cc | Adds --sitrep and --full flags and wires them into update/inspect flows. |
| src/inspect_universe.hh | Extends inspect_universe signature with include_methods toggle. |
| src/inspect_universe.cc | Rewrites inspection output as Turtle with prefixes, types, attributes, methods, and parser vocabulary/proximity. |
| src/Value.hh | Adds asRDF() to the Value interface and concrete value types. |
| src/Value.cc | Implements asRDF() for values and updates PairValue display + RDF rendering. |
| src/TestValue.cc | Updates list display expectations to the new [] syntax. |
| src/TestInspectUniverse.hh | Adds a new test suite for Turtle output structure. |
| src/TestInspectUniverse.cc | Adds tests for type output and Turtle syntax constraints for vocabulary/proximity. |
| src/TestExpression.hh | Adds tests for list literal parsing and REPL output formatting. |
| src/TestExpression.cc | Implements list literal parsing tests and REPL display regression test. |
| src/SystemParser.hh | Updates friend declarations to match new inspect signature and sitrep helper. |
| src/SystemObject.hh | Updates friend declarations to match new inspect signature and sitrep helper. |
| src/ReadEvalPrintLoop.cc | Adjusts REPL output formatting to => <display> only. |
| src/Object.hh | Updates inspect_universe friend declaration signature. |
| src/Expression.cc | Switches list literal parsing from {} to []. |
| src/CMakeLists.txt | Adds new TestInspectUniverse to the build. |
| games/intrptr.arch | Adds ROLL CALL and SITREP methods and refactors inventory listing; updates list literal usage to []. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| << "@prefix archetype: <schema/> .\n" | ||
| << "@prefix type: <type/> .\n" | ||
| << "@prefix obj: <object/> .\n" | ||
| << "@prefix attr: <attr/> .\n" | ||
| << "@prefix msg: <msg/> .\n\n"; |
There was a problem hiding this comment.
The PR description calls out object: as a prefix, but the emitted Turtle declares @prefix obj: <object/> and all instances use obj:. If external tooling/docs expect object:, this will be a breaking change; either switch back to object: or update the PR description and any downstream expectations consistently.
| // -- Vocabulary: parser state -- | ||
|
|
||
| ObjectPtr systemObject = Universe::instance().getObject(Universe::SystemObjectId); | ||
| SystemObject* system_object = dynamic_cast<SystemObject*>(systemObject.get()); | ||
| assert(system_object != nullptr); | ||
| // What verb and noun phrase match what objects? | ||
| // We need to turn the parsing inside out here; the parsed matches are sorted | ||
| // from longest to shortest, not arranged by object. | ||
| SystemObject* system = dynamic_cast<SystemObject*>(systemObject.get()); | ||
| assert(system != nullptr); |
There was a problem hiding this comment.
inspect_universe(..., include_methods=false) still emits the vocabulary and proximate-object sections unconditionally. The PR description says the non---full output should be “state-only” (identity/types/attribute values only). If that contract is intended, gate the vocabulary/proximity emission behind include_methods (or a separate flag) so default --inspect stays minimal and machine-friendly.
| if (sitrep and not Universe::instance().ended()) { | ||
| try { | ||
| Value sitrep_val = dispatch_to_universe("SITREP"); | ||
| result += "SITREP " + sitrep_val->asRDF() + "\n"; | ||
| } catch (const std::exception&) { | ||
| // SITREP not available; silently skip | ||
| } | ||
| result += sitrep_parser_context(); | ||
| } |
There was a problem hiding this comment.
With --sitrep, the appended lines use prefixed names (obj:, type:, archetype:, xsd:) but the output does not include any @prefix declarations (and lines like SITREP ..., PROXIMATE (...) are not valid Turtle triples). If this is meant to be parseable RDF/Turtle as the help text suggests, consider emitting the same prefix block as --inspect (or full URIs) and output valid Turtle statements (e.g., triples) rather than custom labels.
| try { | ||
| Value sitrep_val = dispatch_to_universe("SITREP"); | ||
| result += "SITREP " + sitrep_val->asRDF() + "\n"; | ||
| } catch (const std::exception&) { | ||
| // SITREP not available; silently skip |
There was a problem hiding this comment.
Calling dispatch_to_universe("SITREP") will create a new message ID via Messages.index() if the saved game doesn’t already contain that message name. Even if SITREP is unavailable and you “silently skip”, the universe is still mutated and then re-serialized (out << Universe::instance()), potentially changing the saved file just because --sitrep was requested. To avoid this, use a non-mutating lookup (e.g., Messages.find() + error) when sending optional messages like SITREP.
| try { | |
| Value sitrep_val = dispatch_to_universe("SITREP"); | |
| result += "SITREP " + sitrep_val->asRDF() + "\n"; | |
| } catch (const std::exception&) { | |
| // SITREP not available; silently skip | |
| if (Messages.find("SITREP") >= 0) { | |
| try { | |
| Value sitrep_val = dispatch_to_universe("SITREP"); | |
| result += "SITREP " + sitrep_val->asRDF() + "\n"; | |
| } catch (const std::exception&) { | |
| // SITREP failed at runtime; silently skip | |
| } |
| // Look up the identifier name bound to an object, or empty string if none. | ||
| static std::string identifier_of(int object_id) { | ||
| for (auto const& p : Universe::instance().ObjectIdentifiers) { | ||
| if (p.second == object_id) { | ||
| return Universe::instance().Identifiers.get(p.first); | ||
| } | ||
| } | ||
| return ""; | ||
| } |
There was a problem hiding this comment.
identifier_of() linearly scans Universe::instance().ObjectIdentifiers on every ObjectValue::asRDF() call. In RDF export paths (inspect + sitrep), this can become O(N^2) for large universes with many object references/attributes. Consider building a reverse map once (object_id -> identifier_id) and reusing it, or adding an efficient reverse lookup facility to Universe.
| << " --input=<string> In combination with --update, provide command input as a string." << endl | ||
| << " --sitrep In combination with --update, append a situation report (RDF/Turtle)." << endl | ||
| << " --inspect=file.acx Load a saved binary file and dump its contents as RDF/Turtle." << endl |
There was a problem hiding this comment.
The --sitrep usage string claims the appended report is “RDF/Turtle”, but the current --sitrep output path doesn’t emit Turtle prefixes/triples (it prints labeled collections like SITREP (...), PROXIMATE (...)). Either adjust the help text to describe the actual format, or update the output to be well-formed Turtle so users can pipe it directly into RDF tooling.
| // Attributes: flat view with evaluated values | ||
| for (auto const& attr : obj->attributes_) { | ||
| // Archetype has an endearing (sigh) way of instantiating any attributes that have even been | ||
| // observed with UNDEFINED. This is one reason why saved games have greater size. | ||
| const bool hide_undefined = true; | ||
| auto value = dynamic_cast<const ValueExpression*>(attr.second.get()); | ||
| if (!hide_undefined or (value and value->evaluate()->isDefined())) { | ||
| out << " ; prop:hasAttribute attr:" << Universe::instance().Identifiers.get(attr.first) << '\n'; | ||
| Value value = attr.second->evaluate(); | ||
| if (value->isDefined()) { | ||
| out << "\n ; attr:" << Universe::instance().Identifiers.get(attr.first) | ||
| << " " << value->asRDF(); | ||
| } |
There was a problem hiding this comment.
inspect_universe currently evaluates every attribute expression (attr.second->evaluate()) without setting self/context and without guarding against non-literal expressions. This can produce incorrect values (wrong context), trigger side effects, or even mutate game state during inspection. Consider limiting inspection to ValueExpression-backed attributes (as before), or setting a ContextScope with selfObject = obj and ensuring evaluation is side-effect-free before calling evaluate().
Add the ability to produce RDF report of ACX file, a "SITREP" or "SITuation REPort". This is not only the state of the objects in the game, but proximity and vocabulary. It is intended to be enough information to understand the game state without having to read binary ACX.
Lay the Archetype-side groundwork for the situation report feature:
initialization and after each turn's events
inventory item names into a list without printing them
name-gathering and display logic are separated
and inventory as a structured PairValue list of key-value pairs
Rewrite inspect_universe for proper RDF/Turtle output
The --inspect flag now produces well-formed Turtle with:
instead of just listing attribute names
archetype:nounPhrase predicates on each object
with URI-encoded message names
Without --full, only object identity, types, and attribute values are
emitted — this is the "state-only" view suitable for external parsers
or AI systems that need to understand the game situation without
knowing the internal method implementations.
As part of this work, change the Archetype list literal syntax to use square brackets instead of curly braces; the latter worked but was visually easy to confuse with compound statements.