Last active
December 14, 2022 19:42
-
-
Save mkuliszkiewicz/a293e73cbb47de8012ce8728dd45e828 to your computer and use it in GitHub Desktop.
AoC Day 14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Point: Hashable, CustomStringConvertible { | |
let x: Int; let y: Int | |
init(x: Int, y: Int) { | |
self.x = x | |
self.y = y | |
} | |
init(_ str: String) { | |
// x represents distance to the right and y represents distance down. | |
let el = str.components(separatedBy: ",").map { Int($0)! } | |
self.x = el[0] | |
self.y = el[1] | |
} | |
var description: String { "Point(x: \(x), y: \(y))" } | |
func makeAllPoints(to otherPoint: Point) -> [Point] { | |
guard self != otherPoint else { return [] } | |
if x != otherPoint.x { | |
var minX = min(x, otherPoint.x) | |
var maxX = max(x, otherPoint.x) | |
return (minX...maxX).map { Point(x: $0, y: y) } | |
} else { | |
var minY = min(y, otherPoint.y) | |
var maxY = max(y, otherPoint.y) | |
return (minY...maxY).map { Point(x: x, y: $0) } | |
} | |
} | |
func adjustX(by val: Int) -> Point { | |
Point(x: x + val, y: y) | |
} | |
func adjustY(by val: Int) -> Point { | |
Point(x: x, y: y + val) | |
} | |
func flipY() -> Point { | |
Point(x: x, y: y * -1) | |
} | |
} | |
final class Sand { | |
var position = Point(x: 0, y: 0) | |
} | |
func task1(input: String) -> Int { | |
let rawRows = input | |
.components(separatedBy: .newlines) | |
.filter { !$0.isEmpty } | |
.map { $0.components(separatedBy: " -> ").map(Point.init) } | |
var rawRockPoints: Set<Point> = [] | |
for row in rawRows where !row.isEmpty { | |
for i in (1..<row.count) { | |
let current = row[i] | |
let previous = row[i - 1] | |
previous | |
.makeAllPoints(to: current) | |
.forEach { | |
rawRockPoints.insert($0) | |
} | |
} | |
} | |
var rocksPoints = rawRockPoints.map { $0.adjustX(by: -500).flipY() } | |
var lowestRockPoint = rocksPoints.min(by: { $0.y < $1.y })! | |
var sandBuffer: Set<Point> = [] | |
var sandCounter = 0 | |
var hasFallenDown = false | |
while !hasFallenDown { | |
sandCounter += 1 | |
var currentSand = Sand() | |
func nextMove() -> Point? { | |
var currentPosition = currentSand.position | |
let oneDown = currentPosition.adjustY(by: -1) | |
let oneDownLeft = currentPosition.adjustY(by: -1).adjustX(by: -1) | |
let oneDownRight = currentPosition.adjustY(by: -1).adjustX(by: 1) | |
if !rocksPoints.contains(oneDown) && !sandBuffer.contains(oneDown) { | |
return oneDown | |
} | |
if !rocksPoints.contains(oneDownLeft) && !sandBuffer.contains(oneDownLeft) { | |
return oneDownLeft | |
} | |
if !rocksPoints.contains(oneDownRight) && !sandBuffer.contains(oneDownRight) { | |
return oneDownRight | |
} | |
return nil | |
} | |
while let next = nextMove(), !hasFallenDown { | |
currentSand.position = next | |
hasFallenDown = currentSand.position.y < lowestRockPoint.y | |
if hasFallenDown { | |
print("Has fallen down") | |
} | |
} | |
print("Settled at \(currentSand.position)") | |
sandBuffer.insert(currentSand.position) | |
} | |
return sandCounter - 1 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func task2(input: String) -> Int { | |
let rawRows = input | |
.components(separatedBy: .newlines) | |
.filter { !$0.isEmpty } | |
.map { | |
$0.components(separatedBy: " -> ") | |
.map(Point.init) | |
.map { | |
$0.adjustX(by: -500) | |
.flipY() | |
} | |
} | |
var rawRockPoints: Set<Point> = [] | |
for row in rawRows where !row.isEmpty { | |
for i in (1..<row.count) { | |
let current = row[i] | |
let previous = row[i - 1] | |
previous | |
.makeAllPoints(to: current) | |
.forEach { | |
rawRockPoints.insert($0) | |
} | |
} | |
} | |
var rocksPoints = rawRockPoints | |
let lowestRockPoint = rocksPoints.min(by: { $0.y < $1.y })! | |
let floorLevel = lowestRockPoint.y - 2 | |
print("Floor level \(floorLevel)") | |
var sandCounter = 0 | |
while true { | |
sandCounter += 1 | |
var currentSand = Point(x: 0, y: 0) | |
func nextMove() -> Point? { | |
let oneDown = currentSand.adjustY(by: -1) | |
let oneDownLeft = currentSand.adjustY(by: -1).adjustX(by: -1) | |
let oneDownRight = currentSand.adjustY(by: -1).adjustX(by: 1) | |
if oneDown.y == floorLevel { | |
return nil | |
} | |
if !rocksPoints.contains(oneDown) { | |
return oneDown | |
} | |
if !rocksPoints.contains(oneDownLeft) { | |
return oneDownLeft | |
} | |
if !rocksPoints.contains(oneDownRight) { | |
return oneDownRight | |
} | |
return nil | |
} | |
while let next = nextMove() { | |
currentSand = next | |
} | |
rocksPoints.insert(currentSand) | |
if currentSand == .init(x: 0, y: 0) { | |
return sandCounter | |
} | |
} | |
fatalError() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment