jlelse's Blog

Thoughts, stories and ideas

Advent of Code 2020 in Go: Week 1 and Week 2

Published on in 👨‍💻 Dev
Short link: https://b.jlel.se/s/25
Share online  Translate 

Instead of making a post every other day with all the solutions, here are my approaches for the rest of week 1 and week 2 of Advent of Code 2020.

Day 5

Here I had to fiddle a bit, but finally found a way to convert a string with the letters for the halfs into a number. (Full solution)

func partition(input string, min, max int, lower, upper rune) int {
	for _, c := range input {
		if c == lower {
			max -= (max - min + 1) / 2
		} else if c == upper {
			min += (max - min + 1) / 2
		}
	}
	return min
}

Day 6

Day 6 I found relatively easy, it was mostly just parsing. (Full solution)

Day 7

On day 7 I was able to use quite a bit of recursion and regular expressions in my solution, which was fun. My regular expressions for parsing: (Full solution)

mainColorRe := regexp.MustCompile(`^(?P<color>\w+ \w+) bags contain (?P<contents>.*)\.$`)
contentRe := regexp.MustCompile(`(?P<amount>\d+) (?P<color>\w+ \w+) bags?`)

Day 8

And also on day 8 I could use a regular expression. You had to write some kind of interpreter and fix broken code in part 2. (Full solution)

Day 9

Day 9 was about number sequences and checking them. A case for quite a few loops. Particularly helpful here were the ease of dealing with slices in Go and the method for sorting int slices built into the standard library. (Full solution)

Day 10

Part 1 of day 10 was well doable. In Part 2 you had to calculate possible paths, which was a bit tricky. In the end I found a quite efficient recursive method: (Full solution)

func countPaths(current int, joltages []int, memory map[int]int) (total int) {
	if len(joltages) == 0 {
		return 1
	}
	for _, next := range joltages {
		if next-current > 3 {
			break
		}
		if _, exists := memory[next]; !exists {
			memory[next] = countPaths(next, joltages[1:], memory)
		}
		total += memory[next]
	}
	return
}

Day 11

Day 11 was about occupied seats and how the status of those changes. Part 1 was only about the adjacent seats, part 2 was about the seats that can be seen. Again, I opted for lots of recursion. My solution to check if an occupied seat can be seen: (Full solution)

var dirs = []position{
	{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1},
}

func canSee(seats [][]rune, p, dir position) bool {
	return isSafe(seats, p) && seats[p.row][p.pos] != 'L' && (seats[p.row][p.pos] == '#' || canSee(seats, direction(p, dir), dir))
}

func canSeeAdjacent(seats [][]rune, pos position) (o int) {
	for _, dir := range dirs {
		if canSee(seats, direction(pos, dir), dir) {
			o++
		}
	}
	return
}

Day 12

The task on day 12 was a bit easier again, I think. For part 2 I didn’t bother with any complicated mathematical formulas to turn the waypoint, but used this function: (Full solution)

var rotateWaypoint func(int)
rotateWaypoint = func(degree int) {
	switch degree {
	case 90, -270:
		newWpNorth, newWpEast := -wpEast, wpNorth
		wpNorth = newWpNorth
		wpEast = newWpEast
	case 180, -180:
		rotateWaypoint(90)
		rotateWaypoint(90)
	case 270, -90:
		rotateWaypoint(90)
		rotateWaypoint(90)
		rotateWaypoint(90)
	}
}

Day 13

Day 13, today, was about bus lines. For part 2, I wanted to try normal loops first, but that seemed very inefficient and took too long. I saw solutions online with the Chinese remainder theorem, but finally got inspired to the following solution: (Full solution)

t, step := 0, 1
for i, l := range buslines {
	if l == -1 { // x
		continue
	}
	for (t+i)%l != 0 {
		t += step
	}
	step *= l
}

Tags:

Jan-Lukas Else
Interactions & Comments