Advent of Code 2023 day 1
12/01/2023, 5:00 AMNeil Banman
12/01/2023, 5:06 AMJakub Gwóźdź
12/01/2023, 5:44 AMPaul Woitaschek
12/01/2023, 5:49 AMMarcin Wisniowski
12/01/2023, 6:15 AMMarcin Wisniowski
12/01/2023, 6:16 AMMichael de Kaste
12/01/2023, 6:17 AMoverride fun part2(): Any? {
return parsed.sumOf {
val firstDigit = digits
.minByOrNull { (text, _) ->
it.indexOf(text).let { if(it == -1) MAX_VALUE else it }
}!!.value
val lastDigit = digits
.maxByOrNull { (text, _) ->
it.lastIndexOf(text).let { if(it == -1) MIN_VALUE else it }
}!!.value
firstDigit * 10 + lastDigit
}
}
Michael de Kaste
12/01/2023, 6:18 AMJakub Gwóźdź
12/01/2023, 6:18 AMfun part1(input: Input) = input.sumOf(String::part1calibration)
fun part2(input: Input) = input.sumOf(String::part2calibration)
private fun String.part1calibration() = first(Char::isDigit).digitToInt() * 10 + last(Char::isDigit).digitToInt()
private fun String.part2calibration(): Int {
val l1: Int = indices.firstNotNullOf { betterToDigitOrNull(it) }
val l2: Int = indices.reversed().firstNotNullOf { betterToDigitOrNull(it) }
return l1 * 10 + l2
}
private fun String.betterToDigitOrNull(startIndex: Int): Int? =
if (this[startIndex].isDigit()) this[startIndex].digitToInt()
else digitNames.firstNotNullOfOrNull { (d, name) -> if (startsWith(name, startIndex)) d else null }
val digitNames = listOf(
1 to "one",
2 to "two",
3 to "three",
4 to "four",
5 to "five",
6 to "six",
7 to "seven",
8 to "eight",
9 to "nine",
)
Arkadiusz
12/01/2023, 6:23 AMMarcin Wisniowski
12/01/2023, 6:24 AMBartosz Michalik
12/01/2023, 6:25 AMval digits = listOf(
"one" to '1',
"two" to '2',
"three" to '3',
"four" to '4',
"five" to '5',
"six" to '6',
"seven" to '7',
"eight" to '8',
"nine" to '9'
)
var remaining = input
return sequence {
while(remaining.isNotEmpty()) {
if (remaining.get(0).isDigit()) {
yield(remaining.get(0))
} else {
digits.filter {
remaining.startsWith(it.first)
}.firstOrNull()?.let { yield(it.second) }
}
remaining = remaining.drop(1)
}
}.toList()
}
fun part2(input: List<String>): Any {
fun parse(input: List<String>) = input.map { parseLine(it) }
return parse(input).sumOf { "${it.first()}${it.last()}".toInt() }
}
Jakub Gwóźdź
12/01/2023, 6:25 AM.replace(…)
after reading the part2. And just after submitting the result I read the description and found out that "zero"
is not a valid digit name. Fortunately there was no such substring in my inputMichael de Kaste
12/01/2023, 6:28 AMobject Day1 : Challenge() {
val parsed = input.lines()
override fun part1() = parsed
.map { it.filter(Char::isDigit) }
.sumOf { it.first().digitToInt() * 10 + it.last().digitToInt() }
override fun part2() = parsed.sumOf {
val firstDigit = digits.minByOrNull { (text, _) -> it.indexOfOrNull(text) ?: MAX_VALUE }!!.value
val lastDigit = digits.maxByOrNull { (text, _) -> it.lastIndexOfOrNull(text) ?: MIN_VALUE }!!.value
firstDigit * 10 + lastDigit
}
private val digits = mapOf(
"1" to 1,
"2" to 2,
"3" to 3,
"4" to 4,
"5" to 5,
"6" to 6,
"7" to 7,
"8" to 8,
"9" to 9,
"one" to 1,
"two" to 2,
"three" to 3,
"four" to 4,
"five" to 5,
"six" to 6,
"seven" to 7,
"eight" to 8,
"nine" to 9,
)
}
Anirudh
12/01/2023, 6:30 AMtreb7uchet --> 77
Arkadiusz
12/01/2023, 6:39 AMDan Fingal-Surma
12/01/2023, 6:41 AMAnirudh
12/01/2023, 6:42 AMDan Fingal-Surma
12/01/2023, 6:43 AMString.findAnyOf
and String.findLastAnyOf
Norbert Kiesel
12/01/2023, 6:46 AMMichael de Kaste
12/01/2023, 6:47 AMMichael de Kaste
12/01/2023, 6:47 AMAnirudh
12/01/2023, 6:47 AMNorbert Kiesel
12/01/2023, 6:47 AMDan Fingal-Surma
12/01/2023, 6:48 AMDan Fingal-Surma
12/01/2023, 6:49 AMNorbert Kiesel
12/01/2023, 6:51 AMDan Fingal-Surma
12/01/2023, 6:54 AMNorbert Kiesel
12/01/2023, 6:56 AMNorbert Kiesel
12/01/2023, 6:57 AMxxfast
12/01/2023, 7:02 AMNeil Banman
12/01/2023, 7:05 AMAnirudh
12/01/2023, 7:17 AMJacob
12/01/2023, 7:24 AMDavio
12/01/2023, 8:18 AMDavio
12/01/2023, 8:25 AMlastIndexOf
instead of indexOf
and using maxBy
instead of minBy
Michael de Kaste
12/01/2023, 8:32 AMMichael de Kaste
12/01/2023, 8:33 AMobject Day1 : Challenge() {
val parsed = input.lines()
private fun List<String>.solve() = map { it.filter(Char::isDigit) }
.sumOf { it.first().digitToInt() * 10 + it.last().digitToInt() }
override fun part1() = parsed.solve()
override fun part2() = parsed
.map { replacements.fold(it) { line, (key, value) -> line.replace(key, "$key$value$key") } }
.solve()
private val replacements = listOf(
"one" to 1,
"two" to 2,
"three" to 3,
"four" to 4,
"five" to 5,
"six" to 6,
"seven" to 7,
"eight" to 8,
"nine" to 9,
)
}
Jakub Gwóźdź
12/01/2023, 8:37 AMgsed -r -e "s/one/on1ne/g" -e "s/two/tw2wo/g" -e "s/three/th3ee/g" -e "s/four/fo4ur/g" ...
Davio
12/01/2023, 8:42 AMMichael de Kaste
12/01/2023, 9:03 AMprivate val replacements = listOf(
"one" to "o1e",
"two" to "t2o",
"three" to "t3e",
"four" to "4",
"five" to "5e",
"six" to "6",
"seven" to "7n",
"eight" to "e8t",
"nine" to "n9e",
)
Norbert Kiesel
12/01/2023, 9:06 AMprivate fun three(input: List<String>, withLetters: Boolean): Int {
val map = (1..9).associateBy { it.toString() }.toMutableMap()
if (withLetters) map += mapOf(
"one" to 1, "two" to 2, "three" to 3, "four" to 4, "five" to 5,
"six" to 6, "seven" to 7, "eight" to 8, "nine" to 9
)
val pattern = map.keys.joinToString("|").toRegex()
fun calibration(line: String): Int {
fun IntProgression.digit() = firstNotNullOf { i -> pattern.find(line, i)?.let { map[it.value]!! } }
val first = line.indices.digit()
val last = line.indices.reversed().digit()
return first * 10 + last
}
return input.sumOf { calibration(it) }
}
Michael Böiers
12/01/2023, 9:29 AMpackage aoc2023
fun main() = day01(String(System.`in`.readAllBytes()).split("\n")).forEach(::println)
private fun day01(lines: List<String>): List<Any?> {
val part1 = lines.sumOf { line ->
line.mapNotNull(Char::digitToIntOrNull).let { it.first() * 10 + it.last() }
}
val digits = buildMap {
listOf("one", "two", "three", "four", "five", "six", "seven", "eight", "nine").forEachIndexed { i, s ->
val n = i + 1
put(n.toString(), n)
put(s, n)
}
}
val part2 = lines.sumOf { line ->
val first = digits.getValue(digits.keys.minBy { line.indexOfOrNull(it) ?: Int.MAX_VALUE })
val last = digits.getValue(digits.keys.maxBy { line.lastIndexOf(it) })
first * 10 + last
}
return listOf(part1, part2)
}
fun String.indexOfOrNull(s: String) = indexOf(s).takeIf { it >= 0 }
Lovro Ludvig
12/01/2023, 10:16 AMfun main() {
fun Pair<String, String>.replacement() = second + first.substring(1)
fun findCalibrationCodePartOne(input: List<String>): Long {
// Calculate the code
var sum = 0L
input.map { calibrationLine ->
var firstDigit: Char? = null
var lastDigit: Char? = null
for (index in calibrationLine.indices) {
calibrationLine[index].takeIf { it.isDigit() }?.let { digit ->
if (firstDigit == null) firstDigit = digit
lastDigit = digit
}
}
sum += ("$firstDigit$lastDigit").toInt()
}
return sum
}
fun findCalibrationCodePartTwo(input: List<String>): Long {
// Mapper
val mapper = arrayOf(
"one" to "1",
"two" to "2",
"three" to "3",
"four" to "4",
"five" to "5",
"six" to "6",
"seven" to "7",
"eight" to "8",
"nine" to "9",
)
// Remap values
val adjustedInput = input.map { oldCalibrationLine ->
var newCalibrationLine = oldCalibrationLine
for (index in oldCalibrationLine.indices) {
mapper.forEach { mapperPair ->
val substring = oldCalibrationLine.substring(index)
if (substring.startsWith(mapperPair.first)) {
newCalibrationLine = newCalibrationLine.replace(
oldValue = substring,
newValue = substring.replaceFirst(mapperPair.first, mapperPair.replacement()),
)
}
}
}
newCalibrationLine
}
return findCalibrationCodePartOne(adjustedInput)
}
val calibrationDocument = readInput("Day_01_calibration")
println(findCalibrationCodePartOne(calibrationDocument))
println(findCalibrationCodePartTwo(calibrationDocument))
}
Tolly Kulczycki
12/01/2023, 11:22 AMTolly Kulczycki
12/01/2023, 11:43 AMt2o
in case of a twone
?Michael de Kaste
12/01/2023, 11:51 AMOzioma Ogbe
12/01/2023, 11:57 AM```
fun main() {
val filePath = Paths.get("input1.txt")
val input = Files.readAllLines(filePath)
val digitMap = (1..9).groupBy { it }.mapKeys { it.key.toString() }.mapValues { it.value.first() } +
("one,two,three,four,five,six,seven,eight,nine").split(",")
.mapIndexed { index, value -> value to index + 1 }.toMap()
val result = input.sumOf { line ->
val matched = Regex("""(?=(\d|eight|one|two|three|four|five|six|seven|nine))""").findAll(line).toList()
(digitMap[matched.first().groups[1]!!.value]!! * 10 + digitMap[matched.last().groups[1]!!.value]!!).toInt()
}
println(result)
}```
joney
12/01/2023, 12:54 PMDavio
12/01/2023, 1:01 PMDavio
12/01/2023, 1:25 PMDavio
12/01/2023, 2:12 PMprivate val digitWords = listOf(
"one", "two", "three", "four", "five",
"six", "seven", "eight", "nine"
)
private val digitWordsReversed = digitWords.map { it.reversed() }
private fun getFirstDigit(line: String): Int = getNthDigit(line, digitWords)
private fun getLastDigit(line: String): Int = getNthDigit(line.reversed(), digitWordsReversed)
private fun getNthDigit(line: String, words: List<String>): Int {
var buffer = ""
var expectedChars = words.map { it.first() }.toSet()
line.forEach { c ->
if (c.isDigit()) return c.digitToInt()
if (!expectedChars.contains(c)) {
buffer = ""
return@forEach
}
buffer += c
expectedChars = words.filter { it.startsWith(buffer) }.mapNotNull { it.drop(buffer.length).firstOrNull() }.toSet()
if (expectedChars.isEmpty()) {
return words.indexOf(buffer) + 1
}
}
return -1
}
So this builds up a buffer of characters which may end up forming a digit word, but as soon as a character is found that is not expected, it clears the buffer and continues:
expectedChars = words.filter { it.startsWith(buffer) }.mapNotNull { it.drop(buffer.length).firstOrNull() }.toSet()
is a bit of cryptic way to get the set of next expected characters.
If there are no more expected characters, it must mean we have completed a word and can convert it to its digit (just using the index of it in the list).
The return -1
is actually never reached with this input.
It could be streamlined a bit more, but for now it sufficesPoisonedYouth
12/01/2023, 2:32 PMprivate enum class Digits(val intValue: Int) {
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9)
}
private fun createWordIndexMapFor(line: String): Map<Digits, Sequence<Int>> = Digits.entries.associateWith { word ->
Regex(word.name.lowercase()).findAll(line).map { it.range.first }
}.filter { matches -> matches.value.any { it > -1 } }
private fun Map<Digits, Sequence<Int>>.getMin(): Int {
return this.minBy { it.value.min() }.key.intValue
}
private fun Map<Digits, Sequence<Int>>.getMinIndex(): Int {
return this.minBy { it.value.min() }.value.min()
}
private fun Map<Digits, Sequence<Int>>.getMax(): Int {
return this.maxBy { it.value.max() }.key.intValue
}
private fun Map<Digits, Sequence<Int>>.getMaxIndex(): Int {
return this.maxBy { it.value.max() }.value.max()
}
private fun findFirstDigit(
indexOfWords: Map<Digits, Sequence<Int>>,
line: String,
index: Int
): Int = when {
indexOfWords.isEmpty() -> line[index].digitToInt()
index == -1 -> indexOfWords.getMin()
indexOfWords.getMinIndex() < index -> indexOfWords.getMin()
else -> line[index].digitToInt()
}
private fun findLastDigit(
indexOfWords: Map<Digits, Sequence<Int>>,
line: String,
index: Int
): Int = when {
indexOfWords.isEmpty() -> line[index].digitToInt()
index == -1 -> indexOfWords.getMax()
indexOfWords.getMaxIndex() > index -> indexOfWords.getMax()
else -> line[index].digitToInt()
}
fun part2(input: List<String>): Int {
return input.sumOf { line ->
val indexOfWords = createWordIndexMapFor(line)
val firstIndexInt = line.indexOfFirst { it.isDigit() }
val lastIndexInt = line.indexOfLast { it.isDigit() }
val first = findFirstDigit(indexOfWords, line, firstIndexInt)
val last = findLastDigit(indexOfWords, line, lastIndexInt)
"$first$last".toInt()
}
}
Charles Flynn
12/01/2023, 3:32 PMTolly Kulczycki
12/01/2023, 3:34 PMNimu
12/01/2023, 4:55 PMNorbert Kiesel
12/01/2023, 5:14 PMprivate fun three(input: List<String>, withLetters: Boolean): Int {
val map = (1..9).associateBy { it.toString() }.toMutableMap()
if (withLetters) map += mapOf(
"one" to 1, "two" to 2, "three" to 3, "four" to 4, "five" to 5,
"six" to 6, "seven" to 7, "eight" to 8, "nine" to 9
)
fun calibration(line: String): Int {
val first = map[line.findAnyOf(map.keys)!!.second]!!
val last = map[line.findLastAnyOf(map.keys)!!.second]!!
return first * 10 + last
}
return input.sumOf { calibration(it) }
}
ConorG
12/01/2023, 5:44 PMritesh
12/01/2023, 5:55 PMfun part1(input: List<String>): Int {
return input.sumOf {
(it.find { it.isDigit() }.toString() + it.findLast { it.isDigit() }).toInt()
}
}
fun part2(input: List<String>): Int {
val map = mapOf(
"one" to 1, "two" to 2, "three" to 3, "four" to 4,
"five" to 5, "six" to 6, "seven" to 7, "eight" to 8, "nine" to 9,
"1" to 1, "2" to 2, "3" to 3, "4" to 4, "5" to 5, "6" to 6,
"7" to 7, "8" to 8, "9" to 9
)
return input.sumOf {
val first = map[it.findAnyOf(map.keys)!!.second].toString()
val second = map[it.findLastAnyOf(map.keys)!!.second].toString()
(first + second).toInt()
}
}
Mofe Ejegi
12/01/2023, 6:01 PMfun part2() {
val figures = listOf("one", "two", "three", "four", "five", "six", "seven", "eight", "nine")
val nums = (1..9).map { it.toString() }
val figMap = figures.associateWith { figures.indexOf(it) + 1 } + nums.associateWith { it.toInt() }
val values = mutableListOf<Int>()
inputList.forEach { line ->
var firstIndex = Int.MAX_VALUE
var lastIndex = Int.MIN_VALUE
var firstValue = 0
var lastValue = 0
(figures+nums).forEach {
if (line.contains(it)) {
if (firstIndex != minOf(firstIndex, line.indexOf(it))) {
firstIndex = minOf(firstIndex, line.indexOf(it))
firstValue = figMap[it]!!.toInt()
}
if (lastIndex != maxOf(lastIndex, line.lastIndexOf(it))) {
lastIndex = maxOf(lastIndex, line.lastIndexOf(it))
lastValue = figMap[it]!!.toInt()
}
}
}
values.add("${firstValue}${lastValue}".toInt())
}
println(values.sum())
}
Unusually tricky Day 1.phldavies
12/01/2023, 8:04 PMdenis
12/01/2023, 10:27 PMMichael Böiers
12/01/2023, 10:31 PMephemient
12/02/2023, 1:43 AMindexOfLast
and lastIndexOf
are clearly different functions but it's a bit annoying when I write one expecting the other 😕Nikita Merinov
12/02/2023, 9:37 AMfindAnyOf
and findLastAnyOf
and passed them as params into separate fun. Though it may be harder to understand now.phldavies
12/02/2023, 10:11 AM@AoKSolution
object Day01FindAnyOf : PuzDSL({
part1 {
lines.sumOf {
val first = it.firstNotNullOf(Char::digitToIntOrNull)
val last = it.lastOrNull(Char::isDigit)!!.digitToInt()
10 * first + last
}
}
part2 {
val digits = listOf(
"one", "two", "three", "four", "five",
"six", "seven", "eight", "nine",
) + (1..9).map(Int::toString)
fun Pair<Int, String>?.value() =
if (this == null) 0
else second.singleOrNull()?.digitToInt()
?: digits.indexOf(second).inc()
lines.sumOf {
val first = it.findAnyOf(digits).value()
val last = it.findLastAnyOf(digits).value()
10 * first + last
}
}
})
I opted to create an extension off the result of each so the flow of the code stays clear.makobernal
12/02/2023, 3:40 PMritesh
12/02/2023, 3:43 PMTolly Kulczycki
12/02/2023, 3:43 PMmakobernal
12/02/2023, 3:46 PMone
will not ever be replaced…. Thank you, will try it!Mofe Ejegi
12/02/2023, 3:47 PMmakobernal
12/02/2023, 3:50 PMJacek Rondio
12/03/2023, 1:07 PM