michael-simons

526383?v=4

michael-simons
: michael-simons

About me

I am a father, husband and athlete (the later is probably just wishful thinking). Apart from that, I’m also a Java Champion, Oracle Cloud Groundbreaker ambassador, published author, JUG leader and currently working on Spring Data and Neo4j-OGM at Neo4j. In this role, my main focus is providing first class support of Neo4j in the Spring Environment, but also made contributions to Testcontainers, Spring Boot, Quarkus and a lot of other projects.

Day 00: groovy

Hello, World

This is an over engineered "Hello, World" application written in Groovy, using Spring Boot and the reactive web stack. Of course, one wouldn’t need a framework for that, but since Ralf asked for it…​ ¯\_(ツ)_/¯.

Day 0 doesn’t correspond to any of the official AoC puzzles.

The application defines a HelloWorldController as a top level Spring bean:

    @RestController
    static class HelloWorldController {

        @GetMapping("/")
        def index() {
            Mono.just("Hello, World")
        }
    }

The solutions shall print out a greeting. I will call the above endpoint via Springs reactive WebClient and subscribe to the flow. This is done in a Spring Application listener, reacting on ApplicationReadyEvent. ApplicationReadyEvent is fired when the application is ready to serve requests: After the flow ends, I’ll define a completable future to shutdown the application context. That needs to happen on a new thread, as it contains some blocking calls, which are not allowed in a reactive flow.

    static class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {

        @Override
        void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {

            def applicationContext = applicationReadyEvent.getApplicationContext();

            def port = ((WebServerApplicationContext) applicationContext).getWebServer().getPort();
            def webClient = WebClient.builder().baseUrl(sprintf("http://localhost:%d", port)).build();
            webClient
                    .get().uri("/")
                    .exchange()
                    .flatMap({ r -> r.bodyToMono(String.class) })
                    .doAfterTerminate({ -> CompletableFuture.runAsync(applicationContext.&close) })
                    .subscribe(System.out.&println)
        }
    }

I connect everything in a top level class call DemoApplication and wire up the listener:

    static void main(String[] args) {

        def builder = new SpringApplicationBuilder(DemoApplication.class)
        builder
                .listeners(new ApplicationReadyListener())
                .run(args)
    }

By using Groovys "Grapes" (@Grab('org.springframework.boot:spring-boot-starter-webflux:2.2.1.RELEASE')), this gives a runnable Groovy script:

groovy -Dlogging.level.root=WARN -Dspring.main.banner-mode=OFF solution.groovy

I included some configuration variables to turn off logging and Springs Banner, so that the application outputs only the greeting.

Bear in mind that this solution fires up a complete web stack and therefore is slower than probably any other Hello World program out there.

Day 01: sql

The Tyranny of the Rocket Equation: The database strikes back

This one is a solution just for fun. Why not solving the thing with SQL?

I did this with PostgreSQL, which supports recursive common table expressions.

First, change into the directory of this solution, bring up a Docker container running the latest PostgreSQL version, copy the input.txt into it and get a bash shell:

docker run -d -p 5432:5432  --name postgres1 postgres
docker cp input.txt postgres1:/tmp/
docker exec -it postgres1 bash

From there, we create a database and login:

createdb -U postgres aoc
psql -U postgres aoc

First, create a table and load the data:

CREATE TABLE modules(mass INTEGER);
COPY modules(mass) FROM '/tmp/input.txt';

First star is trivial:

SELECT sum(mass/3-2) FROM modules;

Second star is fun:

WITH RECURSIVE fuel_for_fuel(fuel) AS ( (1)
  SELECT mass/3-2 from modules (2)
  UNION ALL
  SELECT * FROM ( (3)
    SELECT fuel/3-2 AS fuel FROM fuel_for_fuel
  ) hlp WHERE fuel > 0
)
SELECT sum(fuel) from fuel_for_fuel;
1 Declare a recursive common table expression
2 Define the initial value
3 Recursively select from fuel_for_fuel. The nested from clause is only needed to avoid having the equation thrice.

Because? It’s fun.

Day 01: java

The Tyranny of the Rocket Equation

I have written the solution with my 9 year old kid in Java’s JShell. The JShell makes it easy to focus on the main part (equation of fuel, mapping inputs), without going through the hassles of building classes and whatnot.

To run the final program, you need JDK 11. Thanks to JEP 330, launching is as easy as java Solution.java.

Please bare in mind, that one would possible optimize the computation a bit more, but I wanted my kid to understand it.

The equation was straight forward, that’s basic math:

rocket equations
UnaryOperator<Integer> computeFuel = mass -> mass/3 - 2;

Sadly, I cannot use the var keyword to define variables from Lambdas.

We stored the input masses as input.txt and used java.nio.file.Files to read them line by line. This gives a stream of strings. I explained that those needed to be turned into numbers and we also spoke about basis of numbers. For each item of the stream, our equation can be applied.

Star One
var fuelForMass = Files.readAllLines(Path.of("input.txt")).stream() (1)
	.map(Integer::parseInt) (2)
	.map(computeFuel) (3)
	.reduce(0, Integer::sum); (4)

System.out.println("Fuel for mass " + fuelForMass);
1 Read the file line by line
2 Parse the lines into Integers
3 Apply the equation
4 Reduce the values to one single value

I was positivly suprised that a reduction was explainable in minutes with a piece of paper.

Star two was a bit more evolved. I wanted to avoid recursive lambdas. Those are possible (and rather easy in JShell, as JShell allows forward references), but hard to understand.

We first settled with the same stream and "flat mapping" each computed fuel value into a new stream, much like in the puzzle itself. "Flat mapping" is the process of taking one element of a stream and create a new stream from it, thus fanning out the elements of the original stream. While porting our solution from JShell into an executable Java, I accidently used the wrong variable as initial value for our inner stream (builder.add(fuelForMass); instead of builder.add(fuelForIndividualMass);). I noticed that when playing around ideas to make it more readable.

Let’s see if can make things a bit more readable:

Star Two
UnaryOperator<Integer> computeFuel = mass -> mass/3 - 2;

UnaryOperator<Integer> computeFuelForFuel = fuelForIndividualMass ->  (1)
Stream
	.iterate(computeFuel.apply(fuelForIndividualMass), fuel -> fuel > 0, computeFuel) (2)
	.reduce(fuelForIndividualMass, Integer::sum); (3)

var totalFuel = Files.readAllLines(Path.of("input.txt")).stream()
	.map(Integer::parseInt)
	.map(computeFuel.andThen(computeFuelForFuel)) (4)
	.reduce(0, Integer::sum);

System.out.println("Total fuel needed " + totalFuel);
1 We define a second operator, computeFuelForFuel
2 That generates a stream of integers in the form of a glorified for-loop. The first argument is the initial value (computing the fuel for the inital fuel), the second argument checks if we need to compute more fuel, the third is the operator for the next value, that receives the previous one
3 We reduce it again, this time not with 0 as the initial value for the fuel, but with the original value we need for the module
4 Here we concatenate two operators for the mapping. The rest is the same is in the solution for star one.

I was so emberrased for having commited the wrong solution, that I added some simple assertions to the file with values from the puzzle itself:

assert computeFuel.andThen(computeFuelForFuel).apply(1969) == 966;
assert computeFuel.andThen(computeFuelForFuel).apply(100756) == 50346;
assert Stream.of(1969, 100756).map(computeFuel.andThen(computeFuelForFuel))
	.reduce(0, Integer::sum) == 51312;

Be aware that those preconditions are only asserted when you run Java with the -ea flag. They are not a replacement for real tests, but for this solution, they are good enough.

I’m quite positve suprised that a modern Java solution is a readable 13 lines.

Day 02: kotlin

1202 Program Alarm

The main problem to tackle today is to work on state but keeping the original state around for later use.

For today, I decided to use Kotlin.

The solution can be run as a Kotlin script: kotlinc -script solution.kts

To solve the problem, one needs to access arbitrary elements by index. So for that either an array fits nicely or an index accessible collection.

Reading the input is pretty much the same with modern days Java 8 / Java 11:

val program = File("input.txt").readText().split(",").map { it.trim().toInt() }

The program is a Kotlin List, which by default is immutable. That is nice, so we don’t change the original program by accident when run.

I was more focussed on writing idiomatic Kotlin code than writing something more elaborate than my straight forward solution. The solution is a function taking in the program as a list and two additional Int-parameter representing the noun and verb to set. The function returns the memory after the program run as an IntArray.

val ops : Array<(Int, Int) -> Int> = arrayOf(Int::plus, Int::times) (1)

fun run(program: List<Int>, noun: Int, verb: Int): IntArray {

	val mem = program.toIntArray() (2)
	mem[1] = noun
	mem[2] = verb

	for (i in 0..mem.size step 4) { (3)
		val inst = mem.sliceArray(i.until(min(i + 4, mem.size))) (4)
		when (inst[0]) { (5)
			in 1..2 -> mem[inst[3]] = ops[inst[0]-1].invoke(mem[inst[1]], mem[inst[2]])
			99 -> return mem
		}
	}
	return mem;
}
1 Define the supported operations (plus and times)
2 Create a mutable IntArray from the List<Int> so that we can modify it
3 Iterate over all instructions, which have a maximum length of 4
4 Slice out one instruction. Care must be taken not to read over the end of the array when the op code is 99
5 Use when as a statement, reacting on the range of supported opcodes and the special opcode to terminate the program

The solution for the second star is a brute force nested loop:

for(noun in 0..99) {
	for(verb in 0..99) {
		val mem = run(program, noun, verb);
		if(mem[0] == 19690720) {
			println(100 * noun + verb)
			break
		}
	}
}

There are by a high chance nicer solutions to that, but there’s only so much time in a lunch break. Note that I don’t have to read the file multiple times, as the program is stored in an immutable collection.

Day 03: java

Crossed Wires

Today’s problem can be solved mathematically or by brute force. Either you need to compute intersections of segments in 2d (which isn’t that hard) or just search for intersecting points.

Before I even knew the second star puzzle I settled for the brute force searching for common points. The problem space is constrained to two wires anyway, so I didn’t care about memory usage.

Solution is written in Java 11 and can be executed with java Solution.java.

The main idea is a point that can be moved to another point and creating a segment along the way:

static class Point {

	final int x;
	final int y;

	Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

	List<Point> createSegment(String s) {
		Function<Integer, Point> newPoint;
		switch (s.charAt(0)) {
			case 'R':
				newPoint = i -> new Point(x + i, y);
				break;
			case 'L':
				newPoint = i -> new Point(x - i, y);
				break;
			case 'U':
				newPoint = i -> new Point(x, y + i);
				break;
			case 'D':
				newPoint = i -> new Point(x, y - i);
				break;
			default:
				newPoint = i -> this;
		}

		var steps = Integer.parseInt(s.substring(1));
		var segment = new ArrayList<Point>(steps);
		for (int i = 1; i <= steps; ++i) {
			segment.add(newPoint.apply(i));
		}
		return segment;
	}
}

The input is a fixed set of two wires, each on a line. Two wires are represented as maps of Point to Integer (Map<Point, Integer>), mapping each point to the number of steps it took to reach it. The map per wire will not contain duplicate points (self intersections).

So reading and "creating" the wires look like this:

var wires = Files.readAllLines(Path.of("input.txt"));
var pointsOfWires = List.of(new HashMap<Point, Integer>(), new HashMap<Point, Integer>());
for (int i = 0; i < 2; ++i) { (1)
	var wirePoints = pointsOfWires.get(i);
	var startingPoint = new Point(0, 0); (2)
	var steps = 0;
	for (String segments : wires.get(i).split(",")) { (3)
		for (Point l : startingPoint.createSegment(segments)) {
			wirePoints.put(l, ++steps);
			startingPoint = l; (4)
		}
	}
}
1 Fixed number of wires
2 Build wire from central point
3 Create segments with the instructions from the input
4 Move starting point

To find the intersecting point I use Java’s Set, which cannot contain duplicate values. First, add all points from wire 1, than retain only those that are in wire 2 as well.

var intersectingPoints = new HashSet<>(pointsOfWires.get(0).keySet());
intersectingPoints.retainAll(pointsOfWires.get(1).keySet());

For the first start, we have to sort them by "Manhattan distance" from central and take the first one out:

intersectingPoints.stream()
	.map(p -> Math.abs(p.x) + Math.abs(p.y))
	.sorted()
	.findFirst()
	.ifPresent(System.out::println);

Before reading puzzle two, I had only sets and didn’t store the steps. I didn’t like the solution, because the memory usage is horrible. But than, for the second star, we need the steps each wire needs to reach the intersection. Yeah! So with them being stored by wire, we can just map each intersection to the sum of steps each wire takes to get there and done:

intersectingPoints.stream()
	.map(p -> pointsOfWires.get(0).get(p) + pointsOfWires.get(1).get(p))
	.sorted()
	.findFirst()
	.ifPresent(System.out::println);

Day 04: ruby

Secure Container

Yeah, password hacking! Why not choosing Ruby for iterating a lot of stuff? :) Run the solution via ./solution.rb or ruby solution.rb.

You have to love the language for it’s expressiveness.

Star one basically reads like the conditions for the possible passwords:

passwords_matching_first_rules = (134792..675810).select do |v| (1)
  pairs = v.to_s.chars.each_cons(2) (2)
  pairs.any? { |p| p[0] == p[1] } && pairs.all? { |p| p[0].to_i <= p[1].to_i } (3)
end

puts "Star one #{passwords_matching_first_rules.count}"
1 Create range reassembling my input values and select all values for which the block returns true
2 Turn each value into a string, get the cars from it and create pairs of consecutive chars
3 Return whether any of those pairs satisfies being identical and all of the pairs being consecutive numbers

I refrained from using regex here. Finding pairs of numbers is rather easy (/(\d)\1/), but checking if there are lower or equal? Naaa…

However, I used regex for star two:

number_of_passwords_matching_third_rule = passwords_matching_first_rules.count do |p|
  p.to_s.scan(/((\d)\2+)/).map{ |a| a[0]}.any? { |v| v.length == 2 } (1)
end

puts "Star two #{number_of_passwords_matching_third_rule}"
1 Find all numbers repeated at last two times in the string and check if any of those matches is exactly 2 chars long.

The solution uses the previous list of numbers and applies the count method with a block, counting only those elements that return true for the block.

The regex /((\d)\2+)/ needs some explanation: It consists of two capturing groups. The outer one being number one, enclosing everything matched, and the inner one being number two and matching a single digit \d. \2 is a back reference to this second group and needs to be at least once in the string. scan returns an array of arrays (all matches, presented as an item in an array for each group).

That was way easier for me than day 3.

Day 05: scala

Sunny with a Chance of Asteroids

Our teamlead teased and nerd sniped me a bit this week. Scala was the topic. I tend to make this joke now for some time: "Can you read my code? Shall I increase the font? Can you read it now?" - "No, it’s still Scala". I never wrote a Scala program until yesterday, actually, and I possible never tried hard enough to understand at least a bit about it.

I plan on getting Daniels book Scala From Scratch respectively The Neophyte’s Guide to Scala. Daniel is one of the friendliest developers I know and I guess his books will be a good, gentle introduction.

Anyway, the solution to day 5 is my second try with Scala and I behaved like a kid in a sweet shop, trying a bit from everything. So please excuse me, when it’s not exactly the Scala way.

Day 5 builds on 1202 Program Alarm in which a programmable integer computer has to be build. That computer has mutable memory, which exposes an interesting design decision upfront for a Scala program: All the cool iterables, Seq, List and so on, are immutable. I could copy them over and over again, but honestly: That just doesn’t feel right to me. Therefore, I chose an Array as memory. I cannot add or remove elements on the same instance, but elements are mutable. Good enough for the task at hand.

A bit of ceremony is needed to turn the Scala-file into an executable script. So be it.

object Solution extends App {
}

Reading stuff seems to be the everywhere. I misst try-with-resources, though:

val input = io.Source.fromFile("input.txt")
val instructions = input.getLines().flatMap( _.split(",")).map(_.trim).map(_.toInt).toSeq
input.close

However, the underscore sticks out. What the? Turns out, a lot of ussages, see this SO answer. In the example above, it’s just used as Method values.

It became apparent, that todays puzzle would add a lot of operators, so this time I wanted them to objects and I wanted to use Case Classes for them and if possible, work with them in a pattern match.

I started with a basic operation:

abstract class Operation { (1)
  def numargs(): Int (2)

  def execute(pos: Int, args: Seq[(Int, Int)], reader: (((Int, Int)) => Int), writer: (Int, Int) => Unit): Int
}
1 An abstract class
2 An abstract method, This method has 4 arguments: The current position, the arguments for the operation (a sequence of tuples of ints), a reader from the memory and a writer to the memory. Reader and writer are of type function: The reader from one tuple of ints to an int, the writer takes two ints. The tuples contain the position in memory in the first place, and in the second, the access mode.

The execute method is meant to execute the operation and returns the the next position. Now, how does an operation look?

Star one requires all operations from day 2 (add, mul and exit) as well as an input and an echo operation. The exit operation is the easiest one. It does nothing:

case class Exit() extends Operation {
  def numargs(): Int = 0

  def execute(pos: Int, args: Seq[(Int, Int)], reader: (((Int, Int)) => Int), writer: (Int, Int) => Unit): Int = 0
}

I want some more traits for the numerics operation. Traits are used to share interfaces and fields between classes. They are similar to Java 8’s interfaces. Classes and objects can extend traits but traits cannot be instantiated and therefore have no parameters.

trait HasOpcode {
  def opcode(): Int (1)
}

trait NumericOperation extends HasOpcode {
  val ops = Seq[(Int, Int) => Int](_ + _, _ * _) (2)

  def numargs(): Int = 3 (3)

  def opcode(): Int

  def execute(pos: Int, args: Seq[(Int, Int)], reader: (((Int, Int)) => Int), writer: (Int, Int) => Unit): Int = {
    writer(args(2)._1, ops(opcode() - 1)(reader(args(0)), reader(args(1)))) (4)
    pos + numargs() + 1
  }
}
1 Some more methods
2 A member variable representing the available ops, here + and *, the functions using the _ as placeholder for the actual arguments
3 A function with a default implementation
4 And the default execute method for a numeric operation. This selects the the operation based on the opcode, applies it by reading stuff from the memory and writing it back.

The concrete ops look like this then:

case class Add() extends Operation with NumericOperation {

  def opcode() = 1
}

Traits extends other traits, classes extends other classe and are with Traits. Much like extends and implements in Java.

Now, how to get such an operation? I defined a Companion object for the class and an apply method. The apply method bridges between function and object oriented programming and creates instances of an object. Here, it is a beautiful representation of a factory method, determining via a pattern match which concrete instance to create:

object Operation {
  def apply(pos: Int, memory: Array[Int]) = memory(pos) % 100 match {
    case 1 => Add()
    case 2 => Mul()
    case 3 => ReadInto()
    case 4 => Echo()
    case 99 => Exit()
    case opcode@_ => throw new Exception(s"Invalid opcode $opcode")
  }
}

This allows for writing val op = Operation(1, Array(3)) instead of throwing news`around. The last `case with the @ assigns the matched value to the variable before so that I can use it.

Before I show the actual program run, here are the functions I use to read and write from the memory, according the modes defined in the puzzle (position mode (use the value at the given memory adress) or immediate (use the value itself)).

def read(memory: Array[Int])(p: Int, mode: Int) =
  if (mode == 0) memory(p) else p (1)
def write(memory: Array[Int])(p: Int, v: Int) =
  memory(p) = v

val reader = (read(memory) _).tupled (2)
val writer = write(memory) _ (3)
1 Definition of methods with multiple parameter lists
2 tupled is helpful: The partial function originally takes 2 parameters. After that, it takes a Tuple2, which we gonna use in a second.
3 Partial application of the write methode, with only the memory passed to it, effectivly turning it into an accessor or writer.

They look funny… Both have two parameter lists, the first taking in the memory, the second one positional and mode respectively positional and value parameter. Those are methods that applicable to partial application (currying).

The last helper method I have extracts the parameter modes:

def extractModes(of: Int) = for (i <- 3 to 5) yield
  of % Math.pow(10, i).toInt / Math.pow(10, i - 1).toInt

It uses a for-comprehension, something I heard at my work at Neo4j for the first time. We support this in Cypher to generate new patterns.

Adding up gives the following program, representing our computer:

def run(memory: Array[Int], pos: Int = 0): Unit = {

  val operation = Operation(pos, memory)
  val modes = extractModes(memory(pos))
  val args = (1 to operation.numargs).map(i => (memory(pos + i), modes(i - 1))) (1)


  val reader = (read(memory) _).tupled (2)
  val writer = write(memory) _ (3)

  operation match { (4)
    case Exit() => Nil
    case op@_ => {
      val next = op.execute(pos, args, reader, writer)
      run(memory, next)
    }
  }
}
1 Create tuples of parameters and their mod
2 Create reader
3 and writer
4 match on the operation and either exit or execute and run again

To run it, we create an array copy from the instructions read at the start and begin with:

println("For star one, enter 1, for start two, 5")
run(instructions.toArray)

Star two just added additional ops, you’ll find them in the source of course.

Other valid programs are (when loaded Solution.scala into the Scala REPL)

:load Solution.scala
// Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
Solution.run(Array(3,9,8,9,10,9,4,9,99,-1,8))
// Using position mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
Solution.run(Array(3,9,7,9,10,9,4,9,99,-1,8))
// Using immediate mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
Solution.run(Array(3,3,1108,-1,8,3,4,3,99))
// Using immediate mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
Solution.run(Array(3,3,1107,-1,8,3,4,3,99))
// And a bigger example, indidicating less than, equal or greater than 8
Solution.run(Array(3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,
1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,
999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99))

And that concludes my adventure in Scala world.

Run with scala Solution.scala. Tested with Scala code runner version 2.13.1 Correct solutions are: 12896948 and 7704130

Day 06: cypher

Universal Orbit Map

I was so hoping for something to be solved with the help of my favorite database and query language. Enter Neo4j and Cypher.

As with my SQL solution for day1, I’m gonna run all of this in a dockerized version of the database.

docker run -d -p 7474:7474 -p 7687:7687 -e 'NEO4J_AUTH=neo4j/secret' --name neo4j1 neo4j:3.5.13 (1)
docker cp input.txt neo4j1:/var/lib/neo4j/import (2)
docker exec -it neo4j1 cypher-shell -u neo4j -p secret (3)
1 Startup a Neo4j container, publish the HTTP and Bolt ports and define a passwort (secret)
2 Copy the input file into Neo4j’s import directory
3 Login into the container and open the cypher shell for executing commandos.

I’m gonna use the shell, but you can of course also use the Neo4j browser. It has a friendly interface to get you started with your first graph and some nice visualisations. Here’s the one from the puzzle’s description:

day6

I’m gonna use LOAD CSV as described (among other things) in one of my Neo4j related talks. LOAD CSV processes CSV files line by line and takes in an optional field separator, which will be ) in our case:

LOAD csv FROM 'file:///input.txt' AS orbits FIELDTERMINATOR ')'
MERGE (o0:Object {name: orbits[0]}) (1)
MERGE (o1:Object {name: orbits[1]})
MERGE (o0) <- [:ORBITS] - (o1) (2)
RETURN COUNT(*);
1 Create Object nodes. We use a merge statement, that checks whether a given pattern exists or not to avoid duplicates
2 Create the ORBITS relationship between the objects. We could have done all of this in one step, but than nodes would have been duplicated, as MERGE always checks for the existence of the whole pattern.

Having the data, both star one and star two are rather short Cypher statements:

MATCH (c:Object {name: 'COM'}) WITH c
MATCH p=((:Object) -[:ORBITS*1..] -> (c))
RETURN sum(length(p));

This reads: "Match the object named 'COM' (Center of Mass), than match the path from all other objects to this object and return the sum of the length of those paths.". This works because the input is a tree respectivly a directed acyclic graph, to be precise.

Star two uses the built-in shortestPath operation

MATCH (y:Object {name: 'YOU'}) -[:ORBITS] -> (o1:Object) (1)
MATCH (s:Object {name: 'SAN'}) -[:ORBITS] -> (o2:Object)
WITH o1, o2 (2)
MATCH p = shortestPath((o1)-[:ORBITS*1..]-(o2))  (3)
RETURN length(p);
1 Find the starting objects (one step away from YOU and SAN)
2 Pass them on to the next section of the query
3 Match the shortest path and return its length.

And with the SQL example from day 1: Don’t just dump unstructured data into your databases. Use them the way they where meant to be used.

Tested with neo4j:3.5.13 Correct solutions are: 135690 and 298.

Day 07: scala

Amplification Circuit

Shit. Still in Scala land: Today’s task is continues at day 5. So, let’s see if I can manage.

We are speaking about a "real" compute more and more. To solve the task, we need persistent memory and address pointers, and also input.

First, my stack based IO, implememented with a list:

class IO(private var input: Seq[Int] = Seq()) {
  def read: Option[Int] = input match {
    case Nil => None
    case l@_ => {
      input = input.tail
      Some(l.head)
    }
  }

  def <<(v: Int) = { (1)
    input = v +: input
    this
  }
}
1 I like that: Creating own operators. Sadly, I cannot have infix operators with the same symbols, therefore the read

The operations are the same as in day 5, but I added a whole computer class to stuff them together:

class Computer(private val memory: Array[Int]) { (1)

  private def extractModes(of: Int) = for (i <- 3 to 5) yield
    of % Math.pow(10, i).toInt / Math.pow(10, i - 1).toInt

  val stdIo = new IO (2)

  private var next: Option[Int] = Some(0)

  private def load(p: Int, mode: Int) = if (mode == 0) memory(p) else p

  private def store(p: Int, v: Int) = memory(p) = v

  def run(): Option[Int] = {

    val reader = (load _).tupled
    val writer = store _

    def executionInstruction: (Int => Option[Int]) = (ptr: Int) => { (3)
      val operation = Operation(ptr, memory)
      val modes = extractModes(memory(ptr))
      val args = (1 to operation.numargs).map(i => (memory(ptr + i), modes(i - 1)))
      operation match {
        case Exit() => None
        case op@Echo() => Some(op.execute(ptr, args, reader, writer, stdIo)) (4)
        case op@_ => {
          val next = op.execute(ptr, args, reader, writer, stdIo)
          executionInstruction(next)
        }
      }
    }

    next = next.flatMap(executionInstruction)
    stdIo.read (5)
  }

  def expectsInput() = next.isDefined
}

object Computer {
  def loadProgram(instructions: Seq[Int]) = new Computer(instructions.toArray) (6)
}
1 Computer has memory
2 It’s own IO
3 This executes the current instruction and returns the next pointer
4 This is actually already part of star two: The computer pauses, when it echoed some output instead of immediate jumping to the next instruction
5 Return the last output
6 Convinence method to load a program

I didn’t find star one too hard:

def runProgram = (input: Int, computerAndPhase: (Computer, Option[Int])) => {
  val c = computerAndPhase._1
  c.stdIo << input
  computerAndPhase._2 match {
    case v@Some(_) => c.stdIo << v.get
    case _ =>
  }
  c.run().get
} (1)

def runWithoutFeedback(instructions: Seq[Int]): Int = {
  val executeSequence = (computers: Seq[(Computer, Option[Int])]) =>
    computers.foldLeft(0)(runProgram) (2)
  (0 to 4).map(Option(_))
    .permutations (3)
    .map((1 to 5).map(_ => Computer.loadProgram(instructions)).zip(_)) (4)
    .map(executeSequence).max (5)
}

val starOne = runWithoutFeedback(instructions)
println(s"Star one ${starOne}")
1 A run program function, takes an input (0 or the output from the computer machine) and the computer and an optional phase to init the computer If there’s a phase, we use it. The runProgram function returns the input for the next run.
2 Generator for 5 computers with the identical program each
3 A function that executes a sequence of phase, stored in a list of pairs (computer and phase). That list is folded from the left, with initial input of 0
4 Scala has a build in method for permutating lists. That is nice and I use that
5 Init 5 new computers and zip them each with their phase
6 Execute each sequence of computers and phase and determine the maximum, reachable output

The second star took me the whole afternoon…​ The idea is to initialize all computers. Each get started with their assigned test phases. When they are used up, only None are generated, so that runProgram doesn’t use it. Than, loop as long as the last computer expects more input:

def runWithFeedback(instructions: Seq[Int]): Int = {
  val executeSequence2 = (phases: Seq[Option[Int]]) => {
    val computers = (1 to 5).map(_ => Computer.loadProgram(instructions))
    val availablePhases = (phases ++: LazyList.continually(None)).iterator (1)
    val nextRun = () => computers.last.expectsInput()
    var lastOutput = 0
    while (nextRun()) {
      lastOutput = computers
        .zip(availablePhases)
        .foldLeft(lastOutput)(runProgram) (2)
    }
    lastOutput
  }
  (5 to 9).map(Option(_)).permutations.map(executeSequence2).max
}

val starTwo = runWithFeedback(instructions)
println(s"Star two ${starTwo}")
1 A lazy list. This is quite cool.
2 Here the previous input gets feed back into the first computer (as the initial value for the fold)

Other valid programs are (when loaded Solution.scala into the Scala REPL)

:load Solution.scala
// 43210
Solution.runWithoutFeedback(Seq(3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0))
// 54321
Solution.runWithoutFeedback(Seq(3,23,3,24,1002,24,10,24,1002,23,-1,23,
101,5,23,23,1,24,23,23,4,23,99,0,0))
139629729
Solution.runWithFeedback(Seq(3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,
27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5))
// 18216
Solution.runWithFeedback(Seq(3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,
-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,
53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10))
Run with scala Solution.scala. Tested with Scala code runner version 2.13.1 Correct solutions are: 92663 and 14365052

Day 07: java

Amplification Circuit

Run with java --source 13 --enable-preview Solution.java. Tested with java version "13" 2019-09-17 Correct solutions are: 92663 and 14365052

Day 08: python

Space Image Format

I think that’s maybe the second or third time I ever actively used Python. Significant spaces: Is this YAML in disguise ;)?

The idea of the solution: Split the input into chunks the size of the images dimensions, sort by number of zeros and take the first. Second star uses an image mask.

#!/usr/bin/env python3

w = 25
h = 6
d = w * h

def chunks(lst, n):
    """Yield successive n-sized chunks from lst.

    This solution is from Andreas Zwinkau (https://github.com/qznc)
    I used `wrap` from textwrap before, but that doesn't play nice with whitespaces
    (Well, it does, but more for like text processing).
    Many other inputs have been very messed up and hardly readable.
    https://aoc-2019.netlify.com/generated/coder/qznc/generateddays#_day_08_python
    """
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

with open('input.txt', 'r') as file:
    input = file.read().rstrip()

    layers = list(chunks(input, d)) (1)
    mostTransparentLayer = sorted(layers, key=lambda s: s.count("0"))[0] (2)
    starOne = mostTransparentLayer.count("1") * mostTransparentLayer.count("2")
    print(f"Star one {starOne}")

    translation = {"0": " ", "1" : "*", "2": "2"} (3)
    image = ["2" for _ in range(d)] (4)
    px = 0
    for layer in layers:
        for px in range(0, d):
            image[px] = translation[layer[px]] if image[px] == "2" else image[px]

    starTwo = "\n".join(chunks("".join(image), w)) (5)
    print("Star two")
    print(starTwo)
1 Create the layers by chunking the input at the given dimension (Please note the comment at the chunk method). chunk returns a generator. This can be iterated, but cannot be reseted. I need the list of layers twice, so I copy them into a list
2 Create a sorted copy of that list (by the count of 0)
3 I use a dictionary for translating the image value
4 Start with a transparent image as mask. Again. we find a list comprehension during AoC
5 Here, we wrap the final image, this time at the width and than join those lines together by \n

The image mask array could have been generated by unpacking the list like this [*map(lambda item: "2", range(d))], but I like the list comprehension more.

Run with python3 Solution.py. Tested with Python 3.7.0

Day 09: java

Sensor Boost

Say Intcode computer one more time…

giphy

Anyway.

Today, we got relative parameter modes and a bigger address space. I build this on my Java solution for day 7.

Bigger address space has been solved with a view on the runnning program:

private final Map<Long, Long> memory;

private long resolveAddress(long address, int mode) {

	return mode == 2 ? base + address : address;  (1)
}

private Long load(long p, int mode) {

	if (mode == 1) {
		return p;
	}

	var address = resolveAddress(p, mode);
	return this.memory.computeIfAbsent(address, i -> i > program.length ? 0L : program[Math.toIntExact(i)]);
}

private void store(long p, int mode, Long v) {

	var address = resolveAddress(p, mode);
	this.memory.put(address, v);
}
1 Implementing relative memory in one go

The listing also shows the relative memory. One more new instruction to modify it:

case 9 -> {
	var l = load(load(ptr++, 0), modes[0]);
	base += l;
	yield Optional.of(ptr);
}

I also split my io stack into both stdIn and stdOut and throw an exception when the computer requries input:

case 3 -> {
	var v = readStdIn().orElseThrow(InputRequiredException::new);
	store(load(ptr++, 0), modes[0], v);
	yield Optional.of(ptr);
}

Reading and writing to standard io is now internal to the computer. Input can be piped into it. The computer doesn’t return anything now on run. Output can be accessed via head() or drain():

private Optional<Long> readStdIn() {

	return Optional.ofNullable(stdIn.poll());
}

private void writeStdOut(Long in) {

	stdOut.push(in);
}

public Computer pipe(Long in) {

	stdIn.push(in);
	return this;
}

public List<Long> drain() {

	var output = new ArrayList<Long>(this.stdOut.size());
	this.stdOut.descendingIterator().forEachRemaining(output::add);
	this.stdOut.clear();
	return output;
}

public Optional<Long> head() {

	return Optional.of(this.stdOut.poll());
}

I changed this from day 7, so that I can use the amplication circuit with todays computer. Todays computer should not halt after it produced output, in my day 7 solution, it needed to halt.

Biggest challenge today? Can you spot the bug in my day 7 solution? Well, I couldn’t for some time. There’s one tiny, little instruction that just didn’t get hit on day 7. Well, now it does.

For the second star, I needed to drop the recursion, as the stack size went too big.

Run with java --source 13 --enable-preview Solution.java. Tested with java version "13" 2019-09-17, correct solutions are: 3601950151 and 64236.

Day 10: python

Monitoring Station

I like python.

Here’s the idea to solve this puzzle. First have some basic geometry:

def direction(v1, v2):
    return (v2[0]-v1[0], v2[1]-v1[1])

def length(v):
    return math.sqrt(v[0]**2 + v[1]**2)

def norm(t):
    l = length(t)
    return (round(t[0]/l,4), round(t[1]/l,4))

Than

all = {}
for candidate in asteroids:  (1)
    targets = {}

    for other in asteroids:
        if(candidate == other):
            continue
        d = direction(candidate, other) (2)
        targets.setdefault(norm(d), []).append((other, length(d))) (3)

    for val in targets.values(): val.sort(key=lambda i:i[1]) (4)
    all[candidate] = targets

base = max(all.items(), key=lambda i:len(i[1])) (5)
print(f"Star one {len(base[1])}")
1 Create the cross product of each asteroid with all others.
2 Compute the direction and the norm of the directional vector for each pair.
3 Store all targets per direction into a list
4 Sort that list by direction
5 Select the one that has most outgoing directions

That’s the base. From there on:

hit = []
while(len(hit) < 200 and len(base[1]) > 0):
    for val in sorted(base[1].keys(), key=lambda i:(math.atan2(i[0], i[1])), reverse=True): (1)
        targeted = base[1].get(val)
        hit.append(targeted.pop()[0]) (2)
        if(not targeted):
            del base[1][val]
        if(len(hit) == 200):
            break

print(f"Star two {hit[-1][0]*100+hit[-1][1]}")
1 Go through all targeteting directions, counterclockwise
2 Hit the first
3 And move on.
Run with python3 Solution.py. Tested with Python 3.7.0.
Correct solutions are 263 and 1110, expected solutions for test-input2.txt are 210 and 802 and 30 and 1203 for test-input3.txt

Day 11: java

Space Police

I could reuse my day 9 solution completely, which is kinda good, I guess. I added a reset method to the computer, so that I don’t need to reload the program each time.

Nothing special to the solution of the puzzle. Basic walking around stuff. As I will stick in Javaland with IntComputer tasks, I might as well do it nicely object oriented with a bunch of classes:

enum Direction {
	LEFT, RIGHT;

	static Direction fromLong(long instruction) {
		return instruction == 0L ? LEFT : RIGHT;
	}
}

enum View {
	NORTH("^"), SOUTH("v"), WEST("<"), EAST(">");

	private final String rep;

	View(String rep) {
		this.rep = rep;
	}

	View turn(Direction direction) {
		return switch (this) {
			case NORTH -> direction == Direction.LEFT ? WEST : EAST;
			case WEST -> direction == Direction.LEFT ? SOUTH : NORTH;
			case SOUTH -> direction == Direction.LEFT ? EAST : WEST;
			case EAST -> direction == Direction.LEFT ? NORTH : SOUTH;
		};
	}

	@Override
	public String toString() {
		return this.rep;
	}
}

static class Panel {
	private final int x;
	private final int y;

	Panel(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}

	Panel next(View view) {
		int dx = 0;
		int dy = 0;

		switch (view) {
			case NORTH -> dy = 1;
			case WEST -> dx = -1;
			case SOUTH -> dy = -1;
			case EAST -> dx = 1;
		}
		return new Panel(this.x + dx, this.y + dy);
	}
}

You get the idea: A Direction is derived from an instruction, a View uses that direction to compute the next view and a Panel uses that to compute the next one.

Given an enum Color with appropriate method to load and represent it self, the solution basically is the prose above:

enum Color {
	BLACK, WHITE;
}

static Map<Panel, Color> walkHull(Computer computer, Map.Entry<Panel, Color> startPanel, Consumer<Event> callback) {

	var panelComparator = Comparator
		.comparing(Panel::getY).reversed().thenComparing(Panel::getX); (1)
	var panels = new TreeMap<Panel, Color>(panelComparator);

	Consumer<Event> handler = event -> {
		if (event instanceof PanelPaintedEvent) {
			PanelPaintedEvent panelPaintedEvent = (PanelPaintedEvent) event;
			panels.put(panelPaintedEvent.getPanel(), panelPaintedEvent.getPayload());
		}
	};
	handler = handler.andThen(callback);

	var currentView = View.NORTH;
	var currentPanel = startPanel.getKey();
	var currentColor = startPanel.getValue();

	// Need to initialize the start color
	handler.accept(new PanelPaintedEvent(currentPanel, currentColor));
	do {
		// Compute
		computer
			.pipe(panels.getOrDefault(currentPanel, Color.BLACK).toLong()) (2)
			.run(false);
		var output = computer.drain();

		// Paint
		currentColor = Color.fromLong(output.get(0));
		handler.accept(new PanelPaintedEvent(currentPanel, currentColor));

		// Move
		currentView = currentView.turn(Direction.fromLong(output.get(1)));
		currentPanel = currentPanel.next(currentView);
		handler.accept(new MovedToPanelEvent(currentPanel, currentView));
	} while (computer.expectsInput());

	handler.accept(new StoppedEvent(currentPanel));

	computer.reset();
	return panels;
}
1 Probably the most intesting thing here: Creating a comparator for the panels. This saves me from adding equals and hashCode to panel, as I use a TreeMap for storing them. The TreeMap identifies two objects as equal when they are comparing to 0. I could Panel let implement Comparable, but than the comparision would always be the same. For my usecase (painting / printing) them, I want to to be ordered by their y-axis in reversed order first, than by x.
2 I don’t use computeIfAbsent here as I’m gonna put the panel into the map anyway, thus avoiding one operation.

I think that the above solution is a nice way of speaking the domains language without creating ivory towers.

Bonus: I added some handler code that gets each state event and can create this:

day11
Run with java --source 13 --enable-preview Solution.java. Tested with java version "13" 2019-09-17, correct solutions are: 1732 and ABCLFUHJ.

Day 12: ruby

The N-Body Problem

I had help today on a business trip to Malmö and I liked it very much:

Honestly, I would have come up with a solution for part 2 today without staring at the slowly increments of by brute force loop with my wife seeing that the axis and their velocities are independent.

And yes, Eric Wastl was very right with:

This set of initial positions takes 4686774924 steps before it repeats a previous state! Clearly, you might need to find a more efficient way to simulate the universe.
— Advent of Code 2019
Day 12

Today we used Ruby again. Some highlights:

class Array
	def add(other)
    [self,other].transpose.map { |x| x.reduce(:+) }
	end
end

Open classes, yeah! Here adding a pairwise add to Rubys array class

We added some classes that allow adding and applying gravity and velocity like this:

# Other methods obmitteted for brevity

class Moon
  attr_reader :position
  attr_reader :vel
  attr_reader :gravity

  def add_gravity_of(other_moon)

    @gravity = @gravity.add([
      compare_value_of_axis(@position[0], other_moon.position[0]),
      compare_value_of_axis(@position[1], other_moon.position[1]),
      compare_value_of_axis(@position[2], other_moon.position[2]),
    ])

    self
  end

Than first part is fairly trivial and again, readable as in the puzzle:

moons = input.map(&:clone) (1)

(1..1000).each do
  moons
    .product(moons).select { |p| p[0] != p[1] } (2)
    .each{ |m1,m2| m1.add_gravity_of(m2) }
  moons.each{ |m| m.apply_gravity.apply_velocity }
end

total_energy = moons.map(&:energy).reduce(:+)  (3)

puts "Star one #{total_energy}"
1 Cloning the input because we need it unmodified later
2 Create pairs of moons and apply their gravity onto each other
3 This reduction is nice: Map take’s a block taking the mapped value, but we can use & to turn the element of the block into a proc and calling the symbolic name energy (via the :) on it, that happens to be our computation for the enegery.

Second star was hard for me to spot…​ Implementation than was easy:

moons = input.map(&:clone)

cnt = 0
cycles = [-1, -1, -1]
c = [nil, nil, nil]
axes = Array.new(3) { Set.new }

loop do
  moons
    .product(moons).select { |p| p[0] != p[1] }
    .each{ |m1,m2| m1.add_gravity_of(m2) }
  moons.each{ |m| m.apply_gravity.apply_velocity }

  (0..2).each.select { |i| cycles[i] < 0}.each do |i| (1)
    axis = moons.map { |m| [m.position[i], m.vel[i]].flatten }
    cycles[i] = cnt if axes[i].include? axis
    axes[i].add(axis)
  end

  cnt += 1
  break if moons == input or cycles.all? {|v| v != -1} (2)
end

cycles_until_start = cycles.reduce(&:lcm) (3)

puts "Star two #{cycles_until_start}"
1 On three axis independently, check whether it has seen before in this combination (combination of all moon’s axis in question)
2 Break if the moons happened to be back or when all axis have completed a cycle
3 Reduce the number of cycles to their least common multple

Fun stuff to do and I’m really happy about it.

Tested with ruby 2.6.3p62 Correct solutions are: 7013 and 324618307124784

Day 13: java

Care Package

God damn it. I had to fix the comparision method YET ANOTHER TIME. Why? Because I compared to Long with == and not equals (from before I moved to virtual memory I used long. So why does this work at times and sometimes don’t?

Java keeps a cache for Integer and Long instances. The caches reaches from -128 upto 127 (the high mark is configurable for integers). So, two different instances of Integer or Long with the same value compare to true if they are in that range, otherwise not (because == compares addresses). The numerical operators (<, >, , >=) are not affected, because auto-unboxing kicks in for them.

Yay. I was so damn annoyed because I actually know that stuff.

Anyway, after that, the Int-Computer didn’t require any changes, the solution to part 1 is trival. Just count every third output if it is a block:

var computer = Computer.loadProgram(instructions);
var output = computer.run().drain();
int cnt = 0;
for (int i = 0; i < output.size(); ++i) {
	if (i % 3 == 2 && TileType.fromLong(output.get(i)) == TileType.BLOCK) {
		++cnt;
	}
}
System.out.println(String.format("Star one %d", cnt));

The second part? Really? Playing brick out on that thing? Naaah.

instructions.set(0, 2L); (1)

var paddlePattern = List.of(TileType.EMPTY.toLong(), TileType.PADDLE.toLong(), TileType.EMPTY.toLong()); (2)
for (int i = 0; i < instructions.size(); i += 2) {
	if (instructions.subList(i, i + 3).equals(paddlePattern)) { (3)
		var paddleAt = i + 1;
		var j = paddleAt;
		while (instructions.get(--j) != TileType.WALL.toInt()) {
			instructions.set(j, TileType.PADDLE.toLong());
		}
		j = paddleAt;
		while (instructions.get(++j) != TileType.WALL.toInt()) {
			instructions.set(j, TileType.PADDLE.toLong());
		}
		break;
	}
}

var computer = Computer.loadProgram(instructions); (4)
while (computer.run(false).expectsInput()) {
	computer.pipe(0L); (5)
}
computer.head()
	.ifPresent(d -> System.out.println(String.format("Star two %d", d)));
1 The puzzle say you have to change the instructions 🤔 Why not hack all of the instructions?
2 See if we find the game data: An empty thing, followed by the paddle and another empty thing.
3 Make the paddle a bit bigger… until it reaches walls on both sides
4 Load the new instructions
5 Run and never move
6 Last output is the high score after destroying all blocks.
Run with java --source 13 --enable-preview Solution.java. Tested with java version "13" 2019-09-17, correct solutions are: 326 and 15988.
java --source 13 --enable-preview Solution.java --animate gives you an animated version.
day13