Skip to content

Commit 24c8f10

Browse files
committed
day6 part 1 only could not get part 2
1 parent a1e8d32 commit 24c8f10

File tree

5 files changed

+244
-1
lines changed

5 files changed

+244
-1
lines changed

Sources/AdventOfCode.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ let allChallenges: [any AdventDay] = [
77
Day03(),
88
Day04(),
99
Day05(),
10+
Day06(),
1011
]
1112

1213
@main

Sources/Day06.swift

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import Algorithms
2+
3+
enum Direction: Int {
4+
case North = 0
5+
case East, South, West
6+
7+
func heading() -> Coord {
8+
Coord.cross[rawValue]
9+
}
10+
11+
static func fromHeading(coord: Coord) -> Self {
12+
Self(rawValue: Coord.cross.firstIndex { $0 == coord } ?? 0) ?? .North
13+
}
14+
15+
func makeTurn() -> Self {
16+
Self(rawValue: self.rawValue + 1 % 4) ?? .North
17+
}
18+
19+
}
20+
21+
struct Guard {
22+
var pos: Coord
23+
var direction: Direction
24+
25+
func nextPost() -> Coord {
26+
self.pos + self.direction.heading()
27+
}
28+
}
29+
30+
struct Day06: AdventDay {
31+
var grid: Grid
32+
init(data: String) {
33+
grid = Grid(from: data)
34+
}
35+
36+
func guardPatrol() -> (locations: Set<Coord>, steps: [Coord], obstacles: [Coord]) {
37+
var locations: Set<Coord> = Set()
38+
var steps: [Coord] = [Coord]()
39+
var obstacles: [Coord] = [Coord]()
40+
var officer = Guard(pos: grid.firstCoord(of: "^")!, direction: .North)
41+
while officer.pos.isInside(grid: grid) {
42+
// save position
43+
locations.insert(officer.pos)
44+
45+
// move the guard
46+
let nextPos = officer.pos + officer.direction.heading()
47+
if !grid.includes(coord: nextPos) {
48+
obstacles.append(nextPos)
49+
steps.append(nextPos)
50+
break
51+
}
52+
if grid[nextPos] == "#" {
53+
obstacles.append(nextPos)
54+
// guard is blocked
55+
officer.direction = officer.direction.makeTurn()
56+
}
57+
// move officer one step
58+
officer.pos = officer.pos + officer.direction.heading()
59+
steps.append(officer.pos)
60+
}
61+
return (locations, steps, obstacles)
62+
}
63+
64+
func doesComeBack(step: Coord) -> Bool {
65+
var officer = Guard(pos: grid.firstCoord(of: "^")!, direction: .North)
66+
var locations: [Coord] = [Coord]()
67+
while officer.pos.isInside(grid: grid) {
68+
locations.append(officer.pos)
69+
70+
// move the guard
71+
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+
77+
if !grid.includes(coord: nextPos) {
78+
return false
79+
}
80+
if grid[nextPos] == "#" {
81+
// guard is blocked
82+
officer.direction = officer.direction.makeTurn()
83+
}
84+
}
85+
// check if we are going over our steps
86+
if locations.contains([officer.pos, nextPos]) {
87+
return true
88+
}
89+
// move officer one step
90+
officer.pos = officer.pos + officer.direction.heading()
91+
}
92+
return false
93+
}
94+
95+
func part1() -> Int {
96+
guardPatrol().locations.count
97+
}
98+
99+
// func part2() -> Int {
100+
// var potentialObstacles: [Coord] = [Coord]()
101+
// for step in Set(guardPatrol().steps) {
102+
// if doesComeBack(step: step) {
103+
// potentialObstacles.append(step)
104+
// }
105+
// }
106+
// return Set(potentialObstacles).count
107+
// }
108+
109+
func isAValidLoop(wrappedOffset: Int, c: [Coord]) -> Coord? {
110+
if wrappedOffset == 0 {
111+
if c[c.startIndex].x > c[c.endIndex - 1].x {
112+
let coord = Coord(x: c[c.startIndex].x - 1, y: c[c.endIndex - 1].y)
113+
print("yes 0", coord)
114+
return coord
115+
}
116+
}
117+
if wrappedOffset == 1 {
118+
if c[c.startIndex].y > c[c.endIndex - 1].y {
119+
let coord = Coord(x: c[c.startIndex].x, y: c[c.startIndex].y - 1)
120+
print("yes 1", coord)
121+
return coord
122+
}
123+
}
124+
if wrappedOffset == 2 {
125+
126+
if c[c.startIndex].x < c[c.endIndex - 1].x {
127+
let coord = Coord(x: c[c.endIndex - 1].x + 1, y: c[c.startIndex].y)
128+
print("yes 2", coord)
129+
return coord
130+
}
131+
}
132+
if wrappedOffset == 3 {
133+
if c[c.startIndex].y < c[c.endIndex - 1].y {
134+
let coord = Coord(x: c[c.endIndex - 1].x, y: c[c.startIndex].y + 1)
135+
print("yes 3", coord)
136+
return coord
137+
}
138+
}
139+
return nil
140+
}
141+
142+
func part2() -> Int {
143+
var count = 0
144+
let obstacles = guardPatrol().obstacles
145+
146+
var newObstacles: [Coord] = [Coord]()
147+
for (offset, candidates) in obstacles.windows(ofCount: 4).enumerated() {
148+
var c = Array(candidates)
149+
let wrappedOffset = offset % 4
150+
if let coord = isAValidLoop(wrappedOffset: wrappedOffset, c: c) {
151+
count += 1
152+
newObstacles.append(coord)
153+
}
154+
if offset > 4 {
155+
156+
// TODO: this is not right
157+
for (idx, elem) in obstacles[0...0].enumerated() {
158+
print("trying", idx, elem)
159+
let wrappedOffset = offset % 4
160+
c[3] = elem
161+
if let coord = isAValidLoop(wrappedOffset: wrappedOffset, c: c) {
162+
count += 1
163+
newObstacles.append(coord)
164+
print(c)
165+
}
166+
}
167+
168+
}
169+
}
170+
print(newObstacles)
171+
172+
// 115 -> too low
173+
return count
174+
}
175+
}

Sources/Helpers/Coord.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ struct Coord {
1515
/// Offsets for the cross elements (+ shape)
1616
///
1717
static let cross = [
18+
//north
1819
Coord(x: 0, y: -1),
20+
// east
21+
Coord(x: 1, y: 0),
22+
// south
1923
Coord(x: 0, y: 1),
24+
// west
2025
Coord(x: -1, y: 0),
21-
Coord(x: 1, y: 0),
2226
]
2327

2428
var cornerNeighbors: [Coord] {
@@ -41,6 +45,28 @@ struct Coord {
4145

4246
extension Coord: Equatable {}
4347

48+
extension Coord: Hashable {}
49+
50+
extension Coord: RawRepresentable {
51+
init?(rawValue: String) {
52+
let parts = rawValue.integers(separator: ",")
53+
x = parts[0]
54+
y = parts[1]
55+
}
56+
57+
var rawValue: String {
58+
"(\(x),\(y))"
59+
}
60+
61+
typealias RawValue = String
62+
}
63+
64+
extension Coord: CustomStringConvertible {
65+
var description: String {
66+
"\(x),\(y)"
67+
}
68+
}
69+
4470
extension Coord: AdditiveArithmetic {
4571
static let zero = Coord(x: 0, y: 0)
4672

Sources/Helpers/Grid.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,14 @@ extension Grid {
3636
func includes(coord: Coord) -> Bool {
3737
coord.x >= 0 && coord.x <= self.width - 1 && coord.y >= 0 && coord.y <= self.height - 1
3838
}
39+
40+
func firstCoord(of char: Character) -> Coord? {
41+
let index = self.raw.flatMap { $0 }.firstIndex(of: char)
42+
if let index = index {
43+
let x = index % self.width
44+
let y = index / self.width
45+
return Coord(x: x, y: y)
46+
}
47+
return nil
48+
}
3949
}

Tests/Day06.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Testing
2+
3+
@testable import aoc
4+
5+
@Suite("Day06")
6+
struct Day06Tests {
7+
let testData = """
8+
....#.....
9+
.........#
10+
..........
11+
..#.......
12+
.......#..
13+
..........
14+
.#..^.....
15+
........#.
16+
#.........
17+
......#...
18+
"""
19+
20+
@Test("part1")
21+
func testPart1() async throws {
22+
let challenge = Day06(data: testData)
23+
#expect(challenge.part1() == 41)
24+
}
25+
26+
@Test("part2")
27+
func testPart2() async throws {
28+
let challenge = Day06(data: testData)
29+
#expect(challenge.part2() == 6)
30+
}
31+
}

0 commit comments

Comments
 (0)