Finish Day 7
This commit is contained in:
+195
-15
@@ -17,12 +17,26 @@ struct Instruction: Equatable, Comparable {
|
||||
}
|
||||
}
|
||||
|
||||
struct Worker: Equatable, Comparable {
|
||||
var job = Character(" ")
|
||||
var duration = 0
|
||||
|
||||
static func == (lhs: Worker, rhs: Worker) -> Bool {
|
||||
return (lhs.job == rhs.job) && (lhs.duration == rhs.duration)
|
||||
}
|
||||
|
||||
static func < (lhs: Worker, rhs: Worker) -> Bool {
|
||||
return lhs.duration < rhs.duration
|
||||
}
|
||||
}
|
||||
|
||||
class SumParts {
|
||||
var instrList: [Instruction] = []
|
||||
var inventoryComplete: [Character] = []
|
||||
var workers: [Worker] = []
|
||||
var masterClock = 0
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt'
|
||||
init(withFile filename: String) {
|
||||
init(withFile filename: String, numWorkers: Int) {
|
||||
let instrString = Tools.readFile(fromPath: filename)
|
||||
var instrArray = instrString.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
@@ -30,12 +44,14 @@ class SumParts {
|
||||
guard let lastStr = instrArray.last, lastStr.count == 0 else { return }
|
||||
instrArray.removeLast() // empty string
|
||||
parseData(withInstructions: instrArray)
|
||||
workers = Array(repeating: Worker(), count: numWorkers)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString instrString: String) {
|
||||
init(withString instrString: String, numWorkers: Int) {
|
||||
let instrArray = instrString.components(separatedBy: "\n")
|
||||
parseData(withInstructions: instrArray)
|
||||
workers = Array(repeating: Worker(), count: numWorkers)
|
||||
}
|
||||
|
||||
func parseData(withInstructions instr: [String]) {
|
||||
@@ -45,6 +61,7 @@ class SumParts {
|
||||
}
|
||||
|
||||
func getNextAvailable() -> Character? {
|
||||
var retVal: Character?
|
||||
var availDict: [Character : Bool] = [:]
|
||||
for index in 0..<instrList.count {
|
||||
if !instrList.contains(where: { $0.before == instrList[index].complete} ) {
|
||||
@@ -53,10 +70,22 @@ class SumParts {
|
||||
}
|
||||
var available = Array(availDict.keys)
|
||||
available.sort()
|
||||
return available.first
|
||||
if workers.count == 0 {
|
||||
retVal = available.first
|
||||
} else {
|
||||
// Exclude 'available' if already scheduled to a worker
|
||||
for job in available {
|
||||
// if workers.contains(where: { $0.job == job && $0.duration == 0} ) {
|
||||
if !workers.contains(where: { $0.job == job} ) || workers.contains(where: { $0.job == job && $0.duration == 0} ) {
|
||||
retVal = job
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func completeInstructions() -> String {
|
||||
func completeAllInstructions() -> String {
|
||||
var retVal = ""
|
||||
var last: Character = "*"
|
||||
while let instruction = getNextAvailable() {
|
||||
@@ -69,6 +98,77 @@ class SumParts {
|
||||
retVal.append(last)
|
||||
return retVal
|
||||
}
|
||||
|
||||
func complete(instruction: Character) {
|
||||
if instrList.count == 1 && instrList[0].complete != " " {
|
||||
instrList.append(Instruction(complete: instrList[0].before, before: Character(" ")))
|
||||
}
|
||||
instrList.removeAll(where: { $0.complete == instruction })
|
||||
}
|
||||
|
||||
//-------------->> Code for Part 2 <<--------------
|
||||
|
||||
// We'll cheat here and assume the duration is 1 second + offset for One worker and 60 seconds + offset for more than one
|
||||
func duration(forInstruction instr: Character) -> Int {
|
||||
guard let val = instr.ascii else { return -1 }
|
||||
let offset = Int(val) - 64
|
||||
return (workers.count > 2) ? 60 + offset : offset
|
||||
}
|
||||
|
||||
// Go through the list of workers and find the min() time-to-finish
|
||||
func getTimeUntilWorkerFree() -> Int {
|
||||
guard workers.count > 0 else { return 0 }
|
||||
let sortedByDuration = workers.sorted(by: { $0.duration < $1.duration })
|
||||
for worker in sortedByDuration {
|
||||
if worker.duration != 0 {
|
||||
return worker.duration
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func advanceTime(by elapsedtime: Int) {
|
||||
for index in 0..<workers.count {
|
||||
if workers[index].duration > 0 {
|
||||
workers[index].duration -= elapsedtime
|
||||
}
|
||||
}
|
||||
masterClock += elapsedtime
|
||||
}
|
||||
|
||||
// subtract XX seconds from the workers time and add that to the master-clock
|
||||
// Since we advance until worker(s) done, we should complete the tasks finsished by the worker(s)
|
||||
// return true if more work to do
|
||||
func advanceClockAndCompleteInstructions() -> Bool {
|
||||
guard workers.count > 0 else { return false }
|
||||
let advTime = getTimeUntilWorkerFree()
|
||||
if advTime == 0 {
|
||||
let test = workers.contains(where: { $0.duration != 0} )
|
||||
if !test {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// subtract this time from all workers
|
||||
// add this time to the Master-Clock
|
||||
advanceTime(by: advTime)
|
||||
// Complete the "finished" worker(s) instruction
|
||||
for index in 0..<workers.count {
|
||||
if workers[index].duration == 0 {
|
||||
complete(instruction: workers[index].job)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Look for available workers and assign them instructions
|
||||
func scheduleWorkers() {
|
||||
for index in 0..<workers.count {
|
||||
if workers[index].duration == 0 {
|
||||
guard let job = getNextAvailable() else { return }
|
||||
workers[index] = Worker(job: job, duration: duration(forInstruction: job))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Day07: AOCDay {
|
||||
@@ -86,16 +186,16 @@ class Day07: AOCDay {
|
||||
"""
|
||||
|
||||
func testSumPartsInit() {
|
||||
var instr = SumParts(withString: testData)
|
||||
var instr = SumParts(withString: testData, numWorkers: 0)
|
||||
XCTAssertEqual(test: "testSumPartsInit string 0", withExpression: (instr.instrList[0].before == "A"))
|
||||
XCTAssertEqual(test: "testSumPartsInit string 4", withExpression: (instr.instrList[4].complete == "B"))
|
||||
instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt")
|
||||
instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt", numWorkers: 0)
|
||||
XCTAssertEqual(test: "testSumPartsInit file 0", withExpression: (instr.instrList[0].before == "X"))
|
||||
XCTAssertEqual(test: "testSumPartsInit file 4", withExpression: (instr.instrList[4].complete == "O"))
|
||||
}
|
||||
|
||||
func testGetNextAvailable() {
|
||||
let instr = SumParts(withString: testData)
|
||||
let instr = SumParts(withString: testData, numWorkers: 0)
|
||||
if let avail = instr.getNextAvailable() {
|
||||
XCTAssertEqual(test: "testGetNextAvailable", withExpression: (avail == "C"))
|
||||
} else {
|
||||
@@ -104,22 +204,102 @@ class Day07: AOCDay {
|
||||
}
|
||||
|
||||
func testCompleteInstructions() {
|
||||
let instr = SumParts(withString: testData)
|
||||
let answer = instr.completeInstructions()
|
||||
let instr = SumParts(withString: testData, numWorkers: 0)
|
||||
let answer = instr.completeAllInstructions()
|
||||
XCTAssertEqual(test: "testCompleteInstructions", withExpression: (answer == "CABDFE"))
|
||||
}
|
||||
|
||||
func testDuration() {
|
||||
var instr = SumParts(withString: testData, numWorkers: 2)
|
||||
var dur = instr.duration(forInstruction: "A")
|
||||
XCTAssertEqual(test: "testDuration 1 worker A", withExpression: (dur == 1))
|
||||
dur = instr.duration(forInstruction: "K")
|
||||
XCTAssertEqual(test: "testDuration 1 worker K", withExpression: (dur == 11))
|
||||
dur = instr.duration(forInstruction: "Z")
|
||||
XCTAssertEqual(test: "testDuration 1 worker Z", withExpression: (dur == 26))
|
||||
instr = SumParts(withString: testData, numWorkers: 5)
|
||||
dur = instr.duration(forInstruction: "A")
|
||||
XCTAssertEqual(test: "testDuration 5 worker A", withExpression: (dur == 60 + 1))
|
||||
dur = instr.duration(forInstruction: "K")
|
||||
XCTAssertEqual(test: "testDuration 5 worker K", withExpression: (dur == 60 + 11))
|
||||
dur = instr.duration(forInstruction: "Z")
|
||||
XCTAssertEqual(test: "testDuration 5 worker Z", withExpression: (dur == 60 + 26))
|
||||
}
|
||||
|
||||
// Go through the list of workers and find the min() time-to-finish
|
||||
func testGetTimeUntilWorkerFree() {
|
||||
var instr = SumParts(withString: testData, numWorkers: 2)
|
||||
var time = instr.getTimeUntilWorkerFree()
|
||||
XCTAssertEqual(test: "testGetTimeUntilWorkerFree 1 worker", withExpression: (time == 0))
|
||||
instr = SumParts(withString: testData, numWorkers: 5)
|
||||
time = instr.getTimeUntilWorkerFree()
|
||||
XCTAssertEqual(test: "testGetTimeUntilWorkerFree 5 workers", withExpression: (time == 0))
|
||||
}
|
||||
|
||||
func testAdvanceTime() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
let oldClock = instr.masterClock
|
||||
let oldWorkers = instr.workers
|
||||
instr.advanceTime(by: 0)
|
||||
XCTAssertEqual(test: "testAdvanceTime by 0 seconds clock", withExpression: (oldClock == instr.masterClock))
|
||||
XCTAssertEqual(test: "testAdvanceTime by 0 seconds workers", withExpression: (oldWorkers == instr.workers))
|
||||
instr.advanceTime(by: 10)
|
||||
XCTAssertEqual(test: "testAdvanceTime by 10 seconds clock", withExpression: (instr.masterClock == 10))
|
||||
}
|
||||
|
||||
// subtract XX seconds from the workers time and add that to the master-clock
|
||||
// Since we advance until worker(s) done, we should complete the tasks finsished by the worker(s)
|
||||
func testAdvanceClockAndCompleteInstructions() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
let oldWorkers = instr.workers
|
||||
var done = instr.advanceClockAndCompleteInstructions()
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions done=false before first schedule", withExpression: (!done))
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions workers unchanged", withExpression: (oldWorkers == instr.workers))
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions masterClock unchanged", withExpression: (instr.masterClock == 0))
|
||||
instr.scheduleWorkers()
|
||||
done = instr.advanceClockAndCompleteInstructions()
|
||||
XCTAssertEqual(test: "testAdvanceClockAndCompleteInstructions done=true after first schedule", withExpression: (done))
|
||||
}
|
||||
|
||||
// Look for available workers and assign them instructions
|
||||
func testScheduleWorkers() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
let oldWorkers = instr.workers
|
||||
instr.scheduleWorkers()
|
||||
XCTAssertEqual(test: "testScheduleWorkers workers changed", withExpression: (oldWorkers != instr.workers))
|
||||
}
|
||||
|
||||
func testAnswerPart2() {
|
||||
let instr = SumParts(withString: testData, numWorkers: 2)
|
||||
instr.scheduleWorkers()
|
||||
while instr.advanceClockAndCompleteInstructions() {
|
||||
instr.scheduleWorkers()
|
||||
}
|
||||
XCTAssertEqual(test: "testAnswerPart2", withExpression: (instr.masterClock == 15))
|
||||
}
|
||||
|
||||
func day07Tests() {
|
||||
testSumPartsInit()
|
||||
testGetNextAvailable()
|
||||
testCompleteInstructions()
|
||||
testDuration()
|
||||
testGetTimeUntilWorkerFree()
|
||||
testAdvanceTime()
|
||||
testAdvanceClockAndCompleteInstructions()
|
||||
testScheduleWorkers()
|
||||
testAnswerPart2()
|
||||
}
|
||||
|
||||
func day07Final() {
|
||||
let retVal = "None"
|
||||
let instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt")
|
||||
let answer = instr.completeInstructions()
|
||||
print("Answer to part 1 is: \(answer)")
|
||||
print("Answer to part 2 is: \(retVal)")
|
||||
var instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt", numWorkers: 0)
|
||||
let answerPart1 = instr.completeAllInstructions()
|
||||
instr = SumParts(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day07.txt", numWorkers: 5)
|
||||
instr.scheduleWorkers()
|
||||
while instr.advanceClockAndCompleteInstructions() {
|
||||
instr.scheduleWorkers()
|
||||
}
|
||||
let answerPart2 = instr.masterClock
|
||||
print("Answer to part 1 is: \(answerPart1)")
|
||||
print("Answer to part 2 is: \(answerPart2)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import Foundation
|
||||
|
||||
let showTests = true
|
||||
let onlyOneDay = 7
|
||||
let onlyOneDay = 0
|
||||
var allTests: [(() -> ())] = []
|
||||
var allFinal: [(() -> ())] = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user