Skip to content

Instantly share code, notes, and snippets.

@mkuliszkiewicz
Last active December 13, 2022 20:23
Show Gist options
  • Save mkuliszkiewicz/399f56398e7c9da4ac3a724139fd6266 to your computer and use it in GitHub Desktop.
Save mkuliszkiewicz/399f56398e7c9da4ac3a724139fd6266 to your computer and use it in GitHub Desktop.
AoC Day 12 Task 2
class Path {
let point: Point
let previousPath: Path?
let length: Int
init(to point: Point, previousPath path: Path? = nil) {
self.point = point
self.length = 1 + (path?.length ?? 0)
self.previousPath = path
}
}
extension Path {
var array: [Point] {
var result: [Point] = [point]
var currentPath = self
while let path = currentPath.previousPath {
result.append(path.point)
currentPath = path
}
return result
}
}
let alphabet = Array("abcdefghijklmnopqrstuvwxyz")
func task1(input: String) -> Int {
let grid: [[Character]] = input
.components(separatedBy: CharacterSet.newlines)
.filter { !$0.isEmpty }
.map { Array($0) }
let maxX = grid[0].count
let maxY = grid.count
printGrid(grid: grid)
let startY = grid.firstIndex(where: { $0.contains("S") })!
let startX = grid[startY].firstIndex(where: { $0 == "S" })!
print(("start", startX, startY))
let endY = grid.firstIndex(where: { $0.contains("E") })!
let endX = grid[endY].firstIndex(where: { $0 == "E" })!
print(("end", endX, endY))
func val(_ point: Point) -> Character {
return grid[point.y][point.x]
}
func possiblePoints(for point: Point) -> [Point] {
var result: [Point] = []
var directions: [(Int, Int)] = [(-1, 0), (0, 1), (1, 0), (0, -1)]
for (x, y) in directions {
guard
point.x + x < maxX,
point.x + x >= 0,
point.y + y < maxY,
point.y + y >= 0
else { continue }
result.append(Point(x: point.x + x, y: point.y + y))
}
let pointValue = val(point)
if pointValue == "S" { return result }
let currentValueIdx = alphabet.firstIndex(of: pointValue)!
let allowedIndices = Array(0...currentValueIdx + 1)
result = result.filter {
var targetPointVal = val($0)
if targetPointVal == "S" { return false }
if targetPointVal == "E" {
targetPointVal = "z"
}
let targetPointIdx = alphabet.firstIndex(of: targetPointVal)!
return allowedIndices.contains(targetPointIdx)
}
return result
}
func findPath(source: Point, destination: Point) -> Path? {
var paths: [Path] = [] {
didSet {
paths.sort {
return $0.length < $1.length
}
}
}
var visited: Set<Point> = []
paths.append(Path(to: source))
while !paths.isEmpty {
let currentPath = paths.removeFirst()
guard !visited.contains(currentPath.point) else {
continue
}
if currentPath.point == destination {
return currentPath
}
visited.insert(currentPath.point)
for nextPoint in possiblePoints(for: currentPath.point).filter({ !visited.contains($0) }) {
paths.append(Path.init(to: nextPoint, previousPath: currentPath))
}
}
return nil
}
let startPoint = Point(x: startX, y: startY)
let endPoint = Point(x: endX, y: endY)
let shortestPath = findPath(source: startPoint, destination: endPoint)!
return shortestPath.length - 1
}
func task12_2(input: String) -> Int {
var grid: [[Character]] = input
.components(separatedBy: CharacterSet.newlines)
.filter { !$0.isEmpty }
.map { Array($0) }
let maxX = grid[0].count
let maxY = grid.count
let endY = grid.firstIndex(where: { $0.contains("E") })!
let endX = grid[endY].firstIndex(where: { $0 == "E" })!
let endPoint = Point(x: endX, y: endY)
let numberGrid: [[UInt8]] = grid.map { row in
row.map { char in
if char == "S" {
return Character("a").asciiValue!
}
if char == "E" {
return Character("z").asciiValue!
}
return char.asciiValue!
}
}
func val(_ point: Point) -> UInt8 {
numberGrid[point.y][point.x]
}
func possiblePoints(for point: Point) -> [Point] {
var result: [Point] = []
var directions: [(Int, Int)] = [(-1, 0), (0, 1), (1, 0), (0, -1)]
for (x, y) in directions {
guard
point.x + x < maxX,
point.x + x >= 0,
point.y + y < maxY,
point.y + y >= 0
else { continue }
result.append(Point(x: point.x + x, y: point.y + y))
}
let allowedValues = [val(point) - 1, val(point), val(point) + 1]
result = result.filter { proposedPoint in
print(
Int(val(proposedPoint)) - Int(val(point))
)
return Int(val(proposedPoint)) - Int(val(point)) >= -1
}
return result
}
var seenPoints = Set<Point>()
var paths: [Path] = [Path(to: endPoint)]
while !paths.isEmpty {
let currentPath = paths.removeFirst()
if val(currentPath.point) == Character("a").asciiValue! {
return currentPath.length - 1
}
if seenPoints.contains(currentPath.point) {
continue
}
seenPoints.insert(currentPath.point)
let nextPoints = possiblePoints(for: currentPath.point).filter({ !seenPoints.contains($0) })
for nextPoint in nextPoints {
paths.append(Path(to: nextPoint, previousPath: currentPath))
}
}
return -1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment