advent2022

Advent of Code 2022 Solutions
git clone git://bsandro.tech/advent2022
Log | Files | Refs | README | LICENSE

main.go (4903B)


      1 package main
      2 
      3 import (
      4 	"bufio"
      5 	"fmt"
      6 	"log"
      7 	"os"
      8 	"sort"
      9 	"strconv"
     10 	"strings"
     11 )
     12 
     13 type Monkey struct {
     14 	items           []uint64
     15 	orig            []uint64
     16 	operation       func(val uint64) uint64
     17 	test            uint64 // divisible by
     18 	ifTrue, ifFalse int    // pass to monkeys
     19 	count           uint64 // how many times monkey inspected items
     20 }
     21 
     22 func (m *Monkey) Reset() {
     23 	m.items = nil
     24 	m.items = append(m.items, m.orig...)
     25 	m.count = 0
     26 }
     27 func (m *Monkey) parseItems(in string) {
     28 	items := strings.Split(in, ",")
     29 	for _, i := range items {
     30 		item, err := strconv.Atoi(strings.TrimSpace(i))
     31 		if err != nil {
     32 			log.Fatal(err)
     33 		}
     34 		m.items = append(m.items, uint64(item))
     35 		m.orig = append(m.orig, uint64(item))
     36 	}
     37 }
     38 func (m *Monkey) parseOperation(in string) {
     39 	var v, op string
     40 	_, err := fmt.Sscanf(in, "new = old %s %s", &op, &v)
     41 	if err != nil {
     42 		log.Fatal(err)
     43 	}
     44 	m.operation = func(val uint64) uint64 {
     45 		if op == "*" {
     46 			if v == "old" {
     47 				return val * val
     48 			} else {
     49 				num, err := strconv.Atoi(v)
     50 				if err != nil {
     51 					log.Fatal(err)
     52 				}
     53 				return val * uint64(num)
     54 			}
     55 		} else if op == "+" {
     56 			if v == "old" {
     57 				return val + val
     58 			} else {
     59 				num, err := strconv.Atoi(v)
     60 				if err != nil {
     61 					log.Fatal(err)
     62 				}
     63 				return val + uint64(num)
     64 			}
     65 		} else {
     66 			log.Fatal("invalid operation", op)
     67 		}
     68 		return val
     69 	}
     70 }
     71 func (m *Monkey) parseTest(in string) {
     72 	_, err := fmt.Sscanf(in, "divisible by %d", &m.test)
     73 	if err != nil {
     74 		log.Fatal(err)
     75 	}
     76 }
     77 func (m *Monkey) parseIfTrue(in string) {
     78 	_, err := fmt.Sscanf(in, "throw to monkey %d", &m.ifTrue)
     79 	if err != nil {
     80 		log.Fatal(err)
     81 	}
     82 }
     83 func (m *Monkey) parseIfFalse(in string) {
     84 	_, err := fmt.Sscanf(in, "throw to monkey %d", &m.ifFalse)
     85 	if err != nil {
     86 		log.Fatal(err)
     87 	}
     88 }
     89 func (m *Monkey) processItem1(i int) int {
     90 	if i >= len(m.items) {
     91 		log.Fatal("invalid item id")
     92 	}
     93 	m.items[i] = m.operation(m.items[i])
     94 	m.items[i] /= 3
     95 	m.count++
     96 	if m.items[i]%m.test == 0 {
     97 		return m.ifTrue
     98 	} else {
     99 		return m.ifFalse
    100 	}
    101 }
    102 func (m *Monkey) processItem2(i int) int {
    103 	if i >= len(m.items) {
    104 		log.Fatal("invalid item id")
    105 	}
    106 	m.items[i] = m.operation(m.items[i])
    107 	m.count++
    108 	if m.items[i]%m.test == 0 {
    109 		return m.ifTrue
    110 	} else {
    111 		return m.ifFalse
    112 	}
    113 }
    114 
    115 type Monkeys []*Monkey
    116 
    117 func (m *Monkeys) Reset() {
    118 	for _, monkey := range *m {
    119 		monkey.Reset()
    120 	}
    121 }
    122 func (m Monkeys) Len() int { return len(m) }
    123 func (m Monkeys) Swap(i, j int) {
    124 	m[i], m[j] = m[j], m[i]
    125 }
    126 func (m Monkeys) Less(i, j int) bool {
    127 	return m[i].count > m[j].count
    128 }
    129 func (monkeys Monkeys) GetCommon() uint64 {
    130 	var common uint64 = 1
    131 	for _, m := range monkeys {
    132 		common *= m.test
    133 	}
    134 	return common
    135 }
    136 func (monkeys Monkeys) DoTurn1() {
    137 	for _, m := range monkeys {
    138 		for n, _ := range m.items {
    139 			t := m.processItem1(n)
    140 			target := monkeys[t]
    141 			target.items = append(target.items, m.items[n])
    142 		}
    143 		m.items = nil
    144 	}
    145 }
    146 func (monkeys Monkeys) DoTurn2(common uint64) {
    147 	for _, m := range monkeys {
    148 		for n, _ := range m.items {
    149 			m.items[n] %= common
    150 			t := m.processItem2(n)
    151 			target := monkeys[t]
    152 			target.items = append(target.items, m.items[n])
    153 		}
    154 		m.items = nil
    155 	}
    156 }
    157 func (monkeys Monkeys) GetCounts() []uint64 {
    158 	var counts []uint64
    159 	for _, m := range monkeys {
    160 		counts = append(counts, m.count)
    161 	}
    162 	return counts
    163 }
    164 
    165 func main() {
    166 	if len(os.Args) > 1 {
    167 		day11(os.Args[1])
    168 	} else if len(os.Args) == 1 {
    169 		fmt.Printf("usage: %s inputfile.txt\n", os.Args[0])
    170 	} else {
    171 		fmt.Println("No input data")
    172 	}
    173 }
    174 
    175 func day11(input_file string) {
    176 	fmt.Printf("day 11 input filename: %s\n", input_file)
    177 	input, err := os.Open(input_file)
    178 	if err != nil {
    179 		log.Fatal(err)
    180 	}
    181 	defer input.Close()
    182 	scanner := bufio.NewScanner(input)
    183 	var monkeys Monkeys
    184 	current := -1
    185 	for scanner.Scan() {
    186 		in := scanner.Text()
    187 		if in == "" {
    188 			continue
    189 		}
    190 		field, val, _ := strings.Cut(in, ":")
    191 		field = strings.TrimSpace(field)
    192 		val = strings.TrimSpace(val)
    193 		switch field {
    194 		case "Starting items":
    195 			monkeys[current].parseItems(val)
    196 		case "Operation":
    197 			monkeys[current].parseOperation(val)
    198 		case "Test":
    199 			monkeys[current].parseTest(val)
    200 		case "If true":
    201 			monkeys[current].parseIfTrue(val)
    202 		case "If false":
    203 			monkeys[current].parseIfFalse(val)
    204 		default:
    205 			if n, err := fmt.Sscanf(in, "Monkey %d", &current); n != 1 || err != nil {
    206 				log.Fatal("Invalid input", in, err)
    207 			} else {
    208 				// new monkey
    209 				monkeys = append(monkeys, &Monkey{})
    210 			}
    211 		}
    212 	}
    213 	if err = scanner.Err(); err != nil {
    214 		log.Fatal(err)
    215 	}
    216 
    217 	var monkeys2 Monkeys
    218 	monkeys2 = append(monkeys2, monkeys...)
    219 	for i := 0; i < 20; i++ {
    220 		monkeys.DoTurn1()
    221 	}
    222 	sort.Sort(monkeys)
    223 	fmt.Println("Monkey business 1:", monkeys[0].count*monkeys[1].count)
    224 
    225 	monkeys2.Reset()
    226 	common := monkeys2.GetCommon()
    227 	for i := 0; i < 10000; i++ {
    228 		monkeys2.DoTurn2(common)
    229 	}
    230 	sort.Sort(monkeys2)
    231 	fmt.Println("Monkey business 2:", monkeys2[0].count*monkeys2[1].count)
    232 }