Skip to content

Commit c13fa1c

Browse files
committed
day9 quelle horreur
1 parent 5416ba7 commit c13fa1c

File tree

4 files changed

+229
-1
lines changed

4 files changed

+229
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Below is my current advancement in Advent of code:
1616
| Day 6 | :star: | :sad: |
1717
| Day 7 | :star: (45min) | :star: (33min) |
1818
| Day 8 | :star: (20min) | :star: (16min) |
19-
| Day 9 | | |
19+
| Day 9 | :star: (1h51) | :star: (43min) |
2020
| Day 10 | | |
2121
| Day 11 | | |
2222
| Day 12 | | |

Sources/AdventOfCode.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ let allChallenges: [any AdventDay] = [
1010
Day06(),
1111
Day07(),
1212
Day08(),
13+
Day09(),
1314
]
1415

1516
@main

Sources/Day09.swift

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import Algorithms
2+
3+
struct Space: CustomStringConvertible {
4+
var fileId: Int?
5+
var capacity: Int
6+
7+
var description: String {
8+
"\(fileId ?? -1)(\(capacity))"
9+
}
10+
}
11+
12+
struct IndexedSpace: CustomStringConvertible {
13+
var fileId: Int?
14+
var capacity: Int
15+
var startIndex: Int
16+
17+
var description: String {
18+
"\(fileId ?? -1)(\(capacity))"
19+
}
20+
}
21+
extension IndexedSpace {
22+
init(space: Space, startIndex: Int) {
23+
capacity = space.capacity
24+
fileId = space.fileId
25+
self.startIndex = startIndex
26+
}
27+
}
28+
29+
struct File: CustomStringConvertible {
30+
var startIndex: Int
31+
var fileId: Int
32+
var capacity: Int
33+
34+
var description: String {
35+
"\(fileId)=(\(capacity)) \(startIndex)"
36+
}
37+
38+
func computeValue() -> Int {
39+
(startIndex..<startIndex + capacity).map { $0 * fileId }.sum
40+
}
41+
}
42+
extension File {
43+
init(space: Space, startIndex: Int) {
44+
capacity = space.capacity
45+
fileId = space.fileId ?? 0
46+
self.startIndex = startIndex
47+
}
48+
init(space: IndexedSpace) {
49+
capacity = space.capacity
50+
fileId = space.fileId ?? 0
51+
startIndex = space.startIndex
52+
}
53+
}
54+
55+
typealias SpaceIndex = [Int: Space]
56+
57+
struct Day09: AdventDay {
58+
var data: String
59+
60+
func parse(data: String) -> (disk: SpaceIndex, free: SpaceIndex) {
61+
var pointer = 0
62+
var disk: [Int: Space] = [Int: Space]()
63+
var free: [Int: Space] = [Int: Space]()
64+
for (idx, block) in data.trimmed().enumerated() {
65+
let capacity = Int(String(block)) ?? 0
66+
let isFree = idx % 2 != 0
67+
let fileId: Int? = if isFree { nil } else { idx / 2 }
68+
let space = Space(fileId: fileId, capacity: capacity)
69+
70+
// store free space
71+
if isFree {
72+
free[pointer] = space
73+
} else {
74+
disk[pointer] = space
75+
}
76+
77+
pointer += capacity
78+
}
79+
80+
return (disk, free: free.filter { $0.value.capacity != 0 })
81+
}
82+
83+
func part1() -> Int {
84+
var (disk, free) = parse(data: data)
85+
var newDisk = [File]()
86+
var pointer = 0
87+
var iterNum = 0
88+
while disk.count > 0 {
89+
iterNum += 1
90+
if let file = disk[pointer] {
91+
// add the file to the new disk allocation
92+
newDisk.append(File(startIndex: pointer, fileId: file.fileId ?? 0, capacity: file.capacity))
93+
// remove from disk copy
94+
disk.removeValue(forKey: pointer)
95+
// increment the pointer
96+
pointer += file.capacity
97+
if disk.count == 0 {
98+
print("we are done here !")
99+
break
100+
}
101+
continue
102+
}
103+
if let freeSpace = free[pointer] {
104+
// find the file to fill the gap
105+
let lastFileIndex = disk.keys.max() ?? 0
106+
guard let file = disk[lastFileIndex] else {
107+
print("no file available")
108+
continue
109+
}
110+
111+
if freeSpace.capacity >= file.capacity {
112+
// add file to the list
113+
newDisk.append(
114+
File(startIndex: pointer, fileId: file.fileId ?? 0, capacity: file.capacity))
115+
// remove the file from the disk
116+
disk.removeValue(forKey: lastFileIndex)
117+
// remove the free space and insert the new free space
118+
free.removeValue(forKey: pointer)
119+
120+
let newPointer = pointer + file.capacity
121+
if freeSpace.capacity != file.capacity {
122+
// add a new free space
123+
let newCapacity = freeSpace.capacity - file.capacity
124+
free[newPointer] = Space(capacity: newCapacity)
125+
}
126+
pointer = newPointer
127+
continue
128+
}
129+
if freeSpace.capacity < file.capacity {
130+
let newFile = File(
131+
startIndex: pointer, fileId: file.fileId ?? 0, capacity: freeSpace.capacity)
132+
// add file to the list
133+
newDisk.append(newFile)
134+
// reduce the file on the disk
135+
disk[lastFileIndex]?.capacity -= freeSpace.capacity
136+
// remove the free space and insert the new free space
137+
free.removeValue(forKey: pointer)
138+
139+
let newPointer = pointer + freeSpace.capacity
140+
pointer = newPointer
141+
continue
142+
}
143+
}
144+
}
145+
146+
return newDisk.map { file in
147+
file.computeValue()
148+
}.sum
149+
}
150+
151+
func parse2(data: String) -> (disk: [IndexedSpace], free: [IndexedSpace]) {
152+
var pointer = 0
153+
var disk: [IndexedSpace] = [IndexedSpace]()
154+
var free: [IndexedSpace] = [IndexedSpace]()
155+
for (idx, block) in data.trimmed().enumerated() {
156+
let capacity = Int(String(block)) ?? 0
157+
let isFree = idx % 2 != 0
158+
let fileId: Int? = if isFree { nil } else { idx / 2 }
159+
let space = IndexedSpace(fileId: fileId, capacity: capacity, startIndex: pointer)
160+
// store free space
161+
if isFree {
162+
free.append(space)
163+
} else {
164+
disk.append(space)
165+
}
166+
pointer += capacity
167+
}
168+
return (disk, free)
169+
}
170+
171+
func part2() -> Int {
172+
var (disk, free) = parse2(data: data)
173+
// first file will always be at the beginning
174+
var newDisk: [File] = [File(space: disk[0])]
175+
for file in disk[1..<disk.count].reversed() {
176+
// find the first spot that is available
177+
if let spotIndex = free.firstIndex(where: {
178+
$0.capacity >= file.capacity && $0.startIndex < file.startIndex
179+
}) {
180+
let spot = free[spotIndex]
181+
var newFile = File(space: file)
182+
newFile.startIndex = spot.startIndex
183+
newDisk.append(newFile)
184+
if spot.capacity == file.capacity {
185+
free.remove(at: spotIndex)
186+
} else {
187+
free[spotIndex].capacity -= file.capacity
188+
free[spotIndex].startIndex += file.capacity
189+
}
190+
} else {
191+
newDisk.append(File(space: file))
192+
}
193+
}
194+
195+
return newDisk.map { file in
196+
file.computeValue()
197+
}.sum
198+
}
199+
}

Tests/Day09.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Testing
2+
3+
@testable import aoc
4+
5+
@Suite("Day09")
6+
struct Day09Tests {
7+
let testData = """
8+
2333133121414131402
9+
"""
10+
11+
@Test("simple part")
12+
func testSimplePart1() async throws {
13+
#expect(Day09(data: "1234").part1() == 6)
14+
#expect(Day09(data: "12345").part1() == 60)
15+
}
16+
17+
@Test("part1")
18+
func testPart1() async throws {
19+
let challenge = Day09(data: testData)
20+
#expect(challenge.part1() == 1928)
21+
}
22+
23+
@Test("part2")
24+
func testPart2() async throws {
25+
let challenge = Day09(data: testData)
26+
#expect(challenge.part2() == 2858)
27+
}
28+
}

0 commit comments

Comments
 (0)