-
Notifications
You must be signed in to change notification settings - Fork 0
/
16.go
140 lines (123 loc) · 3.05 KB
/
16.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"fmt"
"io/ioutil"
"strconv"
"strings"
)
type rule struct {
firstBounds, secondBounds bounds
possiblePositions map[int]struct{}
}
type bounds struct {
lower, upper int
}
var newLine = "\r\n"
func main() {
lines := prepInput(parseInput())
possiblePositions := make(map[int]struct{})
for i := 0; i < len(strings.Split(lines[27], ",")); i++ {
possiblePositions[i] = struct{}{}
}
rules := make(map[string]rule)
for _, line := range lines[:20] {
words := strings.Fields(line)
var firstBounds, secondBounds bounds
fmt.Sscanf(words[len(words)-3], "%d-%d", &firstBounds.lower, &firstBounds.upper)
fmt.Sscanf(words[len(words)-1], "%d-%d", &secondBounds.lower, &secondBounds.upper)
currentPossiblePositions := copy(possiblePositions)
name := words[0]
if len(words) > 4 {
name = words[0] + words[1]
}
currentRule := rule{firstBounds, secondBounds, currentPossiblePositions}
rules[name] = currentRule
}
errorRate := 0
tickets:
for _, line := range lines[25:] {
values := strings.Split(line, ",")
valid:
for _, valStr := range values {
value, _ := strconv.Atoi(valStr)
for _, currentRule := range rules {
if currentRule.isAllowed(value) {
continue valid
}
}
errorRate += value
continue tickets
}
//only valid tickets here
for i, valStr := range values {
for _, currentRule := range rules {
value, _ := strconv.Atoi(valStr)
if !currentRule.isAllowed(value) {
delete(currentRule.possiblePositions, i)
}
}
}
}
fmt.Println(errorRate)
rulesAndPositions := findExactRulePositions(rules)
result := 1
for name, rule := range rulesAndPositions {
myTicket := strings.Split(lines[22], ",")
if strings.HasPrefix(name, "departure") {
var i int
for i = range rule.possiblePositions {
break
}
num, _ := strconv.Atoi(myTicket[i])
result = result * num
}
}
fmt.Println(result)
}
func copy(in map[int]struct{}) map[int]struct{} {
result := make(map[int]struct{})
for i := range in {
result[i] = in[i]
}
return result
}
func (r *rule) isAllowed(value int) bool {
return r.firstBounds.isWithin(value) || r.secondBounds.isWithin(value)
}
func (b *bounds) isWithin(value int) bool {
return value >= b.lower && value <= b.upper
}
func findExactRulePositions(rules map[string]rule) map[string]rule {
rulesAndPositions := make(map[string]rule)
for len(rules) > 0 {
rules:
for name, currentRule := range rules {
for i := range currentRule.possiblePositions {
count := 0
for _, secondRule := range rules {
if _, exists := secondRule.possiblePositions[i]; exists {
count++
}
}
if count == 1 {
currentRule.possiblePositions = map[int]struct{}{i: {}}
rulesAndPositions[name] = currentRule
delete(rules, name)
continue rules
}
}
}
}
return rulesAndPositions
}
func parseInput() []byte {
input, err := ioutil.ReadFile("input.txt")
if err != nil {
panic(err)
}
return input
}
func prepInput(input []byte) []string {
lines := strings.Split(strings.TrimSpace(string(input)), newLine)
return lines
}