A Practical Advent of Code

by: Ethan McCue

I've never done more than a few days of Advent of Code.

I'm sure its fun if you're the kind of person who likes doing those sorts of puzzles, but that's not really what I'm into. My jam is really finicky, relatively small problems. Problems that everyone can reasonably do and could come up in real code, but where it's really hard to be happy with a solution.

So that's what this is. I'm starting three days in, and I'm nowhere close to prepared to give a challenge a day, but I want to share the sorts of problems that keep me up at night.

The Challenge

The following three samples of JSON come from the activity streams specification.

If you have misguided dreams of making the next Twitter, maybe you've looked at this too.

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "A note",
  "type": "Note",
  "content": "My dog has fleas."
}
{
  "@context": {
     "@vocab": "https://www.w3.org/ns/activitystreams",
     "ext": "https://canine-extension.example/terms/",
     "@language": "en"
  },
  "summary": "A note",
  "type": "Note",
  "content": "My dog has fleas.",
  "ext:nose": 0,
  "ext:smell": "terrible"
}
{
  "@context": [
     "https://www.w3.org/ns/activitystreams",
     {
      "css": "http://www.w3.org/ns/oa#styledBy"
     }
  ],
  "summary": "A note",
  "type": "Note",
  "content": "My dog has fleas.",
  "css": "http://www.csszengarden.com/217/217.css?v=8may2013"
}

In all of them, there is a piece of information we will call "the vocabulary".

If the context is a string, the vocabulary is that string. If the context is an object, the vocabulary is under the @vocab key. If the context is an array, the vocabulary is a string in the first index of the array.

So in all of these examples the vocabulary is "https://www.w3.org/ns/activitystreams"

Assume one of these shapes of JSON is in a file called activity.json. Your job is to extract the vocabulary out of that file and print it.

Restrictions

I am personally most interested in solutions on the "static" side of the world - Java, C#, Rust, etc. - because this is where the solutions really go from "obvious" to "cursed" and "magic".

Leave solutions in the comments below.


My Solution

I've been doodling on a JSON library for Java that I might find time to write about later, but in that my solution is the following.

import dev.mccue.json.Json;
import dev.mccue.json.decode.alpha.Decoder;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        var json = Json.readString(
                Files.readString(Path.of("activity.json"))
        );
        var vocab = Decoder.field(
                json,
                "@context",
                context -> Decoder.oneOf(context,
                        Decoder::string,
                        Decoder.index(0, Decoder::string),
                        Decoder.field("@vocab", Decoder::string)
                )
        );

        System.out.println(vocab);
    }
}

Try it out for yourself if you have a mind to - I would appreciate feedback.

<dependencies>
    <dependency>
        <groupId>dev.mccue</groupId>
        <artifactId>json</artifactId>
        <version>0.0.9</version>
    </dependency>
    <dependency>
        <groupId>dev.mccue</groupId>
        <artifactId>json.decode.alpha</artifactId>
        <version>0.0.9</version>
    </dependency>
</dependencies>

<- Index