Skip to content

Commit

Permalink
Solution for Day 11
Browse files Browse the repository at this point in the history
  • Loading branch information
nlowe committed Dec 11, 2022
1 parent 59186ea commit f130474
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 0 deletions.
2 changes: 2 additions & 0 deletions challenge/cmd/cmd.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions challenge/day11/a.go
@@ -0,0 +1,27 @@
package day11

import (
"fmt"

"github.com/spf13/cobra"

"github.com/nlowe/aoc2022/challenge"
)

func aCommand() *cobra.Command {
return &cobra.Command{
Use: "a",
Short: "Day 11, Problem A",
Run: func(_ *cobra.Command, _ []string) {
fmt.Printf("Answer: %d\n", partA(challenge.FromFile()))
},
}
}

func partA(challenge *challenge.Input) int {
monkeys := parse(challenge)

simulateAndSort(monkeys, 20, 0)

return monkeys[0].inspections * monkeys[1].inspections
}
45 changes: 45 additions & 0 deletions challenge/day11/a_test.go
@@ -0,0 +1,45 @@
package day11

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/nlowe/aoc2022/challenge"
)

const example = `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`

func TestA(t *testing.T) {
input := challenge.FromLiteral(example)

result := partA(input)

require.Equal(t, 10605, result)
}
35 changes: 35 additions & 0 deletions challenge/day11/b.go
@@ -0,0 +1,35 @@
package day11

import (
"fmt"

"github.com/nlowe/aoc2022/util/gmath"

"github.com/spf13/cobra"

"github.com/nlowe/aoc2022/challenge"
)

func bCommand() *cobra.Command {
return &cobra.Command{
Use: "b",
Short: "Day 11, Problem B",
Run: func(_ *cobra.Command, _ []string) {
fmt.Printf("Answer: %d\n", partB(challenge.FromFile()))
},
}
}

func partB(challenge *challenge.Input) int {
monkeys := parse(challenge)

checks := make([]int, len(monkeys))
for i, m := range monkeys {
checks[i] = m.test
}

shrink := gmath.LCM(checks...)

simulateAndSort(monkeys, 10000, shrink)
return monkeys[0].inspections * monkeys[1].inspections
}
17 changes: 17 additions & 0 deletions challenge/day11/b_test.go
@@ -0,0 +1,17 @@
package day11

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/nlowe/aoc2022/challenge"
)

func TestB(t *testing.T) {
input := challenge.FromLiteral(example)

result := partB(input)

require.Equal(t, 2713310158, result)
}
19 changes: 19 additions & 0 deletions challenge/day11/benchmark_test.go
@@ -0,0 +1,19 @@
package day11

import (
"testing"

"github.com/nlowe/aoc2022/challenge"
)

func BenchmarkA(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = partA(challenge.FromFile())
}
}

func BenchmarkB(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = partB(challenge.FromFile())
}
}
17 changes: 17 additions & 0 deletions challenge/day11/import.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 55 additions & 0 deletions challenge/day11/input.txt
@@ -0,0 +1,55 @@
Monkey 0:
Starting items: 99, 67, 92, 61, 83, 64, 98
Operation: new = old * 17
Test: divisible by 3
If true: throw to monkey 4
If false: throw to monkey 2

Monkey 1:
Starting items: 78, 74, 88, 89, 50
Operation: new = old * 11
Test: divisible by 5
If true: throw to monkey 3
If false: throw to monkey 5

Monkey 2:
Starting items: 98, 91
Operation: new = old + 4
Test: divisible by 2
If true: throw to monkey 6
If false: throw to monkey 4

Monkey 3:
Starting items: 59, 72, 94, 91, 79, 88, 94, 51
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 0
If false: throw to monkey 5

Monkey 4:
Starting items: 95, 72, 78
Operation: new = old + 7
Test: divisible by 11
If true: throw to monkey 7
If false: throw to monkey 6

Monkey 5:
Starting items: 76
Operation: new = old + 8
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 2

Monkey 6:
Starting items: 69, 60, 53, 89, 71, 88
Operation: new = old + 5
Test: divisible by 19
If true: throw to monkey 7
If false: throw to monkey 1

Monkey 7:
Starting items: 72, 54, 63, 80
Operation: new = old + 3
Test: divisible by 7
If true: throw to monkey 1
If false: throw to monkey 3
116 changes: 116 additions & 0 deletions challenge/day11/monkey.go
@@ -0,0 +1,116 @@
package day11

import (
"fmt"
"sort"
"strings"

"github.com/nlowe/aoc2022/challenge"
"github.com/nlowe/aoc2022/util"
)

type monkey struct {
items []int

op func(int) int
test int

pass int
fail int

inspections int
}

func parse(challenge *challenge.Input) []*monkey {
sections := challenge.SectionSlice()

monkeys := make([]*monkey, len(sections))
for i, spec := range sections {
m := &monkey{}

lines := strings.Split(spec, "\n")
rawItems := strings.Split(strings.TrimPrefix(lines[1], " Starting items: "), ", ")
for _, item := range rawItems {
m.items = append(m.items, util.MustAtoI(item))
}

rawOp := strings.Fields(lines[2])
switch rawOp[4] {
case "+":
if rawOp[5] == "old" {
m.op = makeSelfAddOp()
} else {
m.op = makeAddOp(util.MustAtoI(rawOp[5]))
}
case "*":
if rawOp[5] == "old" {
m.op = makeSelfMulOp()
} else {
m.op = makeMulOp(util.MustAtoI(rawOp[5]))
}
default:
panic(fmt.Errorf("unknown op '%s' for func: %s", rawOp[4], lines[2]))
}

m.test = util.MustAtoI(strings.Fields(lines[3])[3])
m.pass = util.MustAtoI(strings.Fields(lines[4])[5])
m.fail = util.MustAtoI(strings.Fields(lines[5])[5])

monkeys[i] = m
}

return monkeys
}

func simulateAndSort(monkeys []*monkey, turns, shrink int) {
for i := 0; i < turns; i++ {
for _, m := range monkeys {
var item int
for len(m.items) > 0 {
m.inspections++
item, m.items = m.items[0], m.items[1:]

item = m.op(item)
if shrink == 0 {
item /= 3
} else {
item %= shrink
}

if item%m.test == 0 {
monkeys[m.pass].items = append(monkeys[m.pass].items, item)
} else {
monkeys[m.fail].items = append(monkeys[m.fail].items, item)
}
}
}
}

sort.Slice(monkeys, func(i, j int) bool {
return monkeys[i].inspections > monkeys[j].inspections
})
}

func makeSelfAddOp() func(int) int {
return func(old int) int {
return old + old
}
}

func makeAddOp(off int) func(int) int {
return func(old int) int {
return old + off
}
}

func makeSelfMulOp() func(int) int {
return func(old int) int {
return old * old
}
}

func makeMulOp(off int) func(int) int {
return func(old int) int {
return old * off
}
}
33 changes: 33 additions & 0 deletions challenge/input.go
Expand Up @@ -69,6 +69,31 @@ func (c *Input) Lines() <-chan string {
return c.lines
}

func (c *Input) Sections() <-chan string {
sections := make(chan string)
go func() {
defer close(sections)
section := strings.Builder{}

for line := range c.lines {
section.WriteString(line)

if line == "" {
sections <- strings.TrimSpace(section.String())
section.Reset()
} else {
section.WriteRune('\n')
}
}

if section.Len() != 0 {
sections <- strings.TrimSpace(section.String())
}
}()

return sections
}

func (c *Input) Ints() <-chan int {
result := make(chan int)

Expand Down Expand Up @@ -98,3 +123,11 @@ func (c *Input) IntSlice() (result []int) {

return
}

func (c *Input) SectionSlice() (result []string) {
for section := range c.Sections() {
result = append(result, section)
}

return
}

0 comments on commit f130474

Please sign in to comment.