Old change
This commit is contained in:
parent
2abb86f290
commit
1db15c4581
4 changed files with 116 additions and 204 deletions
|
@ -1,64 +1,5 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Matrix<Element> {
|
|
||||||
var width: Int
|
|
||||||
var height: Int
|
|
||||||
var data: [Element]
|
|
||||||
|
|
||||||
init(width: Int, height: Int, data: [Element]) {
|
|
||||||
precondition(data.count == width * height)
|
|
||||||
self.width = width
|
|
||||||
self.height = height
|
|
||||||
self.data = data
|
|
||||||
}
|
|
||||||
|
|
||||||
subscript(x: Int, y: Int) -> Element {
|
|
||||||
get {
|
|
||||||
precondition(0 <= x && x < width && 0 <= y && y < height)
|
|
||||||
return data[x + width * y]
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
precondition(0 <= x && x < width && 0 <= y && y < height)
|
|
||||||
data[x + width * y] = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Matrix {
|
|
||||||
func map<T>(_ transform: (Element) throws -> T) rethrows -> Matrix<T> {
|
|
||||||
Matrix<T>(width: width, height: height, data: try data.map(transform))
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapIndexed<T>(_ transform: (Int, Int, Element) throws -> T) rethrows -> Matrix<T> {
|
|
||||||
var newData: [T] = []
|
|
||||||
newData.reserveCapacity(data.count)
|
|
||||||
var index = 0
|
|
||||||
for y in 0..<height {
|
|
||||||
for x in 0..<width {
|
|
||||||
newData.append(try transform(x, y, data[index]))
|
|
||||||
index += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Matrix<T>(width: width, height: height, data: newData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func find(where: (Element) throws -> Bool) rethrows -> [(Int, Int)] {
|
|
||||||
var result: [(Int, Int)] = []
|
|
||||||
var index = 0
|
|
||||||
for y in 0..<height {
|
|
||||||
for x in 0..<width {
|
|
||||||
if (try `where`(data[index])) {
|
|
||||||
result.append((x, y))
|
|
||||||
}
|
|
||||||
index += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MatrixError: Error {
|
enum MatrixError: Error {
|
||||||
case invalidShape
|
case invalidShape
|
||||||
}
|
}
|
||||||
|
|
BIN
2022/day15
Executable file
BIN
2022/day15
Executable file
Binary file not shown.
205
2022/day16.swift
205
2022/day16.swift
|
@ -5,183 +5,96 @@ struct Room {
|
||||||
var name: String
|
var name: String
|
||||||
var flowRate: Int
|
var flowRate: Int
|
||||||
var connections: [String]
|
var connections: [String]
|
||||||
|
var index: Int = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let regex = #/Valve (?<room>[A-Z]{2}) has flow rate=(?<flow>\d+); tunnels? leads? to valves? (?<links>[A-Z]{2}(, [A-Z]{2})*)/#
|
let regex = #/Valve (?<room>[A-Z]{2}) has flow rate=(?<flow>\d+); tunnels? leads? to valves? (?<links>[A-Z]{2}(, [A-Z]{2})*)/#
|
||||||
|
|
||||||
var rooms: [String: Room] = [:]
|
var rooms: [String:Room] = [:]
|
||||||
|
|
||||||
for try await line in URL(fileURLWithPath: "day16.input").lines {
|
for try await line in URL(fileURLWithPath: "day16.input").lines {
|
||||||
guard let match = try regex.wholeMatch(in: line) else {
|
guard let match = try regex.wholeMatch(in: line) else {
|
||||||
fatalError("Invalid input: \(line)")
|
fatalError("Invalid input: \(line)")
|
||||||
}
|
}
|
||||||
|
|
||||||
rooms[String(match.room)] = Room(name: String(match.room), flowRate: Int(match.flow)!, connections: match.links.split(separator: ", ").map(String.init))
|
rooms[String(match.room)] = (Room(name: String(match.room), flowRate: Int(match.flow)!, connections: match.links.split(separator: ", ").map(String.init)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Path {
|
let roomsWithValves: [String] = ["AA"] + rooms.values.lazy.filter { $0.flowRate > 0 }.map(\.name).sorted()
|
||||||
var rooms: [String] = []
|
for (index, name) in roomsWithValves.enumerated() {
|
||||||
var opened: Set<String> = []
|
rooms[name]?.index = index
|
||||||
var pressure: Int = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalTime = 30
|
struct Matrix<Element> {
|
||||||
|
var size: Int
|
||||||
|
var data: [Element]
|
||||||
|
|
||||||
func findPath(from room: Room, previous: String? = nil, time: Int = totalTime, path: inout Path) {
|
init(size: Int, data: [Element]) {
|
||||||
guard time > 0 else { return }
|
precondition(data.count == size * size)
|
||||||
|
self.size = size
|
||||||
let best = findBest(path: path, room: room, previous: previous, turnedOn: false, time: time - 1)
|
self.data = data
|
||||||
|
|
||||||
if time >= 2, room.flowRate > 0 && path.opened.insert(room.name).inserted {
|
|
||||||
path.pressure += (time - 1) * room.flowRate
|
|
||||||
path = findBest(path: path, room: room, previous: previous, turnedOn: true, time: time - 2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if best.pressure > path.pressure {
|
init(size: Int, repeating: Element) {
|
||||||
path = best
|
self.init(size: size, data: Array(repeating: repeating, count: size * size))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscript(x: Int, y: Int) -> Element {
|
||||||
|
get {
|
||||||
|
precondition(0 <= x && x < size && 0 <= y && y < size)
|
||||||
|
return data[x + size * y]
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
precondition(0 <= x && x < size && 0 <= y && y < size)
|
||||||
|
data[x + size * y] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func setDiagonal(to value: Element) {
|
||||||
|
for i in 0..<size {
|
||||||
|
self[i, i] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findBest(path: Path, room: Room, previous: String? = nil, turnedOn: Bool, time: Int) -> Path {
|
|
||||||
var path = path
|
|
||||||
path.rooms.append("\(room.name)[\(room.flowRate)]\(turnedOn ? "*" : "")")
|
|
||||||
|
|
||||||
var best = path
|
var distanceMatrix = Matrix(size: roomsWithValves.count, repeating: Int.max)
|
||||||
|
distanceMatrix.setDiagonal(to: 0)
|
||||||
|
|
||||||
for next in room.connections {
|
func findDistances(start: String, current: String, previous: String? = nil, distance: Int = 0) {
|
||||||
if !turnedOn && previous == next {
|
|
||||||
continue
|
let currentRoom = rooms[current]!
|
||||||
|
let startRoom = rooms[start]!
|
||||||
|
|
||||||
|
let nextStart = currentRoom.flowRate > 0 ? current : start
|
||||||
|
if currentRoom.flowRate > 0 {
|
||||||
|
distanceMatrix[startRoom.index, currentRoom.index] = min(distanceMatrix[startRoom.index, currentRoom.index], distance)
|
||||||
}
|
}
|
||||||
|
|
||||||
let nextRoom = rooms[next]!
|
for next in currentRoom.connections where next != previous {
|
||||||
|
findDistances(start: nextStart, current: next, previous: current, distance: distance + 1)
|
||||||
var nextPath = path
|
|
||||||
findPath(from: nextRoom, previous: room.name, time: time, path: &nextPath)
|
|
||||||
if nextPath.pressure > best.pressure {
|
|
||||||
best = nextPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return best
|
|
||||||
}
|
|
||||||
|
|
||||||
//var path = Path()
|
|
||||||
//findPath(from: rooms["AA"]!, path: &path)
|
|
||||||
//print(path.pressure)
|
|
||||||
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
var me: String
|
|
||||||
var mePrevious: String? = nil
|
|
||||||
var meOpened: Bool = false
|
|
||||||
|
|
||||||
var elephant: String
|
|
||||||
var elephantPrevious: String? = nil
|
|
||||||
var elephantOpened: Bool = false
|
|
||||||
|
|
||||||
var timeLeft: Int
|
|
||||||
var pressure: Int = 0
|
|
||||||
var opened: Set<String> = []
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Move: Hashable {
|
|
||||||
case openValve
|
|
||||||
case move(String)
|
|
||||||
}
|
|
||||||
|
|
||||||
extension State {
|
|
||||||
var meRoom: Room { rooms[me]! }
|
|
||||||
var elephantRoom: Room { rooms[elephant]! }
|
|
||||||
|
|
||||||
func nextMoves() -> [State] {
|
|
||||||
let myMoves = moves(from: me, previous: mePrevious, opened: meOpened)
|
|
||||||
var elephantMoves = moves(from: elephant, previous: elephantPrevious, opened: elephantOpened)
|
|
||||||
|
|
||||||
if me == elephant && myMoves.contains(.openValve) {
|
|
||||||
elephantMoves.remove(.openValve)
|
|
||||||
}
|
|
||||||
|
|
||||||
var result: [State] = []
|
|
||||||
result.reserveCapacity(myMoves.count * elephantMoves.count)
|
|
||||||
for a in myMoves {
|
|
||||||
for b in elephantMoves {
|
|
||||||
var next = self
|
|
||||||
next.move(me: a, elephant: b)
|
|
||||||
result.append(next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
mutating func move(me: Move, elephant: Move) {
|
|
||||||
timeLeft -= 1
|
|
||||||
|
|
||||||
switch me {
|
|
||||||
case .openValve:
|
|
||||||
opened.insert(self.me)
|
|
||||||
meOpened = true
|
|
||||||
pressure += timeLeft * meRoom.flowRate
|
|
||||||
|
|
||||||
case .move(let to):
|
|
||||||
mePrevious = self.me
|
|
||||||
meOpened = false
|
|
||||||
self.me = to
|
|
||||||
}
|
|
||||||
|
|
||||||
switch elephant {
|
|
||||||
case .openValve:
|
|
||||||
opened.insert(self.elephant)
|
|
||||||
elephantOpened = true
|
|
||||||
pressure += timeLeft * elephantRoom.flowRate
|
|
||||||
|
|
||||||
case .move(let to):
|
|
||||||
elephantPrevious = self.elephant
|
|
||||||
elephantOpened = false
|
|
||||||
self.elephant = to
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func moves(from: String, previous: String?, opened: Bool) -> Set<Move> {
|
|
||||||
let room = rooms[from]!
|
|
||||||
var result: Set<Move> = []
|
|
||||||
result.reserveCapacity(room.connections.count + 1)
|
|
||||||
|
|
||||||
if !self.opened.contains(from), room.flowRate > 0 {
|
|
||||||
result.insert(.openValve)
|
|
||||||
}
|
|
||||||
|
|
||||||
for next in room.connections {
|
|
||||||
if !opened && next == previous {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result.insert(.move(next))
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let initial = State(me: "AA", elephant: "AA", timeLeft: 26)
|
findDistances(start: "AA", current: "AA")
|
||||||
|
|
||||||
let allValves = Set(rooms.values.lazy.filter { $0.flowRate > 0 }.map(\.name))
|
print(" ", terminator: "")
|
||||||
|
for name in roomsWithValves {
|
||||||
var best = initial
|
print("| \(name) ", terminator: "")
|
||||||
|
}
|
||||||
var queue = [initial]
|
print("|")
|
||||||
while !queue.isEmpty {
|
for y in 0..<distanceMatrix.size {
|
||||||
let next = queue.removeFirst()
|
print(roomsWithValves[y], "", terminator: "")
|
||||||
if next.timeLeft == 0 || next.opened == allValves {
|
for x in 0..<distanceMatrix.size {
|
||||||
if next.pressure > best.pressure {
|
let value = distanceMatrix[x, y]
|
||||||
best = next
|
if value == .max {
|
||||||
|
print("| ", terminator: "")
|
||||||
|
} else {
|
||||||
|
print(String(format: "| %2d ", value), terminator: "")
|
||||||
}
|
}
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
print("|")
|
||||||
queue.append(contentsOf: next.nextMoves())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Part 2:", best.pressure)
|
|
||||||
|
|
58
2022/matrix.swift
Normal file
58
2022/matrix.swift
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
struct Matrix<Element> {
|
||||||
|
var width: Int
|
||||||
|
var height: Int
|
||||||
|
var data: [Element]
|
||||||
|
|
||||||
|
init(width: Int, height: Int, data: [Element]) {
|
||||||
|
precondition(data.count == width * height)
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
subscript(x: Int, y: Int) -> Element {
|
||||||
|
get {
|
||||||
|
precondition(0 <= x && x < width && 0 <= y && y < height)
|
||||||
|
return data[x + width * y]
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
precondition(0 <= x && x < width && 0 <= y && y < height)
|
||||||
|
data[x + width * y] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Matrix {
|
||||||
|
func map<T>(_ transform: (Element) throws -> T) rethrows -> Matrix<T> {
|
||||||
|
Matrix<T>(width: width, height: height, data: try data.map(transform))
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapIndexed<T>(_ transform: (Int, Int, Element) throws -> T) rethrows -> Matrix<T> {
|
||||||
|
var newData: [T] = []
|
||||||
|
newData.reserveCapacity(data.count)
|
||||||
|
var index = 0
|
||||||
|
for y in 0..<height {
|
||||||
|
for x in 0..<width {
|
||||||
|
newData.append(try transform(x, y, data[index]))
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Matrix<T>(width: width, height: height, data: newData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func find(where: (Element) throws -> Bool) rethrows -> [(Int, Int)] {
|
||||||
|
var result: [(Int, Int)] = []
|
||||||
|
var index = 0
|
||||||
|
for y in 0..<height {
|
||||||
|
for x in 0..<width {
|
||||||
|
if (try `where`(data[index])) {
|
||||||
|
result.append((x, y))
|
||||||
|
}
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue