diff --git a/2022/day08/main.go b/2022/day08/main.go new file mode 100644 index 0000000..5f7f108 --- /dev/null +++ b/2022/day08/main.go @@ -0,0 +1,144 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "strings" + + "github.com/alexchao26/advent-of-code-go/cast" + "github.com/alexchao26/advent-of-code-go/util" +) + +//go:embed input.txt +var input string + +func init() { + // do this in init (not main) so test file has same input + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } else { + ans := part2(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } +} + +func part1(input string) int { + grid := parseInput(input) + + // may be visible from multiple angles + visibleCoords := map[[2]int]string{} + for r := 1; r < len(grid)-1; r++ { + // from left + highestFromLeft := -1 + for c := 0; c < len(grid[0])-1; c++ { + height := grid[r][c] + if height > highestFromLeft { + visibleCoords[[2]int{r, c}] = "L" + highestFromLeft = height + } + } + // from right + highestFromRight := -1 + for c := len(grid[0]) - 1; c > 0; c-- { + height := grid[r][c] + if height > highestFromRight { + visibleCoords[[2]int{r, c}] = "R" + highestFromRight = height + } + } + } + + for c := 1; c < len(grid[0])-1; c++ { + // from top + highestFromTop := -1 + for r := 0; r < len(grid)-1; r++ { + height := grid[r][c] + if height > highestFromTop { + visibleCoords[[2]int{r, c}] = "T" + highestFromTop = height + } + } + // from bottom + highestFromBottom := -1 + for r := len(grid) - 1; r > 0; r-- { + height := grid[r][c] + if height > highestFromBottom { + visibleCoords[[2]int{r, c}] = "B" + highestFromBottom = height + } + } + } + + return len(visibleCoords) + 4 // plus 4 for corners +} + +func part2(input string) int { + // multiply the four scores together... score = how many trees any tree can see + // because trees on the edge will have a zero, just ignore them + grid := parseInput(input) + + bestScore := 0 + // iterate through every eligible tree + for r := 1; r < len(grid)-1; r++ { + for c := 1; c < len(grid[0])-1; c++ { + score := visible(grid, r, c, -1, 0) + score *= visible(grid, r, c, 1, 0) + score *= visible(grid, r, c, 0, -1) + score *= visible(grid, r, c, 0, 1) + + if score > bestScore { + bestScore = score + } + } + } + + return bestScore +} + +func visible(grid [][]int, r, c, dr, dc int) int { + count := 0 + startingHeight := grid[r][c] + r += dr + c += dc + for r >= 0 && r < len(grid) && c >= 0 && c < len(grid[0]) { + height := grid[r][c] + if height < startingHeight { + count++ + } else { + count++ + break + } + + r += dr + c += dc + } + + return count +} + +func parseInput(input string) (ans [][]int) { + for _, line := range strings.Split(input, "\n") { + var row []int + for _, n := range strings.Split(line, "") { + row = append(row, cast.ToInt(n)) + } + ans = append(ans, row) + } + return ans +} diff --git a/2022/day08/main_test.go b/2022/day08/main_test.go new file mode 100644 index 0000000..bb6eda5 --- /dev/null +++ b/2022/day08/main_test.go @@ -0,0 +1,63 @@ +package main + +import ( + "testing" +) + +var example = `30373 +25512 +65332 +33549 +35390` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 21, + }, + { + name: "actual", + input: input, + want: 1690, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 8, + }, + { + name: "actual", + input: input, + want: 535680, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/2022/day09/main.go b/2022/day09/main.go new file mode 100644 index 0000000..0e24701 --- /dev/null +++ b/2022/day09/main.go @@ -0,0 +1,253 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "strings" + + "github.com/alexchao26/advent-of-code-go/cast" + "github.com/alexchao26/advent-of-code-go/mathy" + "github.com/alexchao26/advent-of-code-go/util" +) + +//go:embed input.txt +var input string + +func init() { + // do this in init (not main) so test file has same input + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } else { + ans := part2(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } +} + +func part1(input string) int { + // tail follows head logically if in the same row or column + // if not in same row or column, always moves diagonally + insts := parseInput(input) + + // start stacked at 0,0 + var head, tail [2]int + + // "normal" grid mapping... + diffs := map[string][2]int{ + "U": {1, 0}, + "D": {-1, 0}, + "L": {0, -1}, + "R": {0, 1}, + } + + visited := map[[2]int]bool{ + {0, 0}: true, + } + for _, inst := range insts { + for inst.val > 0 { + // move head + diff := diffs[inst.dir] + head[0] += diff[0] // row + head[1] += diff[1] // col + + // update tail + // if diff to row or col is > 1 + + rowDiff := head[0] - tail[0] + colDiff := head[1] - tail[1] + + // if either row or col diff is > 1, then that dimension HAS to move + // additionally, if the other diff is not zero, it needs to be + // adjusted to move diagonally + // note: the nested if blocks screwed me in part 2 because a longer + // rope can make coordinates off by 2 rows AND 2 cols + if mathy.AbsInt(rowDiff) > 1 { + /* 0 1 2 + H . T + diff = head - tail = -2 + want to make tail (2) to (1), so add diff / 2 + + T . H + diff = 2 - 0 = 2 + tail (0) + 2/2 = 1, checks out still + */ + tail[0] += rowDiff / 2 + // account for diagonal adjustment, same math... add col diff + if colDiff != 0 { + tail[1] += colDiff + } + } else if mathy.AbsInt(colDiff) > 1 { + tail[1] += colDiff / 2 + // account for diagonal adjustment, same math... add col diff + if rowDiff != 0 { + tail[0] += rowDiff + } + } + + // update where the tail has been... + visited[tail] = true + inst.val-- // one step at a time + } + } + + // return spots TAIL visited at least once, map[[2]int]bool + return len(visited) +} + +type inst struct { + dir string + val int +} + +func parseInput(input string) (ans []inst) { + for _, line := range strings.Split(input, "\n") { + ans = append(ans, inst{ + dir: line[:1], + val: cast.ToInt(line[2:]), + }) + } + return ans +} + +func part2(input string) int { + // oof, quite the refactor... + insts := parseInput(input) + + rope := initRope(10) + + visited := map[[2]int]bool{} + for _, inst := range insts { + for inst.val > 0 { + rope.moveOneSpace(inst.dir) + + // update where the tail has been... + visited[rope.tail.coords] = true + + inst.val-- // one step at a time + + fmt.Println(inst, rope, len(visited)) + } + } + + return len(visited) +} + +type node struct { + coords [2]int // row, col still + next *node +} + +type rope struct { + head, tail *node +} + +func initRope(length int) rope { + head := &node{} + itr := head + + // start at 1 to account for head already being created + for i := 1; i < length; i++ { + itr.next = &node{} + itr = itr.next + } + + return rope{ + head: head, + tail: itr, + } +} + +func (r rope) moveOneSpace(dir string) { + // "normal" grid mapping... + diffs := map[string][2]int{ + "U": {1, 0}, + "D": {-1, 0}, + "L": {0, -1}, + "R": {0, 1}, + } + + diff := diffs[dir] + r.head.coords[0] += diff[0] + r.head.coords[1] += diff[1] + + // update rest of rope too + r.head.updateTrailer() +} + +func (r rope) String() string { + str := "" + i := 0 + for itr := r.head; itr != nil; itr = itr.next { + str += fmt.Sprintf("%d:[%d,%d]->", i, itr.coords[0], itr.coords[1]) + i++ + } + return str +} + +// recursively updates the node behind itself as it follows +func (n *node) updateTrailer() { + if n.next == nil { + return + } + + rowDiff := n.coords[0] - n.next.coords[0] + colDiff := n.coords[1] - n.next.coords[1] + + // if either row or col diff is > 1, then that dimension HAS to move + // additionally, if the other diff is not zero, it needs to be + // adjusted to move diagonally + if mathy.AbsInt(rowDiff) > 1 && mathy.AbsInt(colDiff) > 1 { + n.next.coords[0] += rowDiff / 2 + n.next.coords[1] += colDiff / 2 + } else if mathy.AbsInt(rowDiff) > 1 { + // see part1 for math logic + n.next.coords[0] += rowDiff / 2 + n.next.coords[1] += colDiff + } else if mathy.AbsInt(colDiff) > 1 { + n.next.coords[1] += colDiff / 2 + n.next.coords[0] += rowDiff + } else { + // no need to continue updating children if movement is over + return + } + + // go to next node + n.next.updateTrailer() +} + +func reImplPart1(input string) int { + // oof, quite the refactor... + insts := parseInput(input) + + rope := initRope(2) + + visited := map[[2]int]bool{} + for _, inst := range insts { + for inst.val > 0 { + rope.moveOneSpace(inst.dir) + + // update where the tail has been... + visited[rope.tail.coords] = true + + inst.val-- // one step at a time + } + } + + // return spots TAIL visited at least once, map[[2]int]bool + return len(visited) +} diff --git a/2022/day09/main_test.go b/2022/day09/main_test.go new file mode 100644 index 0000000..cadaffc --- /dev/null +++ b/2022/day09/main_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "testing" +) + +var example = `R 4 +U 4 +L 3 +D 1 +R 4 +D 1 +L 5 +R 2` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 13, + }, + { + name: "actual", + input: input, + want: 6236, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + t.Run("reimplementation_"+tt.name, func(t *testing.T) { + if got := reImplPart1(tt.input); got != tt.want { + t.Errorf("reImplPart1() = %v, want %v", got, tt.want) + } + }) + } +} + +var largerExample = `R 5 +U 8 +L 8 +D 3 +R 17 +D 10 +L 25 +U 20` + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 1, + }, + { + name: "larger_example", + input: largerExample, + want: 36, + }, + { + name: "actual", + input: input, + want: 2449, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/2022/day10/main.go b/2022/day10/main.go new file mode 100644 index 0000000..5efac70 --- /dev/null +++ b/2022/day10/main.go @@ -0,0 +1,167 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "strings" + + "github.com/alexchao26/advent-of-code-go/cast" + "github.com/alexchao26/advent-of-code-go/util" +) + +//go:embed input.txt +var input string + +func init() { + // do this in init (not main) so test file has same input + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } else { + ans := part2(input) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } +} + +func part1(input string) int { + instructions := parseInput(input) + + X := 1 + sum := 0 + + i := 0 // what the current instruction is + for cycle := 1; cycle <= 220; cycle++ { + // "during" equates to the start of the cycle... + if (cycle-20)%40 == 0 { + sum += X * cycle + } + + switch instructions[i].name { + case "addx": + // decrement cycles on that instruction + // IF it hits zero add V + // AND move to next step + instructions[i].cycles-- + if instructions[i].cycles == 0 { + X += instructions[i].val + i++ + } + case "noop": + // just increment to next instruction + i++ + } + } + + return sum +} + +func part2(input string) string { + instructions := parseInput(input) + + X := 1 // doubles as sprite's center coordinate + + // 6 rows by 40 wide screen, starts all off + CRT := [6][40]string{} + for i, rows := range CRT { + for j := range rows { + CRT[i][j] = "." + } + } + + i := 0 // what the current instruction is + for cycle := 1; i < len(instructions); cycle++ { + // if (cycle-20)%40 == 0 { + // sum += X * cycle + // } + + /* + X = horizontal position of middle of (3 pixel wide) sprite + axis draws left to right, top to bottom, 40 wide x 6 high + 1---40 + 41---80 + ... + 201---240 + + draws 1 pixel per cycle + light up pixels IF the pixel being drawn is the same as one of the sprite's 3 pixels + + */ + + // calculate which pixel is being drawn... ZERO INDEXED + pixelRow := (cycle - 1) / 40 + pixelCol := (cycle - 1) % 40 + + // see if the spite's horizontal location overlaps that pixelCol + spriteLeft, spriteRight := X-1, X+1 + if spriteLeft <= pixelCol && spriteRight >= pixelCol { + CRT[pixelRow][pixelCol] = "#" + } + + switch instructions[i].name { + case "addx": + // decrement cycles on that instruction + // IF it hits zero add V + // AND move to next step + instructions[i].cycles-- + if instructions[i].cycles == 0 { + X += instructions[i].val + i++ + } + case "noop": + // just increment to next instruction + i++ + } + + } + log := "" + for _, rows := range CRT { + for _, cell := range rows { + log += cell + } + log += "\n" + } + fmt.Println(log) + return log +} + +type instruction struct { + name string + val int + cycles int +} + +func parseInput(input string) (ans []instruction) { + for _, l := range strings.Split(input, "\n") { + switch l[:4] { + case "addx": + ans = append(ans, instruction{ + name: "addx", + val: cast.ToInt(l[5:]), + cycles: 2, + }) + case "noop": + ans = append(ans, instruction{ + name: "noop", + cycles: 1, + }) + default: + panic("input line: " + l) + } + } + return ans +} diff --git a/2022/day10/main_test.go b/2022/day10/main_test.go new file mode 100644 index 0000000..e891291 --- /dev/null +++ b/2022/day10/main_test.go @@ -0,0 +1,216 @@ +package main + +import ( + "testing" +) + +var example = `addx 15 +addx -11 +addx 6 +addx -3 +addx 5 +addx -1 +addx -8 +addx 13 +addx 4 +noop +addx -1 +addx 5 +addx -1 +addx 5 +addx -1 +addx 5 +addx -1 +addx 5 +addx -1 +addx -35 +addx 1 +addx 24 +addx -19 +addx 1 +addx 16 +addx -11 +noop +noop +addx 21 +addx -15 +noop +noop +addx -3 +addx 9 +addx 1 +addx -3 +addx 8 +addx 1 +addx 5 +noop +noop +noop +noop +noop +addx -36 +noop +addx 1 +addx 7 +noop +noop +noop +addx 2 +addx 6 +noop +noop +noop +noop +noop +addx 1 +noop +noop +addx 7 +addx 1 +noop +addx -13 +addx 13 +addx 7 +noop +addx 1 +addx -33 +noop +noop +noop +addx 2 +noop +noop +noop +addx 8 +noop +addx -1 +addx 2 +addx 1 +noop +addx 17 +addx -9 +addx 1 +addx 1 +addx -3 +addx 11 +noop +noop +addx 1 +noop +addx 1 +noop +noop +addx -13 +addx -19 +addx 1 +addx 3 +addx 26 +addx -30 +addx 12 +addx -1 +addx 3 +addx 1 +noop +noop +noop +addx -9 +addx 18 +addx 1 +addx 2 +noop +noop +addx 9 +noop +noop +noop +addx -1 +addx 2 +addx -37 +addx 1 +addx 3 +noop +addx 15 +addx -21 +addx 22 +addx -6 +addx 1 +noop +addx 2 +addx 1 +noop +addx -10 +noop +noop +addx 20 +addx 1 +addx 2 +addx 2 +addx -6 +addx -11 +noop +noop +noop` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 13140, + }, + { + name: "actual", + input: input, + want: 15880, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "example", + input: example, + want: `##..##..##..##..##..##..##..##..##..##.. +###...###...###...###...###...###...###. +####....####....####....####....####.... +#####.....#####.....#####.....#####..... +######......######......######......#### +#######.......#######.......#######..... +`, + }, + { + name: "actual", + input: input, + want: `###..#.....##..####.#..#..##..####..##.. +#..#.#....#..#.#....#.#..#..#....#.#..#. +#..#.#....#....###..##...#..#...#..#.... +###..#....#.##.#....#.#..####..#...#.##. +#....#....#..#.#....#.#..#..#.#....#..#. +#....####..###.#....#..#.#..#.####..###. +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/2022/day11/main.go b/2022/day11/main.go new file mode 100644 index 0000000..64ec5ed --- /dev/null +++ b/2022/day11/main.go @@ -0,0 +1,243 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "sort" + "strings" + + "github.com/alexchao26/advent-of-code-go/util" +) + +//go:embed input.txt +var input string + +func init() { + // do this in init (not main) so test file has same input + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(true) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } else { + ans := part2(true) + util.CopyToClipboard(fmt.Sprintf("%v", ans)) + fmt.Println("Output:", ans) + } +} + +func part1(useRealInput bool) int { + monkeys := initInput() + if !useRealInput { + monkeys = initExample() + } + + inspectedCounts := make([]int, len(monkeys)) + for round := 0; round < 20; round++ { + for i, monkey := range monkeys { + for _, item := range monkey.items { + newItemVal := monkey.operation(item) / 3 + + if newItemVal%monkey.testDivisibleBy == 0 { + monkeys[monkey.trueMonkey].items = append( + monkeys[monkey.trueMonkey].items, newItemVal) + } else { + monkeys[monkey.falseMonkey].items = append( + monkeys[monkey.falseMonkey].items, newItemVal) + } + + } + inspectedCounts[i] += len(monkey.items) + + // empty out this monkey's items + monkeys[i].items = []int{} + } + } + + sort.Ints(inspectedCounts) + return inspectedCounts[len(inspectedCounts)-1] * inspectedCounts[len(inspectedCounts)-2] +} + +// oh my god i figured out a math-y remainder theorem-y thing myself! +func part2(useRealInput bool) int { + monkeys := initInput() + if !useRealInput { + monkeys = initExample() + } + + // the worry levels will always increase now that they're not being divided + // by 3, and we care about remainders because that's what all the tests are + // BUT we can't just mod by any monkey's testBy number, because they're all + // throwing the items around, + // so find a shared common denominator that can be used to keep the numbers + // under overflow + bigMod := 1 + for _, m := range monkeys { + bigMod *= m.testDivisibleBy + } + + inspectedCounts := make([]int, len(monkeys)) + for round := 0; round < 10000; round++ { + + for i, monkey := range monkeys { + for _, item := range monkey.items { + newItemVal := monkey.operation(item) + newItemVal %= bigMod + + if newItemVal%monkey.testDivisibleBy == 0 { + monkeys[monkey.trueMonkey].items = append( + monkeys[monkey.trueMonkey].items, newItemVal) + } else { + monkeys[monkey.falseMonkey].items = append( + monkeys[monkey.falseMonkey].items, newItemVal) + } + + } + inspectedCounts[i] += len(monkey.items) + + // empty out this monkey's items + monkeys[i].items = []int{} + } + } + + sort.Ints(inspectedCounts) + return inspectedCounts[len(inspectedCounts)-1] * inspectedCounts[len(inspectedCounts)-2] +} + +type monkey struct { + items []int + operation func(int) int + testDivisibleBy int + trueMonkey, falseMonkey int // indices +} + +// faster to manually type this than write a parser (and potentially debug) +func initInput() []monkey { + return []monkey{ + { + items: []int{50, 70, 89, 75, 66, 66}, + operation: func(old int) int { + return old * 5 + }, + testDivisibleBy: 2, + trueMonkey: 2, + falseMonkey: 1, + }, + { + items: []int{85}, + operation: func(old int) int { + return old * old + }, + testDivisibleBy: 7, + trueMonkey: 3, + falseMonkey: 6, + }, + { + items: []int{66, 51, 71, 76, 58, 55, 58, 60}, + operation: func(old int) int { + return old + 1 + }, + testDivisibleBy: 13, + trueMonkey: 1, + falseMonkey: 3, + }, + { + items: []int{79, 52, 55, 51}, + operation: func(old int) int { + return old + 6 + }, + testDivisibleBy: 3, + trueMonkey: 6, + falseMonkey: 4, + }, + { + items: []int{69, 92}, + operation: func(old int) int { + return old * 17 + }, + testDivisibleBy: 19, + trueMonkey: 7, + falseMonkey: 5, + }, + { + items: []int{71, 76, 73, 98, 67, 79, 99}, + operation: func(old int) int { + return old + 8 + }, + testDivisibleBy: 5, + trueMonkey: 0, + falseMonkey: 2, + }, + { + items: []int{82, 76, 69, 69, 57}, + operation: func(old int) int { + return old + 7 + }, + testDivisibleBy: 11, + trueMonkey: 7, + falseMonkey: 4, + }, + { + items: []int{65, 79, 86}, + operation: func(old int) int { + return old + 5 + }, + testDivisibleBy: 17, + trueMonkey: 5, + falseMonkey: 0, + }, + } +} + +func initExample() []monkey { + return []monkey{ + { + items: []int{79, 98}, + operation: func(num int) int { + return num * 19 + }, + testDivisibleBy: 23, + trueMonkey: 2, + falseMonkey: 3, + }, + { + items: []int{54, 65, 75, 74}, + operation: func(num int) int { + return num + 6 + }, + testDivisibleBy: 19, + trueMonkey: 2, + falseMonkey: 0, + }, + { + items: []int{79, 60, 97}, + operation: func(num int) int { + return num * num + }, + testDivisibleBy: 13, + trueMonkey: 1, + falseMonkey: 3, + }, + { + items: []int{74}, + operation: func(num int) int { + return num + 3 + }, + testDivisibleBy: 17, + trueMonkey: 0, + falseMonkey: 1, + }, + } +} diff --git a/2022/day11/main_test.go b/2022/day11/main_test.go new file mode 100644 index 0000000..745fe37 --- /dev/null +++ b/2022/day11/main_test.go @@ -0,0 +1,59 @@ +package main + +import ( + "testing" +) + +var example = `` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + useRealInput bool + want int + }{ + { + name: "example", + useRealInput: false, + want: 10605, + }, + { + name: "actual", + useRealInput: true, + want: 151312, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.useRealInput); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + useRealInput bool + want int + }{ + { + name: "example", + useRealInput: false, + want: 2713310158, + }, + { + name: "actual", + useRealInput: true, + want: 51382025916, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.useRealInput); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +}