1
+ package adventofcode2023
2
+
3
+ import java.io.File
4
+
5
+ fun Pair <Int , Int >.add (other : Pair <Int , Int >): Pair <Int , Int > =
6
+ Pair (this .first + other.first, this .second + other.second)
7
+
8
+ object Day10 {
9
+ private const val STARTING_CHAR = ' S'
10
+ // Constants for marking flow direction in the second part
11
+ private const val UPWARDS_DIRECTION = ' U'
12
+ private const val DOWNWARDS_DIRECTION = ' D'
13
+ private const val OTHER_DIRECTION = ' O'
14
+ private const val NOT_LOOP = ' .'
15
+
16
+ private val inputs = File (" resources/adventofcode2023/Day10.txt" ).readLines()
17
+
18
+ // Vertical pipes' first element is the direction that flow is going from so that the pipe is going upwards, the second is downwards
19
+ private val pipes = mapOf (
20
+ ' |' to listOf (Pair (0 , 1 ), Pair (0 , - 1 )),
21
+ ' L' to listOf (Pair (1 , 0 ), Pair (0 , - 1 )),
22
+ ' J' to listOf (Pair (- 1 , 0 ), Pair (0 , - 1 )),
23
+ ' 7' to listOf (Pair (0 , 1 ), Pair (- 1 , 0 )),
24
+ ' F' to listOf (Pair (0 , 1 ), Pair (1 , 0 )),
25
+ ' -' to listOf (Pair (- 1 , 0 ), Pair (1 , 0 )),
26
+ ' .' to emptyList(),
27
+ STARTING_CHAR to listOf (Pair (0 , 1 ), Pair (0 , - 1 ), Pair (1 , 0 ), Pair (- 1 , 0 ))
28
+ )
29
+
30
+ private val verticalPipes = setOf (' |' , ' L' , ' J' , ' 7' , ' F' )
31
+
32
+ private fun getCharAt (position : Pair <Int , Int >): Char =
33
+ inputs[position.second][position.first]
34
+
35
+ private fun getStartPosition (): Pair <Int , Int > {
36
+ for (y in inputs.indices) {
37
+ val x = inputs[y].indexOf(STARTING_CHAR )
38
+ if (x != - 1 ) return Pair (x, y)
39
+ }
40
+ throw NoSuchElementException (" Start position not found" )
41
+ }
42
+
43
+ private fun getFirstPipe (startPosition : Pair <Int , Int >): Pair <Int , Int > {
44
+ pipes[STARTING_CHAR ]?.forEach { direction ->
45
+ val position = startPosition.add(direction)
46
+ if (pipes[getCharAt(position)]!! .any { getCharAt(position.add(it)) == STARTING_CHAR })
47
+ return position
48
+ }
49
+ throw NoSuchElementException (" First pipe not found" )
50
+ }
51
+
52
+ private fun getLoopLength (): Int {
53
+ var last = getStartPosition()
54
+ var current = getFirstPipe(last)
55
+ var counter = 0
56
+
57
+ while (getCharAt(current) != STARTING_CHAR ) {
58
+ val newCurrent = current.add(pipes[getCharAt(current)]!! .first { current.add(it) != last })
59
+ last = current
60
+ current = newCurrent
61
+ counter++
62
+ }
63
+
64
+ return counter
65
+ }
66
+
67
+ // Returns a map with only the loop consisting of upwards/downwards/other markings
68
+ private fun getLoopDirectionsMap (): List <List <Char >> {
69
+ val directionsMap = List (inputs.size) { MutableList (inputs[0 ].length) { NOT_LOOP } }
70
+
71
+ fun updateDirectionsMap (position : Pair <Int , Int >, char : Char ) {
72
+ directionsMap[position.second][position.first] = char
73
+ }
74
+
75
+ var last = getStartPosition()
76
+ var current = getFirstPipe(last)
77
+ var currentChar = getCharAt(current)
78
+
79
+ while (currentChar != STARTING_CHAR ) {
80
+ updateDirectionsMap(
81
+ current,
82
+ if (verticalPipes.contains(currentChar)) {
83
+ if (last == current.add(pipes[currentChar]!! [0 ])) UPWARDS_DIRECTION else DOWNWARDS_DIRECTION
84
+ } else OTHER_DIRECTION
85
+ )
86
+
87
+ val newCurrent = current.add(pipes[currentChar]!! .first { current.add(it) != last })
88
+ last = current
89
+ current = newCurrent
90
+ currentChar = getCharAt(current)
91
+ }
92
+
93
+ when (last) {
94
+ current.add(pipes[STARTING_CHAR ]!! [0 ]) -> updateDirectionsMap(current, UPWARDS_DIRECTION )
95
+ current.add(pipes[STARTING_CHAR ]!! [1 ]) -> updateDirectionsMap(current, DOWNWARDS_DIRECTION )
96
+ else -> updateDirectionsMap(current, OTHER_DIRECTION )
97
+ }
98
+
99
+ return directionsMap
100
+ }
101
+
102
+ private fun getStartEndCountCharacters (directionsMap : List <List <Char >>): List <Char > {
103
+ directionsMap.forEach { line ->
104
+ line.forEach {
105
+ if (it != NOT_LOOP )
106
+ return listOf ( it, if (it == UPWARDS_DIRECTION ) DOWNWARDS_DIRECTION else UPWARDS_DIRECTION )
107
+ }
108
+ }
109
+ throw NoSuchElementException (" Start and end count characters not found" )
110
+ }
111
+
112
+ private fun countTilesEnclosedByLoop (): Int {
113
+ val directionsMap = getLoopDirectionsMap()
114
+ val (startChar, endChar) = getStartEndCountCharacters(directionsMap)
115
+ var counter = 0
116
+
117
+ directionsMap.forEach { line ->
118
+ var shouldCount = false
119
+
120
+ line.forEach { character ->
121
+ if (character == startChar) shouldCount = true
122
+ else if (character == endChar) shouldCount = false
123
+ else if (shouldCount && character == NOT_LOOP ) counter++
124
+ }
125
+ }
126
+
127
+ return counter
128
+ }
129
+
130
+ fun part1 () = println ((getLoopLength() + 1 ) / 2 )
131
+
132
+ fun part2 () = println (countTilesEnclosedByLoop())
133
+ }
134
+
135
+ fun main () {
136
+ Day10 .part1()
137
+ Day10 .part2()
138
+ }
0 commit comments