# Module 6 scenarios: Grid, lexer and parser Each heading is a test name. The Rust test lives in `tests/rust/test_06.rs` and the TypeScript test in `tests/ts/test_06.test.ts`; both state exactly what is written here. Part II has its own harness object, `Baba`, made by `newBaba(level)` from a level in the format of `course/schema/level.schema.json`: a `width`, a `height` and a list of `objects`, each `{kind, x, y}`. `x` grows right and `y` grows down. A kind is either an object (`"baba"`) or a word of text (`"text:BABA"`). `place(kind, x, y)` adds one more object to the level and returns its id. Several objects may share a tile. `rules()` returns every rule the board currently spells, as normalised strings such as `"BABA IS YOU"`, sorted, each distinct rule once. The base rule `"TEXT IS PUSH"` is always in it, although no text spells it. Duplicates are a real thing in the game (stacked text "will attempt to produce all possible rules", and a rule spelled twice can duplicate objects, see `docs/research/baba-is-you.md` §e), so the engine may hold the same rule more than once, but `rules()` is the set of distinct rules and no test counts duplicates. Words used: the nouns `BABA`, `ROCK`, `FLAG`; the properties `YOU`, `WIN`, `PUSH`, `STOP`; the operators `IS` and `AND`; the meta-noun `TEXT` (only through the base rule). Rules read left to right in a row and top to bottom in a column. A test writes a sentence as its words with their tiles: `BABA (0,0) IS (1,0) YOU (2,0)` is three text objects, `text:BABA` at x 0, y 0, and so on. ### test_06_horizontal_rule - Setup: `newBaba` with a level 5 wide and 3 high whose `objects` are, in this order: `BABA (0,0) IS (1,0) YOU (2,0)`; an object `baba` at (3,2); `YOU (0,2) IS (1,2) FLAG (2,2)`. - Action: none. The rules come from the level's objects. - Assertions: - `rules()` is exactly `["BABA IS YOU", "TEXT IS PUSH"]`. - Row 2 spells nothing: `YOU IS FLAG` has a property where a noun must start the sentence, and the parser never reads right to left (`FLAG IS YOU`). The `baba` object is not text and plays no part in parsing. ### test_06_crossword_shared_is - Setup: `newBaba` with an empty level 3 wide and 3 high. Place `BABA (0,1)`, `IS (1,1)`, `YOU (2,1)`, then `FLAG (1,0)`. - Assertions 1: `rules()` is exactly `["BABA IS YOU", "TEXT IS PUSH"]`. `FLAG` above `IS` is half a sentence. - Action: place `WIN (1,2)`. - Assertions 2: `rules()` is exactly `["BABA IS YOU", "FLAG IS WIN", "TEXT IS PUSH"]`. The `IS` at (1,1) is in a row sentence and a column sentence at once, and the rules were recompiled when the board changed. ### test_06_and_distributes - Setup: `newBaba` with an empty level 7 wide and 1 high. Place `BABA (0,0) AND (1,0) ROCK (2,0) IS (3,0) PUSH (4,0) AND (5,0) STOP (6,0)`. - Assertions: `rules()` is exactly `["BABA IS PUSH", "BABA IS STOP", "ROCK IS PUSH", "ROCK IS STOP", "TEXT IS PUSH"]`. AND distributes over both sides: two subjects times two complements is four rules. ### test_06_stacked_text_all_combinations - Setup: `newBaba` with an empty level 3 wide and 1 high. Place `text:BABA` at (0,0), then `text:ROCK` also at (0,0), then `IS (1,0)` and `YOU (2,0)`. - Assertions: `rules()` is exactly `["BABA IS YOU", "ROCK IS YOU", "TEXT IS PUSH"]`. Both stacked words start a sentence: the parser produces every rule the stack allows. ### test_06_default_text_is_push - Setup: `newBaba` with a level 3 wide and 3 high whose only object is a `baba` at (1,1). - Assertions: `rules()` is exactly `["TEXT IS PUSH"]`. No text spells it: it is a base rule of the game.