Last active
December 17, 2016 15:02
-
-
Save DeepFriedTwinkie/97199334be11447bd89bf10b346170cc to your computer and use it in GitHub Desktop.
AdventOfCode.com 2016/Day 4 Solution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
//: ## Helpers | |
func string(fromFile name:String, fileExtension:String) -> String? { | |
if let filePath = Bundle.main.path(forResource:name, ofType:fileExtension) { | |
if let inputData = FileManager.default.contents(atPath: filePath) { | |
return String(data: inputData, encoding: .utf8) | |
} | |
} | |
return nil | |
} | |
//: ## Solution Objects | |
struct Room { | |
let sectorID: Int | |
let checksum: String | |
let name: String | |
// Used in Part 2 | |
var decryptedName:String { | |
return String(name.characters.map({ return $0.rotate(by: sectorID) } )) | |
} | |
let characterCounts: [Character:Int] | |
let isReal:Bool | |
static func countCharacters(characterArray:[String]) -> [Character:Int] { | |
let singleString = characterArray.joined().characters.sorted() | |
return singleString.reduce([:]) { (counts: [Character : Int], element) in | |
var counts = counts | |
counts[element] = counts[element]?.advanced(by: 1) ?? 1 | |
return counts | |
} | |
} | |
init?(string:String) { | |
let components = string.components(separatedBy: "-") | |
guard components.count >= 2 else { return nil } | |
// Get the SectorID and Checksum | |
guard let numbers = components.last else { return nil } | |
// Get the indexes | |
guard let openBracketIndex = numbers.characters.index(of:"["), | |
let closeBracketIndex = numbers.characters.index(of:"]") else { return nil } | |
// Figure out the sectorID | |
guard let sector = Int(numbers.substring(to: openBracketIndex)) else { | |
return nil | |
} | |
sectorID = sector | |
let tempChecksum = numbers[numbers.index(after: openBracketIndex)..<closeBracketIndex] | |
checksum = tempChecksum | |
// Count up unique characters | |
let tempCharacterCounts = Room.countCharacters(characterArray: Array(components.dropLast())) | |
characterCounts = tempCharacterCounts | |
// Create the name | |
name = components.dropLast().joined(separator: "-") | |
// Check if Real | |
isReal = { | |
let topCounts = tempCharacterCounts.sorted(by: { | |
if $0.value == $1.value { return $0.key < $1.key } | |
return $0.value > $1.value | |
}) | |
let topCharsString = String(topCounts.map({$0.key}).prefix(tempChecksum.characters.count)) | |
return topCharsString == tempChecksum | |
}() | |
} | |
} | |
// Part 2 Solution | |
extension Character { | |
static let zAscii = "z".unicodeScalars.first!.value | |
static let aAscii = "a".unicodeScalars.first!.value | |
func rotate(by: Int) -> Character { | |
switch self { | |
case "a"..."z": | |
let remainder = UInt32(by % 26) | |
let scalars = String(self).unicodeScalars | |
let currentAscii = scalars[scalars.startIndex].value | |
if (currentAscii + remainder) > Character.zAscii { | |
let fromTop = remainder - (Character.zAscii - currentAscii) - 1 | |
return Character(UnicodeScalar(Character.aAscii + fromTop)!) | |
} | |
return Character(UnicodeScalar(currentAscii + remainder)!) | |
default: | |
return " " | |
} | |
} | |
} | |
//: ## Input Processing | |
let day = "Day4" | |
let testInput = ["qzmt-zixmtkozy-ivhz-343"] | |
let testInputs = ["qzmt-zixmtkozy-ivhz-343[abcde]", | |
"aaaaa-bbb-z-y-x-123[abxyz]", | |
"a-b-c-d-e-f-g-h-987[abcde]", | |
"not-a-real-room-404[oarel]", | |
"totally-real-room-200[decoy]"] | |
func prepareInput() -> [Room] { | |
if let inputString = string(fromFile: day, fileExtension: "txt") { | |
let roomStrings = inputString.components(separatedBy: "\n") | |
return roomStrings.flatMap ( { return Room(string: $0) } ) | |
} | |
return [Room]() | |
} | |
//let rooms = prepareInput() | |
let rooms = testInputs.flatMap( { return Room(string:$0) } ) | |
//: ## Solution Execution | |
//: ### Part 1 | |
let sectorSum = rooms.filter( { return $0.isReal }) | |
.reduce(0, {$0 + $1.sectorID} ) | |
print("Part 1 Answer: \(sectorSum)\n") | |
//: ### Part 2 | |
print("Part 2 Answers:") | |
for room in rooms { | |
print("\(room.decryptedName) - \(room.sectorID)") | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated for part 2 solution.