diff --git a/src/aoc2015/Day01.kt b/src/aoc2015/Day01.kt new file mode 100644 index 0000000..54f8667 --- /dev/null +++ b/src/aoc2015/Day01.kt @@ -0,0 +1,57 @@ +package aoc2015 + +import println +import readInput + +/* +--- Day 1: Not Quite Lisp --- +Santa was hoping for a white Christmas, but his weather machine's "snow" function is powered by stars, and he's fresh out! To save Christmas, he needs you to collect fifty stars by December 25th. +Collect stars by helping Santa solve puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck! +Here's an easy puzzle to warm you up. +Santa is trying to deliver presents in a large apartment building, but he can't find the right floor - the directions he got are a little confusing. He starts on the ground floor (floor 0) and then follows the instructions one character at a time. +An opening parenthesis, (, means he should go up one floor, and a closing parenthesis, ), means he should go down one floor. +The apartment building is very tall, and the basement is very deep; he will never find the top or bottom floors. +For example: + +(()) and ()() both result in floor 0. +((( and (()(()( both result in floor 3. +))((((( also results in floor 3. +()) and ))( both result in floor -1 (the first basement level). +))) and )())()) both result in floor -3. + +To what floor do the instructions take Santa? + +*/ +fun main() { + + val inlineTestInput = """ +(()(()( +""" + + fun part1(input: List): Int { + return input.single().count { it == '(' } - input.single().count { it == ')' } + } + + fun part2(input: List): Int { + var floor = 0 + for ((i, c) in input.single().withIndex()) { + if (c == '(') floor++ else floor-- + if (floor < 0) return i + 1 + } + return 0 + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + //val testInput = readInput("aoc2015/Day01_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 3) + check(testInputPart2Result == 0) + + val input = readInput("aoc2015/Day01") + part1(input).println() + part2(input).println() +} diff --git a/src/aoc2015/Day02.kt b/src/aoc2015/Day02.kt new file mode 100644 index 0000000..1769a2a --- /dev/null +++ b/src/aoc2015/Day02.kt @@ -0,0 +1,52 @@ +package aoc2015 + +import println +import readInput + +/* +--- Day 2: I Was Told There Would Be No Math --- +The elves are running low on wrapping paper, and so they need to submit an order for more. They have a list of the dimensions (length l, width w, and height h) of each present, and only want to order exactly as much as they need. +Fortunately, every present is a box (a perfect right rectangular prism), which makes calculating the required wrapping paper for each gift a little easier: find the surface area of the box, which is 2*l*w + 2*w*h + 2*h*l. The elves also need a little extra paper for each present: the area of the smallest side. +For example: + +A present with dimensions 2x3x4 requires 2*6 + 2*12 + 2*8 = 52 square feet of wrapping paper plus 6 square feet of slack, for a total of 58 square feet. +A present with dimensions 1x1x10 requires 2*1 + 2*10 + 2*10 = 42 square feet of wrapping paper plus 1 square foot of slack, for a total of 43 square feet. + +All numbers in the elves' list are in feet. How many total square feet of wrapping paper should they order? + +*/ +fun main() { + + val inlineTestInput = """ +2x3x4 +1x1x10 +""" + + fun part1(input: List): Int { + return input.sumOf { + val dims = it.split("x").map(String::toInt).sorted() + 2 * dims[0] * dims[1] + 2 * dims[1] * dims[2] + 2 * dims[0] * dims[2] + dims[0] * dims[1] + } + } + + fun part2(input: List): Int { + return input.sumOf { + val dims = it.split("x").map(String::toInt).sorted() + 2 * (dims[0] + dims[1]) + dims.reduce(Int::times) + } + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + //val testInput = readInput("aoc2015/Day02_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 58 + 43) + check(testInputPart2Result == 34 + 14) + + val input = readInput("aoc2015/Day02") + part1(input).println() + part2(input).println() +} diff --git a/src/aoc2015/Day03.kt b/src/aoc2015/Day03.kt new file mode 100644 index 0000000..5895d20 --- /dev/null +++ b/src/aoc2015/Day03.kt @@ -0,0 +1,85 @@ +package aoc2015 + +import RelPos +import println +import readInput + +/* +--- Day 3: Perfectly Spherical Houses in a Vacuum --- +Santa is delivering presents to an infinite two-dimensional grid of houses. +He begins by delivering a present to the house at his starting location, and then an elf at the North Pole calls him via radio and tells him where to move next. Moves are always exactly one house to the north (^), south (v), east (>), or west (<). After each move, he delivers another present to the house at his new location. +However, the elf back at the north pole has had a little too much eggnog, and so his directions are a little off, and Santa ends up visiting some houses more than once. How many houses receive at least one present? +For example: + +> delivers presents to 2 houses: one at the starting location, and one to the east. +^>v< delivers presents to 4 houses in a square, including twice to the house at his starting/ending location. +^v^v^v^v^v delivers a bunch of presents to some very lucky children at only 2 houses. + + +*/ +fun main() { + + val inlineTestInput = """ +^>v< +""" + + fun part1(input: List): Int { + val houses = HashSet() + var x = 0 + var y = 0 + for (c in input.single()) { + when (c) { + '<' -> x-- + '>' -> x++ + '^' -> y-- + 'v' -> y++ + } + houses.add(RelPos(x, y)) + } + return houses.size + } + + fun part2(input: List): Int { + val houses = HashSet() + var xs = 0 + var ys = 0 + var xr = 0 + var yr = 0 + var parity = false + for (c in input.single()) { + if (parity) { + when (c) { + '<' -> xr-- + '>' -> xr++ + '^' -> yr-- + 'v' -> yr++ + } + houses.add(RelPos(xr, yr)) + } else { + when (c) { + '<' -> xs-- + '>' -> xs++ + '^' -> ys-- + 'v' -> ys++ + } + houses.add(RelPos(xs, ys)) + } + parity = !parity + } + return houses.size + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + //val testInput = readInput("aoc2015/Day03_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 4) + check(testInputPart2Result == 3) + + val input = readInput("aoc2015/Day03") + part1(input).println() + part2(input).println() +} diff --git a/src/aoc2015/Day04.kt b/src/aoc2015/Day04.kt new file mode 100644 index 0000000..afd34ec --- /dev/null +++ b/src/aoc2015/Day04.kt @@ -0,0 +1,45 @@ +package aoc2015 + +import md5 +import println +import readInput + +/* +--- Day 4: The Ideal Stocking Stuffer --- +Santa needs help mining some AdventCoins (very similar to bitcoins) to use as gifts for all the economically forward-thinking little girls and boys. +To do this, he needs to find MD5 hashes which, in hexadecimal, start with at least five zeroes. The input to the MD5 hash is some secret key (your puzzle input, given below) followed by a number in decimal. To mine AdventCoins, you must find Santa the lowest positive number (no leading zeroes: 1, 2, 3, ...) that produces such a hash. +For example: + +If your secret key is abcdef, the answer is 609043, because the MD5 hash of abcdef609043 starts with five zeroes (000001dbbfa...), and it is the lowest such number to do so. +If your secret key is pqrstuv, the lowest number it combines with to make an MD5 hash starting with five zeroes is 1048970; that is, the MD5 hash of pqrstuv1048970 looks like 000006136ef.... + + +*/ +fun main() { + + val inlineTestInput = """ +abcdef +""" + + fun part1(input: List): Int { + return IntRange(0, 10000000).first { (input.single() + it.toString()).md5().startsWith("00000") } + } + + fun part2(input: List): Int { + return IntRange(0, 10000000).first { (input.single() + it.toString()).md5().startsWith("000000") } + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + //val testInput = readInput("aoc2015/Day04_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 609043) + //check(testInputPart2Result == 0) + + val input = readInput("aoc2015/Day04") + part1(input).println() + part2(input).println() +} diff --git a/src/aoc2015/Day05.kt b/src/aoc2015/Day05.kt new file mode 100644 index 0000000..4b15089 --- /dev/null +++ b/src/aoc2015/Day05.kt @@ -0,0 +1,78 @@ +package aoc2015 + +import println +import readInput + +/* +--- Day 5: Doesn't He Have Intern-Elves For This? --- +Santa needs help figuring out which strings in his text file are naughty or nice. +A nice string is one with all of the following properties: + +It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou. +It contains at least one letter that appears twice in a row, like xx, abcdde (dd), or aabbccdd (aa, bb, cc, or dd). +It does not contain the strings ab, cd, pq, or xy, even if they are part of one of the other requirements. + +For example: + +ugknbfddgicrmopn is nice because it has at least three vowels (u...i...o...), a double letter (...dd...), and none of the disallowed substrings. +aaa is nice because it has at least three vowels and a double letter, even though the letters used by different rules overlap. +jchzalrnumimnmhp is naughty because it has no double letter. +haegwjzuvuyypxyu is naughty because it contains the string xy. +dvszwmarrgswjxmb is naughty because it contains only one vowel. + +How many strings are nice? + +*/ +fun main() { + + val inlineTestInput = """ +ugknbfddgicrmopn +aaa +jchzalrnumimnmhp +haegwjzuvuyypxyu +dvszwmarrgswjxmb +""" + + val inlineTestInput2 = """ +qjhvhtzxzqqjkmpb +xxyxx +uurcxstgmygtbstg +ieodomkazucvgmuy +""" + + fun part1(input: List): Int { + var nice = 0 + for (i in input) { + val vowels = i.filter { "aeiou".contains(it) }.take(3).count() == 3 + val double = i.zipWithNext { a, b -> a == b }.any { it } + val sane = listOf("ab", "cd", "pq", "xy").none { i.contains(it) } + if (vowels && double && sane) nice++ + } + return nice + } + + fun part2(input: List): Int { + var nice = 0 + for (i in input) { + val double = i.zipWithNext { a, b -> "$a$b" }.any { i.replace(it, "").length < i.length - 3 } + val spaced = i.zipWithNext().zipWithNext().any { it.first.first == it.second.second } + if (double && spaced) nice++ + } + return nice + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + val testInput2 = inlineTestInput2.trim().reader().readLines() + //val testInput = readInput("aoc2015/Day05_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput2) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 2) + check(testInputPart2Result == 2) + + val input = readInput("aoc2015/Day05") + part1(input).println() + part2(input).println() +} diff --git a/src/downloader/Downloader.kt b/src/downloader/Downloader.kt index 63efa38..490a585 100644 --- a/src/downloader/Downloader.kt +++ b/src/downloader/Downloader.kt @@ -23,7 +23,7 @@ fun main() { cookie = props.getProperty("cookie", cookie) } - val downloader = Downloader(2023, "aoc2023", cookie) + val downloader = Downloader(2015, "aoc2015", cookie) downloader.updateToLatest() }