|
|
|
@ -27,11 +27,6 @@ struct Activity: Equatable, Comparable {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct GuardMap {
|
|
|
|
|
|
|
|
var id = 0
|
|
|
|
|
|
|
|
var sleepMap: [Bool] = Array(repeating: false, count: 60)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make some assumptions based on the fact that there is only on guard on duty per night
|
|
|
|
// Make some assumptions based on the fact that there is only on guard on duty per night
|
|
|
|
|
|
|
|
|
|
|
|
// read in data
|
|
|
|
// read in data
|
|
|
|
@ -42,7 +37,7 @@ struct GuardMap {
|
|
|
|
// - create histogram and determine which minute he has slept through the most
|
|
|
|
// - create histogram and determine which minute he has slept through the most
|
|
|
|
class Repose {
|
|
|
|
class Repose {
|
|
|
|
var scheduleArray: [String] = []
|
|
|
|
var scheduleArray: [String] = []
|
|
|
|
var sleepMapForGuardID: [Int : [Int]] = [:] // id : Array if ints, one for each hour; increment if asleep
|
|
|
|
var sleepMapForGuardID: [Int : [Int]] = [:] // dictionary of [id : Array of ints, one for each hour; increment if asleep]
|
|
|
|
var activitiesForDay: [Int : [Activity]] = [:]
|
|
|
|
var activitiesForDay: [Int : [Activity]] = [:]
|
|
|
|
|
|
|
|
|
|
|
|
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day04.txt'
|
|
|
|
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day04.txt'
|
|
|
|
@ -53,15 +48,14 @@ class Repose {
|
|
|
|
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
|
|
|
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
|
|
|
guard let lastStr = scheduleArray.last, lastStr.count == 0 else { return }
|
|
|
|
guard let lastStr = scheduleArray.last, lastStr.count == 0 else { return }
|
|
|
|
scheduleArray.removeLast() // empty string
|
|
|
|
scheduleArray.removeLast() // empty string
|
|
|
|
// parseData(withSchedule: scheduleArray)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Supply test data in the form of a String
|
|
|
|
// Supply test data in the form of a String
|
|
|
|
init(withString schedule: String) {
|
|
|
|
init(withString schedule: String) {
|
|
|
|
scheduleArray = schedule.components(separatedBy: "\n")
|
|
|
|
scheduleArray = schedule.components(separatedBy: "\n")
|
|
|
|
// parseData(withSchedule: scheduleArray)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Needed this due to Guard starting day before midnight of the previous month (broke my simple day = month * 31 rule)
|
|
|
|
static func increment(day: Int) -> Int {
|
|
|
|
static func increment(day: Int) -> Int {
|
|
|
|
// there is a leap year every year divisible by four except for years which are both divisible by 100 and not divisible by 400.
|
|
|
|
// there is a leap year every year divisible by four except for years which are both divisible by 100 and not divisible by 400.
|
|
|
|
// Therefore, the year 2000 will be a leap year, but the years 1700, 1800, and 1900 were not.
|
|
|
|
// Therefore, the year 2000 will be a leap year, but the years 1700, 1800, and 1900 were not.
|
|
|
|
@ -74,13 +68,11 @@ class Repose {
|
|
|
|
myDay = 31
|
|
|
|
myDay = 31
|
|
|
|
myMonth -= 1
|
|
|
|
myMonth -= 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// print("input Day = \(day), myMonth=\(myMonth), myDay=\(myDay)")
|
|
|
|
|
|
|
|
if myDay == nDays[myMonth - 1] {
|
|
|
|
if myDay == nDays[myMonth - 1] {
|
|
|
|
retVal = (myMonth + 1) * 31 + 1
|
|
|
|
retVal = (myMonth + 1) * 31 + 1
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
retVal = day + 1
|
|
|
|
retVal = day + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// print("newDay = \(retVal)")
|
|
|
|
|
|
|
|
return retVal
|
|
|
|
return retVal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -91,7 +83,6 @@ class Repose {
|
|
|
|
if line.count > 0 {
|
|
|
|
if line.count > 0 {
|
|
|
|
// Split line into time and action
|
|
|
|
// Split line into time and action
|
|
|
|
var parseString = line
|
|
|
|
var parseString = line
|
|
|
|
// print("\n\(line)")
|
|
|
|
|
|
|
|
parseString.removeFirst()
|
|
|
|
parseString.removeFirst()
|
|
|
|
let splitStr = parseString.components(separatedBy: "]")
|
|
|
|
let splitStr = parseString.components(separatedBy: "]")
|
|
|
|
guard splitStr.count > 1 else { break parseScope }
|
|
|
|
guard splitStr.count > 1 else { break parseScope }
|
|
|
|
@ -127,14 +118,12 @@ class Repose {
|
|
|
|
startShiftStr.removeFirst()
|
|
|
|
startShiftStr.removeFirst()
|
|
|
|
retVal.id = Int(startShiftStr.components(separatedBy: " ")[0]) ?? -1
|
|
|
|
retVal.id = Int(startShiftStr.components(separatedBy: " ")[0]) ?? -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// print("source line : \(retVal.day) \(hour) : \(retVal.minute) -- splitStr '\(actionStr)'\n")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retVal
|
|
|
|
return retVal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func add(activity: Activity) {
|
|
|
|
func add(activity: Activity) {
|
|
|
|
if activitiesForDay[activity.day] == nil {
|
|
|
|
if activitiesForDay[activity.day] == nil {
|
|
|
|
// print("adding day \(activity.day) activity : \(activity)")
|
|
|
|
|
|
|
|
activitiesForDay[activity.day] = [activity]
|
|
|
|
activitiesForDay[activity.day] = [activity]
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
activitiesForDay[activity.day]!.append(activity)
|
|
|
|
activitiesForDay[activity.day]!.append(activity)
|
|
|
|
@ -149,7 +138,6 @@ class Repose {
|
|
|
|
for day in activitiesForDay.keys {
|
|
|
|
for day in activitiesForDay.keys {
|
|
|
|
activitiesForDay[day]!.sort()
|
|
|
|
activitiesForDay[day]!.sort()
|
|
|
|
sleepMapForGuardID[findID(forDay: day)] = Array(repeating: 0, count: 60)
|
|
|
|
sleepMapForGuardID[findID(forDay: day)] = Array(repeating: 0, count: 60)
|
|
|
|
// print("\(activitiesForDay[day]!)\n")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -165,8 +153,6 @@ class Repose {
|
|
|
|
|
|
|
|
|
|
|
|
func buildHistogram(forDay day: Int) -> [Int] {
|
|
|
|
func buildHistogram(forDay day: Int) -> [Int] {
|
|
|
|
var retVal = Array(repeating: 0, count: 60)
|
|
|
|
var retVal = Array(repeating: 0, count: 60)
|
|
|
|
// var sleepMapForGuardID: [Int : [Int]] = [:] // id : Array if ints, one for each hour; increment if asleep
|
|
|
|
|
|
|
|
// var activitiesForDay: [Int : [Activity]] = [:]
|
|
|
|
|
|
|
|
addActivitiesIfNecessary()
|
|
|
|
addActivitiesIfNecessary()
|
|
|
|
if let array = activitiesForDay[day] {
|
|
|
|
if let array = activitiesForDay[day] {
|
|
|
|
var startSleep = 0
|
|
|
|
var startSleep = 0
|
|
|
|
@ -180,7 +166,6 @@ class Repose {
|
|
|
|
retVal[min] = 1
|
|
|
|
retVal[min] = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// print("\(activity)")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retVal
|
|
|
|
return retVal
|
|
|
|
@ -197,19 +182,19 @@ class Repose {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Sum all the minutes slept, retrun the total and the minute of most sleeps
|
|
|
|
// Sum all the minutes slept, retrun the total and the minute of most sleeps
|
|
|
|
func sumMinutes(forID id: Int) -> (total: Int, maxMinute: Int) {
|
|
|
|
func sumMinutes(forID id: Int) -> (total: Int, maxMinute: Int, maxMinuteVal: Int) {
|
|
|
|
var retVal = (total: 0, maxMinute: -1)
|
|
|
|
var retVal = (total: 0, maxMinute: -1, maxMinuteVal: -1)
|
|
|
|
guard var array = sleepMapForGuardID[id] else { return retVal }
|
|
|
|
guard var array = sleepMapForGuardID[id] else { return retVal }
|
|
|
|
guard array.count == 60 else { return retVal }
|
|
|
|
guard array.count == 60 else { return retVal }
|
|
|
|
for i in 0..<60 {
|
|
|
|
for i in 0..<60 {
|
|
|
|
retVal.total += array[i]
|
|
|
|
retVal.total += array[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
retVal.maxMinute = array.firstIndex(of: (array.max() ?? 1)) ?? 0
|
|
|
|
retVal.maxMinuteVal = array.max() ?? 1
|
|
|
|
// print("ID:\(id), retVal:\(retVal)")
|
|
|
|
retVal.maxMinute = array.firstIndex(of: retVal.maxMinuteVal) ?? 0
|
|
|
|
return retVal
|
|
|
|
return retVal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func findGuard() -> (id: Int, minute: Int) {
|
|
|
|
func findGuard(forPart1 part1: Bool) -> (id: Int, minute: Int) {
|
|
|
|
var retVal = (id: 0, minute: -1)
|
|
|
|
var retVal = (id: 0, minute: -1)
|
|
|
|
addActivitiesIfNecessary()
|
|
|
|
addActivitiesIfNecessary()
|
|
|
|
for day in activitiesForDay.keys {
|
|
|
|
for day in activitiesForDay.keys {
|
|
|
|
@ -219,18 +204,16 @@ class Repose {
|
|
|
|
var maxTime = 0
|
|
|
|
var maxTime = 0
|
|
|
|
for id in sleepMapForGuardID.keys {
|
|
|
|
for id in sleepMapForGuardID.keys {
|
|
|
|
let stats = sumMinutes(forID: id)
|
|
|
|
let stats = sumMinutes(forID: id)
|
|
|
|
if stats.total > maxTime {
|
|
|
|
let maxForPart = part1 ? stats.total : stats.maxMinuteVal
|
|
|
|
maxTime = stats.total
|
|
|
|
if maxForPart > maxTime {
|
|
|
|
|
|
|
|
maxTime = maxForPart
|
|
|
|
retVal.minute = stats.maxMinute
|
|
|
|
retVal.minute = stats.maxMinute
|
|
|
|
retVal.id = id
|
|
|
|
retVal.id = id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retVal
|
|
|
|
return retVal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// [1518-04-04 23:59] Guard #223 begins shift
|
|
|
|
|
|
|
|
// [1518-09-15 00:12] falls asleep
|
|
|
|
|
|
|
|
// [1518-06-01 00:32] wakes up
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Need a state-machine
|
|
|
|
// Need a state-machine
|
|
|
|
// - start shift
|
|
|
|
// - start shift
|
|
|
|
@ -246,7 +229,6 @@ class Repose {
|
|
|
|
// 11-04 #99 ....................................##########..............
|
|
|
|
// 11-04 #99 ....................................##########..............
|
|
|
|
// 11-05 #99 .............................................##########.....
|
|
|
|
// 11-05 #99 .............................................##########.....
|
|
|
|
// #99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0
|
|
|
|
// #99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Day04: AOCDay {
|
|
|
|
class Day04: AOCDay {
|
|
|
|
lazy var tests: (() -> ()) = day04Tests
|
|
|
|
lazy var tests: (() -> ()) = day04Tests
|
|
|
|
@ -306,7 +288,6 @@ class Day04: AOCDay {
|
|
|
|
|
|
|
|
|
|
|
|
func testPasrseLine() {
|
|
|
|
func testPasrseLine() {
|
|
|
|
var response = Repose.parse(line: "")
|
|
|
|
var response = Repose.parse(line: "")
|
|
|
|
// print("Response : \(response)")
|
|
|
|
|
|
|
|
XCTAssertEqual(test: "testPasrseLine empty", withExpression: (response.minute == -1))
|
|
|
|
XCTAssertEqual(test: "testPasrseLine empty", withExpression: (response.minute == -1))
|
|
|
|
let repo = Repose(withString: testData)
|
|
|
|
let repo = Repose(withString: testData)
|
|
|
|
response = Repose.parse(line: repo.scheduleArray[0])
|
|
|
|
response = Repose.parse(line: repo.scheduleArray[0])
|
|
|
|
@ -334,13 +315,10 @@ class Day04: AOCDay {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XCTAssertEqual(test: "testAddActivity number of days", withExpression: (repo.activitiesForDay.keys.count == 5))
|
|
|
|
XCTAssertEqual(test: "testAddActivity number of days", withExpression: (repo.activitiesForDay.keys.count == 5))
|
|
|
|
var count = repo.activitiesForDay[342]?.count ?? 0
|
|
|
|
var count = repo.activitiesForDay[342]?.count ?? 0
|
|
|
|
// print("count : \(count)")
|
|
|
|
|
|
|
|
XCTAssertEqual(test: "testAddActivity activies day 1", withExpression: (count == 5))
|
|
|
|
XCTAssertEqual(test: "testAddActivity activies day 1", withExpression: (count == 5))
|
|
|
|
count = repo.activitiesForDay[343]?.count ?? 0
|
|
|
|
count = repo.activitiesForDay[343]?.count ?? 0
|
|
|
|
// print("count : \(count)")
|
|
|
|
|
|
|
|
XCTAssertEqual(test: "testAddActivity activies day 2", withExpression: (count == 3))
|
|
|
|
XCTAssertEqual(test: "testAddActivity activies day 2", withExpression: (count == 3))
|
|
|
|
count = repo.activitiesForDay[344]?.count ?? 0
|
|
|
|
count = repo.activitiesForDay[344]?.count ?? 0
|
|
|
|
// print("count : \(count)")
|
|
|
|
|
|
|
|
XCTAssertEqual(test: "testAddActivity activies day 3", withExpression: (count == 3))
|
|
|
|
XCTAssertEqual(test: "testAddActivity activies day 3", withExpression: (count == 3))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -387,15 +365,18 @@ class Day04: AOCDay {
|
|
|
|
repo.add(histogram: hist, toID: repo.findID(forDay: day))
|
|
|
|
repo.add(histogram: hist, toID: repo.findID(forDay: day))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var tuple = repo.sumMinutes(forID: 10)
|
|
|
|
var tuple = repo.sumMinutes(forID: 10)
|
|
|
|
XCTAssertEqual(test: "testSumMinutes id 10", withExpression: (tuple == (50, 24)))
|
|
|
|
let passTest = (tuple.total == 50) && (tuple.maxMinute == 24)
|
|
|
|
|
|
|
|
XCTAssertEqual(test: "testSumMinutes id 10", withExpression: passTest)
|
|
|
|
tuple = repo.sumMinutes(forID: 99)
|
|
|
|
tuple = repo.sumMinutes(forID: 99)
|
|
|
|
XCTAssertEqual(test: "testSumMinutes id 99", withExpression: (tuple == (30, 45)))
|
|
|
|
XCTAssertEqual(test: "testSumMinutes id 99", withExpression: (tuple == (30, 45, 3)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testFindGuard() {
|
|
|
|
func testFindGuard() {
|
|
|
|
let repo = Repose(withString: testData)
|
|
|
|
let repo = Repose(withString: testData)
|
|
|
|
let answer = repo.findGuard()
|
|
|
|
var answer = repo.findGuard(forPart1: true)
|
|
|
|
XCTAssertEqual(test: "testFindGuard", withExpression: (answer == (10, 24)))
|
|
|
|
XCTAssertEqual(test: "testFindGuard Part 1", withExpression: (answer == (10, 24)))
|
|
|
|
|
|
|
|
answer = repo.findGuard(forPart1: false)
|
|
|
|
|
|
|
|
XCTAssertEqual(test: "testFindGuard Part 2", withExpression: (answer == (99, 45)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func day04Tests() {
|
|
|
|
func day04Tests() {
|
|
|
|
@ -410,12 +391,10 @@ class Day04: AOCDay {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func day04Final() {
|
|
|
|
func day04Final() {
|
|
|
|
let retVal = "None"
|
|
|
|
|
|
|
|
let repo = Repose(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day04.txt")
|
|
|
|
let repo = Repose(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day04.txt")
|
|
|
|
// let repo = Repose(withString: testData)
|
|
|
|
var answer = repo.findGuard(forPart1: true)
|
|
|
|
let answer = repo.findGuard()
|
|
|
|
|
|
|
|
print("answer=\(answer)")
|
|
|
|
|
|
|
|
print("Answer to part 1 is: \(answer.id * answer.minute)")
|
|
|
|
print("Answer to part 1 is: \(answer.id * answer.minute)")
|
|
|
|
print("Answer to part 2 is: \(retVal)")
|
|
|
|
answer = repo.findGuard(forPart1: false)
|
|
|
|
|
|
|
|
print("Answer to part 2 is: \(answer.id * answer.minute)")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|