Finish Day 7

master
Peter 7 years ago
parent 62f65846c7
commit 200555b6cb

@ -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: [(() -> ())] = []

Loading…
Cancel
Save