diff --git a/2022/go/day11/day11.go b/2022/go/day11/day11.go new file mode 100644 index 0000000..4d24078 --- /dev/null +++ b/2022/go/day11/day11.go @@ -0,0 +1,148 @@ +package day11 + +import ( + _ "fmt" + "strings" + "sort" + "adventofcode2022/utils" + "math/big" +) + +type op int + +const ( + addition op = iota + 1 + multiply + square +) + +type monkey struct { + items []*big.Int + operation op + opArg *big.Int + test *big.Int + ifTrue int + ifFalse int + inspected int +} + +func Part1(input string) int { + + monkeys := parseInput(input) + var level = big.NewInt(0) + for round := 0; round < 20; round++ { + for i, monkey := range monkeys { + for _, item := range monkey.items { + monkeys[i].inspected++ + switch monkey.operation { + case addition: + level = new(big.Int).Add(item, monkey.opArg) + case multiply: + level = new(big.Int).Mul(item, monkey.opArg) + case square: + level = new(big.Int).Mul(item, item) + } + level = new(big.Int).Div(level, big.NewInt(3)) + t := &big.Int{} + t.Mod(level, monkey.test) + if t.Sign() == 0 { + monkeys[monkey.ifTrue].items = append(monkeys[monkey.ifTrue].items, level) + } else { + monkeys[monkey.ifFalse].items = append(monkeys[monkey.ifFalse].items, level) + } + + } + monkeys[i].items = monkeys[i].items[:0] + } + } + sort.Slice(monkeys, func(i, j int) bool { + return monkeys[i].inspected > monkeys[j].inspected + }) + + return monkeys[0].inspected * monkeys[1].inspected +} + +func Part2(input string) int { + monkeys := parseInput(input) + var level = big.NewInt(0) + commonDivisor := big.NewInt(3 * 13 * 19 * 17 * 5 * 7 * 11 * 2) + for round := 0; round < 10000; round++ { + for i, monkey := range monkeys { + for _, item := range monkey.items { + monkeys[i].inspected++ + switch monkey.operation { + case addition: + level = new(big.Int).Add(item, monkey.opArg) + case multiply: + level = new(big.Int).Mul(item, monkey.opArg) + case square: + level = new(big.Int).Mul(item, item) + } + level = level.Mod(level, commonDivisor) + t := &big.Int{} + t.Mod(level, monkey.test) + if t.Sign() == 0 { + monkeys[monkey.ifTrue].items = append(monkeys[monkey.ifTrue].items, level) + } else { + monkeys[monkey.ifFalse].items = append(monkeys[monkey.ifFalse].items, level) + } + + } + monkeys[i].items = monkeys[i].items[:0] + } + } + sort.Slice(monkeys, func(i, j int) bool { + return monkeys[i].inspected > monkeys[j].inspected + }) + + return monkeys[0].inspected * monkeys[1].inspected +} + +func parseInput(input string) []monkey { + monkeys := []monkey{} + + for i, monkeyString := range strings.Split(input, "\n\n") { + for _, line := range strings.Split(monkeyString, "\n") { + if strings.HasPrefix(line, "Monkey") { + monkeys = append(monkeys, monkey{}) + } else if strings.HasPrefix(line, " Starting items: ") { + s := strings.TrimPrefix(line, " Starting items: ") + for _, piece := range strings.Split(s, ", ") { + t := utils.MustAtoi(piece) + monkeys[i].items = append(monkeys[i].items, big.NewInt(int64(t))) + } + } else if strings.HasPrefix(line, " Operation: new = ") { + s := strings.TrimPrefix(line, " Operation: new = ") + if strings.HasPrefix(s, "old + ") { + s2 := strings.TrimPrefix(s, "old + ") + monkeys[i].operation = addition + t := utils.MustAtoi(s2) + monkeys[i].opArg = big.NewInt(int64(t)) + } else if s == "old * old" { + monkeys[i].operation = square + } else if strings.HasPrefix(s, "old * ") { + s2 := strings.TrimPrefix(s, "old * ") + monkeys[i].operation = multiply + t := utils.MustAtoi(s2) + monkeys[i].opArg = big.NewInt(int64(t)) + } + + } else if strings.HasPrefix(line, " Test: divisible by ") { + s := strings.TrimPrefix(line, " Test: divisible by ") + t := utils.MustAtoi(s) + monkeys[i].test = big.NewInt(int64(t)) + } else if strings.HasPrefix(line, " If true: throw to monkey ") { + s := strings.TrimPrefix(line, " If true: throw to monkey ") + monkeys[i].ifTrue = utils.MustAtoi(s) + } else if strings.HasPrefix(line, " If false: throw to monkey ") { + s := strings.TrimPrefix(line, " If false: throw to monkey ") + monkeys[i].ifFalse = utils.MustAtoi(s) + } else if line == "" { + // do nothing + } else { + panic("unknown input") + } + } + } + return monkeys +} \ No newline at end of file diff --git a/2022/go/day11/day11_test.go b/2022/go/day11/day11_test.go new file mode 100644 index 0000000..46b8b60 --- /dev/null +++ b/2022/go/day11/day11_test.go @@ -0,0 +1,45 @@ +package day11 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPart1(t *testing.T) { + r := Part1( +`Monkey 0: +Starting items: 79, 98 +Operation: new = old * 19 +Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: +Starting items: 54, 65, 75, 74 +Operation: new = old + 6 +Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + +Monkey 2: +Starting items: 79, 60, 97 +Operation: new = old * old +Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + +Monkey 3: +Starting items: 74 +Operation: new = old + 3 +Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1 +`) + require.Equal(t, 10605, r) +} + +func TestPart2(t *testing.T) { + r := Part2("") + require.Equal(t, 0, r) +} diff --git a/2022/go/day11/input.txt b/2022/go/day11/input.txt new file mode 100644 index 0000000..e5e8e6e --- /dev/null +++ b/2022/go/day11/input.txt @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 54, 98, 50, 94, 69, 62, 53, 85 + Operation: new = old * 13 + Test: divisible by 3 + If true: throw to monkey 2 + If false: throw to monkey 1 + +Monkey 1: + Starting items: 71, 55, 82 + Operation: new = old + 2 + Test: divisible by 13 + If true: throw to monkey 7 + If false: throw to monkey 2 + +Monkey 2: + Starting items: 77, 73, 86, 72, 87 + Operation: new = old + 8 + Test: divisible by 19 + If true: throw to monkey 4 + If false: throw to monkey 7 + +Monkey 3: + Starting items: 97, 91 + Operation: new = old + 1 + Test: divisible by 17 + If true: throw to monkey 6 + If false: throw to monkey 5 + +Monkey 4: + Starting items: 78, 97, 51, 85, 66, 63, 62 + Operation: new = old * 17 + Test: divisible by 5 + If true: throw to monkey 6 + If false: throw to monkey 3 + +Monkey 5: + Starting items: 88 + Operation: new = old + 3 + Test: divisible by 7 + If true: throw to monkey 1 + If false: throw to monkey 0 + +Monkey 6: + Starting items: 87, 57, 63, 86, 87, 53 + Operation: new = old * old + Test: divisible by 11 + If true: throw to monkey 5 + If false: throw to monkey 0 + +Monkey 7: + Starting items: 73, 59, 82, 65 + Operation: new = old + 6 + Test: divisible by 2 + If true: throw to monkey 4 + If false: throw to monkey 3 \ No newline at end of file diff --git a/2022/go/main.go b/2022/go/main.go index c92f46b..0c06107 100644 --- a/2022/go/main.go +++ b/2022/go/main.go @@ -18,6 +18,8 @@ import ( "adventofcode2022/day08" "adventofcode2022/day09" "adventofcode2022/day10" + "adventofcode2022/day11" + ) @@ -58,6 +60,9 @@ func main() { case 10: fmt.Printf("part 1: %d\n", day10.Part1(utils.Readfile(d))) fmt.Printf("part 2: %s\n", day10.Part2(utils.Readfile(d))) + case 11: + fmt.Printf("part 1: %d\n", day11.Part1(utils.Readfile(d))) + fmt.Printf("part 2: %d\n", day11.Part2(utils.Readfile(d))) default: panic(fmt.Errorf("no such day: %d", d)) } @@ -65,7 +70,7 @@ func main() { // Reads day from os.Args. func day() int { - latest := 9 + latest := 10 if len(os.Args) == 1 { return latest }