Compare commits
2 Commits
a9b398d1ad
...
59db6f9c82
Author | SHA1 | Date |
---|---|---|
chylex | 59db6f9c82 | |
chylex | 140d110213 |
|
@ -6,9 +6,12 @@
|
|||
<component name="CidrRootsConfiguration">
|
||||
<sourceRoots>
|
||||
<file path="$PROJECT_DIR$/2015" />
|
||||
<file path="$PROJECT_DIR$/2020" />
|
||||
</sourceRoots>
|
||||
<excludeRoots>
|
||||
<file path="$PROJECT_DIR$/.gradle" />
|
||||
<file path="$PROJECT_DIR$/2020/target" />
|
||||
<file path="$PROJECT_DIR$/2021" />
|
||||
<file path="$PROJECT_DIR$/build" />
|
||||
<file path="$PROJECT_DIR$/gradle" />
|
||||
</excludeRoots>
|
||||
|
|
143
2021/08/main.kt
143
2021/08/main.kt
|
@ -1,35 +1,132 @@
|
|||
import Position.BOTTOM
|
||||
import Position.BOTTOM_LEFT
|
||||
import Position.BOTTOM_RIGHT
|
||||
import Position.MIDDLE
|
||||
import Position.TOP
|
||||
import Position.TOP_LEFT
|
||||
import Position.TOP_RIGHT
|
||||
import java.io.File
|
||||
import java.util.EnumSet
|
||||
|
||||
fun main() {
|
||||
val records = File("input/1.txt").readLines().map { line ->
|
||||
line.split(" | ", limit = 2).map { it.split(' ') }.let { Record(it[0], it[1]) }
|
||||
line.split(" | ", limit = 2).map { it.split(' ') }.let { Record(it[0], it[1]) }
|
||||
}
|
||||
|
||||
val simpleDigitCount = records.sumOf { r -> r.output.count { it.length in UNIQUE_SEGMENT_COUNT_TO_DIGITS } }
|
||||
part1(records)
|
||||
part2(records)
|
||||
}
|
||||
|
||||
fun part1(records: List<Record>) {
|
||||
@Suppress("ConvertLambdaToReference")
|
||||
val segmentCountToDigits = DIGITS
|
||||
.map { it.value to it.positions.size }
|
||||
.groupBy { it.second }
|
||||
.mapValues { it.value.map { e -> e.first } }
|
||||
|
||||
val uniqueSegmentCountToDigits = segmentCountToDigits
|
||||
.filterValues { it.size == 1 }
|
||||
.mapValues { it.value.single() }
|
||||
|
||||
val simpleDigitCount = records.sumOf { r -> r.output.count { it.length in uniqueSegmentCountToDigits } }
|
||||
println("Total appearances of 1,4,7,8: $simpleDigitCount")
|
||||
}
|
||||
|
||||
private data class Record(val patterns: List<String>, val output: List<String>)
|
||||
fun part2(records: List<Record>) {
|
||||
println("Total output: ${records.sumOf(Record::deduceOutput)}")
|
||||
}
|
||||
|
||||
private val DIGIT_TO_SEGMENT_COUNT = mapOf(
|
||||
0 to 6,
|
||||
1 to 2,
|
||||
2 to 5,
|
||||
3 to 5,
|
||||
4 to 4,
|
||||
5 to 5,
|
||||
6 to 6,
|
||||
7 to 3,
|
||||
8 to 7,
|
||||
9 to 6,
|
||||
data class Digit(val value: Int, val positions: EnumSet<Position>)
|
||||
|
||||
enum class Position {
|
||||
TOP,
|
||||
TOP_LEFT,
|
||||
TOP_RIGHT,
|
||||
MIDDLE,
|
||||
BOTTOM_LEFT,
|
||||
BOTTOM_RIGHT,
|
||||
BOTTOM
|
||||
}
|
||||
|
||||
private val DIGITS = listOf(
|
||||
Digit(0, EnumSet.of(TOP, TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM)),
|
||||
Digit(1, EnumSet.of(TOP_RIGHT, BOTTOM_RIGHT)),
|
||||
Digit(2, EnumSet.of(TOP, TOP_RIGHT, MIDDLE, BOTTOM_LEFT, BOTTOM)),
|
||||
Digit(3, EnumSet.of(TOP, TOP_RIGHT, MIDDLE, BOTTOM_RIGHT, BOTTOM)),
|
||||
Digit(4, EnumSet.of(TOP_LEFT, TOP_RIGHT, MIDDLE, BOTTOM_RIGHT)),
|
||||
Digit(5, EnumSet.of(TOP, TOP_LEFT, MIDDLE, BOTTOM_RIGHT, BOTTOM)),
|
||||
Digit(6, EnumSet.of(TOP, TOP_LEFT, MIDDLE, BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM)),
|
||||
Digit(7, EnumSet.of(TOP, TOP_RIGHT, BOTTOM_RIGHT)),
|
||||
Digit(8, EnumSet.of(TOP, TOP_LEFT, TOP_RIGHT, MIDDLE, BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM)),
|
||||
Digit(9, EnumSet.of(TOP, TOP_LEFT, TOP_RIGHT, MIDDLE, BOTTOM_RIGHT, BOTTOM)),
|
||||
)
|
||||
|
||||
@Suppress("ConvertLambdaToReference")
|
||||
private val SEGMENT_COUNT_TO_DIGITS = DIGIT_TO_SEGMENT_COUNT
|
||||
.entries
|
||||
.groupBy { it.value }
|
||||
.mapValues { it.value.map { e -> e.key } }
|
||||
|
||||
private val UNIQUE_SEGMENT_COUNT_TO_DIGITS = SEGMENT_COUNT_TO_DIGITS
|
||||
.filterValues { it.size == 1 }
|
||||
.mapValues { it.value.single() }
|
||||
data class Record(val patterns: List<String>, val output: List<String>) {
|
||||
private fun deduceMapping(): Map<Char, Position> {
|
||||
val mapping = mutableMapOf<Char, Position>()
|
||||
|
||||
// The digit 1 is made of the top right and bottom right segment.
|
||||
val patternFor1 = patterns.first { it.length == 2 }
|
||||
|
||||
// We can deduce the mapping for both right segments by counting how many times each segment
|
||||
// appears among all of the digits (top right appears in 8 digits, bottom right in 9 digits).
|
||||
if (patterns.count { patternFor1[0] in it } == 8) {
|
||||
mapping[patternFor1[0]] = TOP_RIGHT
|
||||
mapping[patternFor1[1]] = BOTTOM_RIGHT
|
||||
}
|
||||
else {
|
||||
mapping[patternFor1[1]] = TOP_RIGHT
|
||||
mapping[patternFor1[0]] = BOTTOM_RIGHT
|
||||
}
|
||||
|
||||
// The digit 7 is made of both right segments, and the top segment.
|
||||
val patternFor7 = patterns.first { it.length == 3 }
|
||||
|
||||
// We can deduce the mapping for the top segment,
|
||||
// since it is the only segment which is not shared with the digit 1.
|
||||
mapping[patternFor7.first { it !in patternFor1 }] = TOP
|
||||
|
||||
// The digit 4 is made of both right segments, the top left segment, and the middle segment.
|
||||
// Both right segments are already deduced, so we only want the remaining two segments.
|
||||
val patternFor4MinusDeduced = patterns.first { it.length == 4 }.toSet().minus(patternFor1.toSet()).toTypedArray()
|
||||
|
||||
// We can deduce the mapping for the top left and middle segments by counting how many times each segment
|
||||
// appears among all of the digits (top left appears in 6 digits, middle in 7 digits).
|
||||
if (patterns.count { patternFor4MinusDeduced[0] in it } == 6) {
|
||||
mapping[patternFor4MinusDeduced[0]] = TOP_LEFT
|
||||
mapping[patternFor4MinusDeduced[1]] = MIDDLE
|
||||
}
|
||||
else {
|
||||
mapping[patternFor4MinusDeduced[1]] = TOP_LEFT
|
||||
mapping[patternFor4MinusDeduced[0]] = MIDDLE
|
||||
}
|
||||
|
||||
// The digit 8 uses all seven segments, so we use it and remove the five segments we already know,
|
||||
// keeping the remaining two segments (bottom left, and bottom).
|
||||
val remainingSegments = patterns.first { it.length == 7 }.toSet().minus(mapping.keys.toSet()).toTypedArray()
|
||||
|
||||
// We can deduce the mapping for the bottom left and bottom segments by counting how many times each segment
|
||||
// appears among all of the digits (bottom left appears in 4 digits, bottom in 7 digits).
|
||||
if (patterns.count { remainingSegments[0] in it } == 4) {
|
||||
mapping[remainingSegments[0]] = BOTTOM_LEFT
|
||||
mapping[remainingSegments[1]] = BOTTOM
|
||||
}
|
||||
else {
|
||||
mapping[remainingSegments[1]] = BOTTOM_LEFT
|
||||
mapping[remainingSegments[0]] = BOTTOM
|
||||
}
|
||||
|
||||
return mapping
|
||||
}
|
||||
|
||||
fun deduceOutput(): Int {
|
||||
val mapping = deduceMapping()
|
||||
|
||||
return output.fold(0) { total, digit ->
|
||||
val positions = digit.map(mapping::getValue).toSet()
|
||||
val value = DIGITS.first { it.positions == positions }.value
|
||||
|
||||
(total * 10) + value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue