-
Notifications
You must be signed in to change notification settings - Fork 0
/
19.swift
116 lines (107 loc) · 3.7 KB
/
19.swift
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
import Foundation
struct Blueprint {
var n: Int
var ore, clay: Int
var obsidian: (ore: Int, clay: Int)
var geode: (ore: Int, obsidian: Int)
}
struct Items: Hashable {
var ore, clay, obsidian, geode: Int
func add(_ ore: Int, _ clay: Int, _ obsidian: Int, _ geode: Int) -> Items {
return Items(ore: self.ore + ore, clay: self.clay + clay,
obsidian: self.obsidian + obsidian, geode: self.geode + geode)
}
}
struct State: Hashable {
var minute: Int
var values: Items
var robots: Items
init(_ m: Int, _ v: Items, _ r: Items) {
self.minute = m
self.values = v
self.robots = r
}
func val() -> Int {
return robots.ore + robots.clay * 10 + robots.obsidian * 100 + robots.geode * 1000
}
}
func maxgeodes(_ bp: Blueprint, _ minutes: Int, _ maxlen: Int) -> Int {
var m = 0, maxmin = 0, i = 0
var processed = Set<State>()
var queue = [State(0,
Items(ore: 0, clay: 0, obsidian: 0, geode: 0),
Items(ore: 1, clay: 0, obsidian: 0, geode: 0))]
while !queue.isEmpty && i < queue.count {
let s = queue[i]
i += 1
if s.minute == minutes {
m = max(m, s.values.geode)
continue
}
if s.minute > maxmin {
maxmin = s.minute
processed.removeAll()
if queue.count > maxlen {
queue.removeFirst(max(i - 1, 0))
i = 0
queue.sort { $0.val() > $1.val() }
queue.removeLast(max(queue.count - maxlen, 0))
continue
}
}
if processed.contains(s) {
continue
}
processed.insert(s)
if s.values.ore >= bp.geode.ore && s.values.obsidian >= bp.geode.obsidian {
queue.append(State(s.minute + 1,
s.values.add(s.robots.ore - bp.geode.ore, s.robots.clay, s.robots.obsidian - bp.geode.obsidian, s.robots.geode),
s.robots.add(0, 0, 0, 1)))
}
if s.values.ore >= bp.obsidian.ore && s.values.clay >= bp.obsidian.clay {
queue.append(State(s.minute + 1,
s.values.add(s.robots.ore - bp.obsidian.ore, s.robots.clay - bp.obsidian.clay, s.robots.obsidian, s.robots.geode),
s.robots.add(0, 0, 1, 0)))
}
if s.values.ore >= bp.clay {
queue.append(State(s.minute + 1,
s.values.add(s.robots.ore - bp.clay, s.robots.clay, s.robots.obsidian, s.robots.geode),
s.robots.add(0, 1, 0, 0)))
}
if s.values.ore >= bp.ore {
queue.append(State(s.minute + 1,
s.values.add(s.robots.ore - bp.ore, s.robots.clay, s.robots.obsidian, s.robots.geode),
s.robots.add(1, 0, 0, 0)))
}
queue.append(State(s.minute + 1,
s.values.add(s.robots.ore, s.robots.clay, s.robots.obsidian, s.robots.geode), s.robots))
}
return m
}
var blueprints = [Blueprint]()
while let line = readLine() {
let n = line.numbers
blueprints.append(Blueprint(n: n[0], ore: n[1], clay: n[2], obsidian: (n[3], n[4]), geode: (n[5], n[6])))
}
var part1 = 0
for bp in blueprints {
part1 += bp.n * maxgeodes(bp, 24, 2000000)
}
var part2 = 1
for bp in blueprints.prefix(3) {
part2 *= maxgeodes(bp, 32, 2000000)
}
print(part1, part2)
extension String {
var numbers: [Int] {
guard let regex = try? NSRegularExpression(pattern: "-?\\d+", options: [.caseInsensitive]) else {
return []
}
let matches = regex.matches(in: self, options: [], range: NSMakeRange(0, self.count))
return matches.map { match in
String(self[Range(match.range, in: self)!])
}.map {
Int($0)!
}
}
}