JSON and Datomic-style Triples

Ugh, I need to explain the current implementation of JSON input in Dusa. So the only JavaScript logic I wrote for Day 2 was a big bundle of nonsense that splats the input apart into a JSON version of itself.

const INPUT = `
Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
`
  .trim()
  .split('\\n')
  .map((line) => line.slice(5).split(':'))
  .map((line) => ({
    game: parseInt(line[0]),
    data: line[1]
      .trim()
      .split(';')
      .map((draw) =>
        draw
          .trim()
          .split(',')
          .map((item) => item.trim().split(' '))
          .map(([number, color]) => ({ number: parseInt(number), color })),
      ),
  }));

That code produces JSON that looks like this from the inputs:

[
  {
    "game": 1,
    "data": [
      [
        { "number": 3, "color": "blue" },
        { "number": 4, "color": "red" }
      ],
      [
        { "number": 1, "color": "red" },
        { "number": 2, "color": "green" },
        { "number": 6, "color": "blue" }
      ],
      [{ "number": 2, "color": "green" }]
    ]
  },
  ...
]

Dusa’s JSON loading functionality automatically makes up a new constant for every object and list in the JSON data! Then every piece of information is stored as a record with three pieces of information:

  1. Generated to the object or array
  2. Index (strings for objects, ints for arrays)
  3. Representation of the data stored at that location, a string, int, array reference, or object reference.

The result is something like this, though the names of references generated in Dusa aren’t actually meaningful the way they are here.

**field ref       "game".  is 1.
field ref       "data"   is refData.
field refData   0        is refData0.
field refData   1        is refData1.
field refData   2        is refData2.
field refData0  0        is refData00.
field refData00 "number" is 3.
field refData00 "color"  is "blue".
field refData0  1        is refData01.
field refData01 "number" is 4.
field refData01 "color"  is "red".
field refData1  0        is refData10.
field refData10 "number" is 1.
field refData10 "color"  is "red".
field refData1  1        is refData11.
field refData11 "number" is 2.
field refData11 "color"  is "green".
field refData1  2        is refData12.
field refData12 "number" is 6.
field refData12 "color"  is "blue".
field refData2  0        is refData20.
field refData20 "number" is 2.
field refData20 "color"  is "green".**

This style of representation matches the “datoms” pattern used by Datomic, at least as taught in the Learn Datalog Today! tutorial of Datomic’s dialect of Datalog. It’s quite powerful, because it lets us throw basically arbitrary JSON into Dusa and work with it there.

Getting out cleaner information from triples

To solve the problem for Day 2, we’ll use facts of the form

**draw GameNumber DrawNumber Color is Number**

to represent that, in the DrawNumberth draw of game number GameNumber, we pulled out Number balls of the color Color.

The important pattern to think about when working with these Datomic-esque triples is that, in order to look up two fields of the same object, you look up two objects with different fields but the same object reference. So all related color and number combinations can be looked up with this pair of premises

   **field Ref "color" is Color,
   field Ref "number" is Number**

The rest of the game is just tracking down the correct intermediate references to get the following: