Skip to content

Commit b2468f5

Browse files
committed
day15 part1
1 parent cb56eb0 commit b2468f5

File tree

11 files changed

+444
-54
lines changed

11 files changed

+444
-54
lines changed

Package.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ let dependencies: [Target.Dependency] = [
55
.product(name: "Algorithms", package: "swift-algorithms"),
66
.product(name: "Collections", package: "swift-collections"),
77
.product(name: "ArgumentParser", package: "swift-argument-parser"),
8+
.product(name: "MLX", package: "mlx-swift"),
9+
.product(name: "MLXFFT", package: "mlx-swift"),
810
]
911

1012
let package = Package(
1113
name: "aoc",
12-
platforms: [.macOS(.v13)],
14+
platforms: [.macOS(.v14)],
1315
dependencies: [
1416
.package(
1517
url: "https://github.com/apple/swift-algorithms.git",
1618
.upToNextMajor(from: "1.2.0")),
19+
.package(url: "https://github.com/ml-explore/mlx-swift.git", from: "0.21.2"),
1720
.package(
1821
url: "https://github.com/apple/swift-collections.git",
1922
.upToNextMajor(from: "1.0.0")),

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ Below is my current advancement in Advent of code:
2121
| Day 11 | :star: (28min) | :star: (1min) |
2222
| Day 12 | :star: | :star: |
2323
| Day 13 | :star: | :star: (5min) |
24-
| Day 14 | | |
25-
| Day 15 | | |
24+
| Day 14 | :star: | :star: |
25+
| Day 15 | :star: (1h04) | |
2626
| Day 16 | | |
2727
| Day 17 | | |
2828
| Day 18 | | |

Sources/AdventOfCode.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ let allChallenges: [any AdventDay] = [
1515
Day11(),
1616
Day12(),
1717
Day13(),
18+
Day14(),
19+
Day15(),
1820
]
1921

2022
@main

Sources/Day06.swift

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ enum Direction: Int {
55
case East, South, West
66

77
func heading() -> Coord {
8-
Coord.cross[rawValue]
8+
if Coord.cross.indices.contains(rawValue) {
9+
return Coord.cross[rawValue]
10+
}
11+
fatalError()
912
}
1013

1114
static func fromHeading(coord: Coord) -> Self {
@@ -18,7 +21,7 @@ enum Direction: Int {
1821

1922
}
2023

21-
struct Guard {
24+
struct Guard: Hashable {
2225
var pos: Coord
2326
var direction: Direction
2427

@@ -61,29 +64,28 @@ struct Day06: AdventDay {
6164
return (locations, steps, obstacles)
6265
}
6366

64-
func doesComeBack(step: Coord) -> Bool {
65-
var officer = Guard(pos: grid.firstCoord(of: "^")!, direction: .North)
66-
var locations: [Coord] = [Coord]()
67-
while grid.includes(coord: officer.pos) {
68-
locations.append(officer.pos)
67+
func doesComeBack(step: Coord, path: [Coord].SubSequence, grid newGrid: Grid<Character>) -> Bool {
68+
guard let officerPos = newGrid.firstCoord(of: "^") else {
69+
return false
70+
}
71+
var officer = Guard(pos: officerPos, direction: .North)
72+
var locations: [Guard] = [Guard]()
73+
while newGrid.includes(coord: officer.pos) {
74+
// check if we are going over our steps
75+
if locations.contains(officer) {
76+
return true
77+
}
78+
locations.append(officer)
6979

7080
// move the guard
7181
let nextPos = officer.pos + officer.direction.heading()
72-
// behave like there is a real obstacle
73-
if nextPos == step {
74-
officer.direction = officer.direction.makeTurn()
75-
} else {
76-
if !grid.includes(coord: nextPos) {
77-
return false
78-
}
79-
if grid[nextPos] == "#" {
80-
// guard is blocked
81-
officer.direction = officer.direction.makeTurn()
82-
}
82+
83+
if !newGrid.includes(coord: nextPos) {
84+
return false
8385
}
84-
// check if we are going over our steps
85-
if locations.contains([officer.pos, nextPos]) {
86-
return true
86+
if let nextChar = newGrid[nextPos], nextChar == "#" {
87+
// guard is blocked
88+
officer.direction = officer.direction.makeTurn()
8789
}
8890
// move officer one step
8991
officer.pos = officer.pos + officer.direction.heading()
@@ -125,35 +127,25 @@ struct Day06: AdventDay {
125127
}
126128

127129
func part2() -> Int {
130+
131+
let (_, steps, _) = guardPatrol()
128132
var count = 0
129-
let (_, steps, obstacles) = guardPatrol()
130-
131-
var newObstacles: [Coord] = [Coord]()
132-
for (offset, candidates) in obstacles.windows(ofCount: 4).enumerated() {
133-
var c = Array(candidates)
134-
let wrappedOffset = offset % 4
135-
if let coord = isAValidLoop(wrappedOffset: wrappedOffset, c: c) {
136-
count += 1
137-
newObstacles.append(coord)
138-
}
139-
if offset > 4 {
140-
141-
// TODO: this is not right
142-
for (_, elem) in obstacles[0...offset].enumerated() {
143-
let wrappedOffset = offset % 4
144-
c[3] = elem
145-
if let coord = isAValidLoop(wrappedOffset: wrappedOffset, c: c) {
146-
if steps.contains(coord) {
147-
count += 1
148-
newObstacles.append(coord)
149-
}
150-
}
133+
let newSteps = steps.dropFirst()
134+
for (stepIdx, step) in newSteps.enumerated() {
135+
var newGrid = grid
136+
if newGrid.includes(coord: step) {
137+
newGrid.raw[step.y][step.x] = "#"
138+
if doesComeBack(step: step, path: newSteps[0..<stepIdx], grid: newGrid) {
139+
count += 1
140+
print("found a loop at", step)
151141
}
152-
153142
}
154143
}
155-
144+
// 125 -> too low
145+
// 200 -> too low
156146
// 115 -> too low
147+
// 1713 -> not the right answer
148+
157149
return count
158150
}
159151
}

Sources/Day14.swift

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import Algorithms
2+
import Foundation
3+
4+
func getDocumentsDirectory() -> URL {
5+
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
6+
return paths[0]
7+
}
8+
9+
struct Robot: CustomStringConvertible {
10+
var description: String {
11+
"p=\(pos) v=\(velocity)"
12+
}
13+
14+
var pos: Coord
15+
var velocity: Coord
16+
17+
func after(n: Int = 100, width: Int = 101, height: Int = 103) -> Self {
18+
var newPos = self.pos + (self.velocity * n)
19+
newPos.x %= width
20+
newPos.y %= height
21+
if newPos.x < 0 {
22+
newPos.x += width
23+
}
24+
if newPos.y < 0 {
25+
newPos.y += height
26+
}
27+
return Self(pos: newPos, velocity: self.velocity)
28+
}
29+
}
30+
extension Robot {
31+
init(_ values: [Coord]) {
32+
pos = values[0]
33+
velocity = values[1]
34+
}
35+
}
36+
37+
struct Picture {
38+
var width: Int
39+
var height: Int
40+
41+
func toGrid(robots: [Robot]) -> Grid<Bool> {
42+
var grid = Grid<Bool>(
43+
raw: [[Bool]](repeating: [Bool](repeating: false, count: width), count: height))
44+
let robotPos = robots.reduce(into: [Coord: Bool]()) { partialResult, r in
45+
partialResult[r.pos] = true
46+
}
47+
for (pos, _) in robotPos {
48+
grid.raw[pos.y][pos.x] = true
49+
}
50+
return grid
51+
}
52+
53+
func save(for robots: [Robot], at: Int) {
54+
55+
let imageData = toGrid(robots: robots).toImage()
56+
let filename = getDocumentsDirectory().appendingPathComponent("aoc/\(at).pbm")
57+
58+
do {
59+
try imageData.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
60+
} catch {
61+
print("could not write")
62+
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
63+
}
64+
}
65+
}
66+
67+
struct Day14: AdventDay {
68+
var robots: [Robot] = [Robot]()
69+
init(data: String) {
70+
robots = data.lines().map { l in
71+
Robot(
72+
l.replacing(/(p=)|(v=)/, with: "").split(separator: " ").map {
73+
Coord.init(rawValue: String($0))!
74+
})
75+
}
76+
}
77+
78+
func part1() -> Int {
79+
let width = 101
80+
let height = 103
81+
// let width = 11
82+
// let height = 7
83+
let middleX = width / 2
84+
let middleY = height / 2
85+
let nRobots = robots.map { r in
86+
r.after(n: 100, width: width, height: height)
87+
}
88+
let quad1 = nRobots.filter {
89+
$0.pos.x >= 0 && $0.pos.x < middleX && $0.pos.y >= 0 && $0.pos.y < middleY
90+
}
91+
let quad2 = nRobots.filter {
92+
$0.pos.x > middleX && $0.pos.y >= 0 && $0.pos.y < middleY
93+
}
94+
let quad3 = nRobots.filter {
95+
$0.pos.x >= 0 && $0.pos.x < middleX && $0.pos.y > middleY
96+
}
97+
let quad4 = nRobots.filter {
98+
$0.pos.x > middleX && $0.pos.y > middleY
99+
}
100+
let quads = [quad1.count, quad2.count, quad3.count, quad4.count]
101+
return quads.reduce(1, *)
102+
}
103+
104+
func part2_naive() -> Int {
105+
let picture = Picture(width: 101, height: 103)
106+
let nFrames = 8000
107+
for iter in 7000..<nFrames {
108+
let nRobots = robots.map { r in
109+
r.after(n: iter, width: picture.width, height: picture.height)
110+
}
111+
picture.save(for: nRobots, at: iter)
112+
if iter % 1000 == 0 {
113+
print(iter)
114+
}
115+
}
116+
return 0
117+
}
118+
119+
func part2() -> Int {
120+
let width = 101
121+
let height = 103
122+
let picture = Picture(width: width, height: height)
123+
for iter in 0..<(width * height) {
124+
let nRobots = robots.map { r in
125+
r.after(n: iter, width: width, height: height)
126+
}
127+
picture.save(for: nRobots, at: iter)
128+
}
129+
return 0
130+
}
131+
}

0 commit comments

Comments
 (0)