Heading to the finish line

It has been a little while. I have been swamped with work and the work on my thesis, leaving no room to finish the Advent of Code or much of anything else. Yesterday I gave my practice presentation for my thesis. This means I am one more step closer to the finish line. During the day there were many interactions with fellow students. One of the topics has been the templates to use at Open Universiteit. So, I thought I would just create a repository of the templates that I use, so that anyone can learn from them. ...

February 17, 2024 - 1 min Arjen Wiersma

Advent of Code 2023 day 9

The weekend generally is a place to find hard puzzles again, this time not so much. A simple quest to find the next number in a sequence with a fully written out algorithm to follow. They key here is to use recursion. package main import ( "fmt" "time" "arjenwiersma.nl/aoc/internal/aoc" ) func NextStep(in []int) int { allZero := true for _, v := range in { if v != 0 { allZero = false } } if allZero { return 0 } var diffs []int for i := 1; i < len(in); i++ { diffs = append(diffs, in[i]-in[i-1]) } p := NextStep(diffs) return in[len(in)-1] + p } func main() { content := aoc.AsLines("2023/Day09/input.txt") var lines [][]int for _, v := range content { lines = append(lines, aoc.AsNumbers(v)) } startTime := time.Now() var res []int for _, v := range lines { res = append(res, NextStep(v)) } r := aoc.SumArray(res) endTime := time.Now() elapsed := endTime.Sub(startTime) fmt.Printf("Part 1: %d (%v)\n", r, elapsed) startTime = time.Now() for _, v := range lines { aoc.Reverse(v) } res = []int{} for _, v := range lines { res = append(res, NextStep(v)) } r = aoc.SumArray(res) endTime = time.Now() elapsed = endTime.Sub(startTime) fmt.Printf("Part 2: %d (%v)\n", r, elapsed) }

December 9, 2023 - 1 min Arjen Wiersma

Advent of Code 2023 day 8

Somewhat suspicious of 2 easy days we end up at Day 8. A simple map to follow again, from one key follow the instructions until we hit ZZZ. Part 2 had us do it for several keys at once, with the goal to find the spot where they all converge. This can take forever, erhm, a long time. So there has to be a math type solution to this problem. It turns out to be a Least Common Multiple problem. It is the smallest positive integer that is divisible by two or more numbers without leaving a remainder. To find the LCM of two or more numbers, you can use a method called prime factorization or a simpler approach involving multiples. We can also use the Greatest Common Divisor (GCD) to find the LCM. ...

December 9, 2023 - 2 min Arjen Wiersma

Advent of Code 2023 day 7

Today we learned about CamelCards, a game of poker meant to play on the back of a camel. The most interesting part here was the parsing of the cards and figuring out how to properly rank them. Part 2 turned out to be as easy as tracking Jokers. package main import ( "fmt" "sort" "strconv" "strings" "time" "arjenwiersma.nl/aoc/internal/aoc" ) type Card struct { bid int hand []int jokers int } func (c *Card) strongerThen(o *Card) bool { for i, v := range c.hand { if v > o.hand[i] { return true } else if v < o.hand[i] { return false } } return false } func (c *Card) rank() int { freq := make([]int, 15) for _, v := range c.hand { if v == 1 { // skip counting the joker continue } freq[v]++ } sort.Ints(freq) freq[len(freq)-1] += c.jokers strength := 2 * freq[len(freq)-1] // full house and 2 pair if freq[len(freq)-2] == 2 { strength += 1 } return strength } func NewCard(s string, bid int, p2 bool) *Card { c := &Card{} c.bid = bid c.jokers = 0 for p := 0; p < len(s); p++ { if s[p]-'0' >= 2 && s[p]-'0' <= 9 { c.hand = append(c.hand, int(s[p]-'0')) } else { x := 10 switch s[p] { case 'A': x = 14 case 'K': x = 13 case 'Q': x = 12 case 'J': if p2 { c.jokers += 1 x = 1 } else { x = 11 } case 'T': x = 10 } c.hand = append(c.hand, x) } } return c } func (c *Card) String() string { return fmt.Sprintf("%v (%d)", c.hand, c.bid) } func main() { content := aoc.AsLines("2023/Day07/input.txt") var cards []*Card for _, v := range content { p := strings.Split(v, " ") b, _ := strconv.Atoi(p[1]) c := NewCard(p[0], b, false) cards = append(cards, c) } startTime := time.Now() lessFunc := func(i, j int) bool { if cards[i].rank() == cards[j].rank() { return cards[j].strongerThen(cards[i]) } return cards[i].rank() < cards[j].rank() } sort.Slice(cards, lessFunc) res := 0 for i, c := range cards { res += (i + 1) * c.bid } endTime := time.Now() elapsed := endTime.Sub(startTime) if 251216224 != res { panic("Wrong answer") } fmt.Printf("Part 1: %d (%v)\n", res, elapsed) // 251216224 cards = []*Card{} for _, v := range content { p := strings.Split(v, " ") b, _ := strconv.Atoi(p[1]) c := NewCard(p[0], b, true) cards = append(cards, c) } startTime = time.Now() sort.Slice(cards, lessFunc) res = 0 for i, c := range cards { res += (i + 1) * c.bid } endTime = time.Now() elapsed = endTime.Sub(startTime) if 250825971 != res { panic("Wrong part 2") } fmt.Printf("Part 2: %d (%v)\n", res, elapsed) // 250825971 }

December 9, 2023 - 3 min Arjen Wiersma

Advent of Code 2023 day 6

Day 6 turned out to be the easiest day in the range so far. A simple implementation of the algorithm was more than sufficient. I later learned that it was a quadratic function. On the subreddit Deatranger999 said: If you hold down the button for x seconds, then you will beat the distance if the quadratic x^2 - t x + d is at most 0, where t is the total time of the race and d is the distance you’d like to beat. So I just plugged each one into WolframAlpha, found the roots, and then calculated the number of integers between the two roots. ...

December 9, 2023 - 2 min Arjen Wiersma

Advent of Code 2023 day 5

Today was an interesting problem. We are basically given a map to follow based on a number, possibly transforming the number at each step. With a single number this is quite simple, just apply the rules and step through each set of transformations. The problem becomes tricky when it turns out we have to deal with enormous ranges of numbers. On the subreddit some people reported their implementation to take hours and use 20GB of memory. ...

December 9, 2023 - 3 min Arjen Wiersma

Advent of Code 2023 Day 4

The difficulty is going up and down. This day was quite easy in comparison to yesterday. Today it was about parsing some numbers and finding a set of winning numbers. As I am doing these puzzles in Go I found out that there is no default set type. There is an implementation by HashiCorp named go-set that fills this void. I did not use an external package (I try to avoid them while doing AoC), but I am very tempted to pull that package in. ...

December 4, 2023 - 2 min Arjen Wiersma

Advent of Code 2023 Day 3

Day 3 was quite something. I think that in an attempt to make it harder for AI to solve the puzzles the creators also increased the difficulty level of the base puzzles a little too much. The test was not very clear as to what should happen with negative numbers and it might trip people up. The puzzle itself is a great to exercise grid knowledge as you have to work with neighbors and you have to extend the numbers when you find them. Part 2 was just some bookkeeping on my existing implementation, so it was not too much work. ...

December 3, 2023 - 2 min Arjen Wiersma

Advent of Code 2023 Day 2

Day 2 was another fun challenge. Lots of splitting of strings. I wonder if there is a better way to filter out the min and max value from the separate grabs. I am sure I will not be able to complete all challenges this year, but so far so good. package main import ( "fmt" "os" "strconv" "strings" ) type Grab struct { red, green, blue int } type Game struct { id int grabs []Grab } func main() { content, _ := os.ReadFile("2023/Day02/input.txt") var input []Game for g, l := range strings.Split(strings.TrimSpace(string(content)), "\n") { game := Game{} game.id = g + 1 parts := strings.Split(l, ":") grabs := strings.Split(parts[1], ";") for _, h := range grabs { grab := Grab{} for _, rgb := range strings.Split(h, ",") { color := strings.Split(strings.TrimSpace(rgb), " ") i, _ := strconv.Atoi(color[0]) switch color[1] { case "red": grab.red = i case "green": grab.green = i case "blue": grab.blue = i } } game.grabs = append(game.grabs, grab) } input = append(input, game) } max := Grab{ red: 12, green: 13, blue: 14, } var possible []Game outer: for _, game := range input { for _, grab := range game.grabs { if grab.red > max.red || grab.green > max.green || grab.blue > max.blue { continue outer } } // fmt.Println("Possible game: ", game) possible = append(possible, game) } sum := 0 for _, g := range possible { sum += g.id } fmt.Println("Part 1: ", sum) var powers []Grab for _, game := range input { min := Grab{ red: 0, green: 0, blue: 0, } for _, grab := range game.grabs { if grab.red > min.red { min.red = grab.red } if grab.green > min.green { min.green = grab.green } if grab.blue > min.blue { min.blue = grab.blue } } powers = append(powers, min) } sum = 0 for _, x := range powers { sum += x.red * x.green * x.blue } fmt.Println("Part 2: ", sum) }

December 2, 2023 - 2 min Arjen Wiersma

Advent of Code 2023 Day 1

The Advent of Code has started again. At NOVI we participate with a group of our students. We use the AoC throughout the entire curriculum as practice exercises to learn new programming languages or the application of data-structures and algorithms. Day 1 was a tricky start for most people. Part 1 was not too bad, but part 2 tripped most people up. I guess the idea was that you would have to solve the challenge with an array iteration, but most students tripped up. They tried to match each word and replace the occurrence in the text, running head-on into the edge-case where 2 numbers overlap, such as “eightwo”. ...

December 2, 2023 - 2 min Arjen Wiersma