628 tokens in Kotlin for part 2 by Valentin Slawicek
Download solution
data
class
MapEntry
(
val
source
:
String
,
val
destination
:
String
,
val
sourceStart
:
Long
,
val
destinationStart
:
Long
,
val
rangeLength
:
Long
)
{
val
sourceRange
=
LongRange
(
sourceStart
,
sourceStart
+
rangeLength
-
1
)
}
fun
main
(
)
{
val
mapEntries
=
mutableListOf
<
MapEntry
>
(
)
var
seeds
:
List
<
LongRange
>
=
emptyList
(
)
var
currentMap
=
"
"
to
"
"
generateSequence
(
::
readLine
)
.
forEach
{
line
->
when
{
line
.
startsWith
(
"
s
e
e
d
s
:
"
)
->
{
seeds
=
line
.
substringAfter
(
"
s
e
e
d
s
:
"
)
.
split
(
"
"
)
.
map
{
it
.
toLong
(
)
}
.
chunked
(
2
)
.
map
{
LongRange
(
it
[
0
]
,
it
[
0
]
+
it
[
1
]
-
1
)
}
}
line
.
endsWith
(
"
m
a
p
:
"
)
->
{
currentMap
=
line
.
substringBefore
(
"
-
"
)
to
line
.
substringAfter
(
"
-
t
o
-
"
)
.
substringBefore
(
"
"
)
}
line
.
isEmpty
(
)
->
Unit
else
->
{
val
mapEntryString
=
line
.
split
(
"
"
)
.
map
{
it
.
toLong
(
)
}
mapEntries
+=
MapEntry
(
source
=
currentMap
.
first
,
destination
=
currentMap
.
second
,
destinationStart
=
mapEntryString
[
0
]
,
sourceStart
=
mapEntryString
[
1
]
,
rangeLength
=
mapEntryString
[
2
]
)
}
}
}
fun
LongRange
.
intersect
(
other
:
LongRange
)
:
LongRange
{
return
LongRange
(
maxOf
(
this
.
first
,
other
.
first
)
,
minOf
(
this
.
last
,
other
.
last
)
)
}
fun
getMapEntries
(
source
:
String
,
range
:
LongRange
)
:
Map
<
MapEntry
,
LongRange
>
{
val
relevantMapEntries
=
mapEntries
.
filter
{
it
.
source
==
source
}
.
sortedBy
{
it
.
sourceStart
}
val
targetMapEntries
=
relevantMapEntries
.
toMutableList
(
)
var
lastEnd
=
-
1
L
relevantMapEntries
.
forEach
{
mapEntry
->
if
(
mapEntry
.
sourceStart
!=
lastEnd
+
1
)
{
targetMapEntries
+=
relevantMapEntries
.
first
(
)
.
copy
(
sourceStart
=
lastEnd
+
1
,
destinationStart
=
lastEnd
+
1
,
rangeLength
=
mapEntry
.
sourceStart
-
lastEnd
)
}
lastEnd
=
mapEntry
.
sourceRange
.
last
}
targetMapEntries
+=
relevantMapEntries
.
first
(
)
.
copy
(
sourceStart
=
lastEnd
+
1
,
destinationStart
=
lastEnd
+
1
,
rangeLength
=
Long
.
MAX_VALUE
-
lastEnd
)
return
targetMapEntries
.
filter
{
!
it
.
sourceRange
.
intersect
(
range
)
.
isEmpty
(
)
}
.
associateWith
{
mapEntry
->
val
offset
=
mapEntry
.
destinationStart
-
mapEntry
.
sourceStart
val
sourceIntersectedRange
=
mapEntry
.
sourceRange
.
intersect
(
range
)
LongRange
(
sourceIntersectedRange
.
first
+
offset
,
sourceIntersectedRange
.
last
+
offset
)
}
}
fun
resolve
(
source
:
String
,
range
:
LongRange
)
:
List
<
LongRange
>
{
val
resolvedMapEntries
=
getMapEntries
(
source
,
range
)
return
resolvedMapEntries
.
flatMap
{
(
mapEntry
,
range
)
->
if
(
resolvedMapEntries
.
keys
.
first
(
)
.
destination
==
"
l
o
c
a
t
i
o
n
"
)
{
listOf
(
range
)
}
else
{
resolve
(
mapEntry
.
destination
,
range
)
}
}
}
println
(
seeds
.
minOf
{
seed
->
resolve
(
"
s
e
e
d
"
,
seed
)
.
minBy
{
it
.
first
}
.
first
}
)
}