-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
101 lines (85 loc) · 2.1 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main
import (
"bufio"
"fmt"
"log"
"os"
"regexp"
"strconv"
"strings"
)
// bagContent is a structure of bags which can be carried in another bag
type bagContent struct {
name string
number int
}
// canCarry determines if the "search" bag can be carried in the "in" bag
func canCarry(search string, in string, bags map[string][]bagContent) bool {
bag := bags[in]
if len(bag) == 0 {
return false
}
// test the current and the nested bags
for _, n := range bag {
if n.name == search || canCarry(search, n.name, bags) {
return true
}
}
return false
}
// haveToContain calculates how many bags the specified bag have to contain
func haveToContain(name string, bags map[string][]bagContent) int {
if len(bags[name]) == 0 {
return 0
}
// summarize the number of nested bags
res := 0
for _, v := range bags[name] {
res += v.number * (1 + haveToContain(v.name, bags))
}
return res
}
func main() {
// open file with the input values
file, err := os.Open("input.txt")
if err != nil {
log.Fatal("Cannot open the input file.")
}
defer file.Close()
// open a scanner to read from the file
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
// process all lines
bags := make(map[string][]bagContent)
for scanner.Scan() {
val := scanner.Text()
// extract the bag data into better form
bag := strings.Split(val[:len(val)-1], " bags contain ")
color := bag[0]
contains := regexp.MustCompile(" bags?(, )?").Split(bag[1], -1)
contains = contains[:len(contains)-1]
// store all bags in bags map
bags[color] = []bagContent{}
for _, v := range contains {
c := strings.SplitN(v, " ", 2)
// store only if the bag can content any other one
if c[1] != "other" {
num, _ := strconv.Atoi(c[0])
bags[color] = append(bags[color], bagContent{
name: c[1],
number: num,
})
}
}
}
// calculate how many bags can carry my bag
carryable := 0
for k := range bags {
if canCarry("shiny gold", k, bags) {
carryable++
}
}
// print the result
fmt.Println("Part 1:", carryable)
fmt.Println("Part 2:", haveToContain("shiny gold", bags))
}