{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Eric Burden","description":"The latest articles on DEV Community by Eric Burden (@ericwburden).","link":"https:\/\/dev.to\/ericwburden","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F538131%2Fa53a7954-5d99-4783-b473-596864e4e193.jpeg","title":"DEV Community: Eric Burden","link":"https:\/\/dev.to\/ericwburden"},"language":"en","item":[{"title":"Advent of Code 2023 - Day 12","pubDate":"Tue, 12 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-12-3o2","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-12-3o2","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 12 - Hot Springs\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/12\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Oh My Pun!\n<\/h2>\n\n<p>Today we have a relatively simple input for a deceptively difficult problem. Let's start with the input, though. We have multiple lines where each line is split in half (by a single space every time,  thankfully). The left half depicts different spring in different conditions and the right half indicates the sizes of known sizes of damaged groups. Oh, also, \"Hot Springs\". Get it?<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"cm\">\/**\n * This enum represents the different states a spring\n *\n * @property rep The character that represents this enum variant.\n *\/<\/span>\n<span class=\"k\">enum<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">rep<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Char<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nc\">DAMAGED<\/span><span class=\"p\">(<\/span><span class=\"sc\">'#'<\/span><span class=\"p\">),<\/span> <span class=\"nc\">OPERATIONAL<\/span><span class=\"p\">(<\/span><span class=\"sc\">'.'<\/span><span class=\"p\">),<\/span> <span class=\"nc\">UNKNOWN<\/span><span class=\"p\">(<\/span><span class=\"sc\">'?'<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromChar<\/span><span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Char<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Condition<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sc\">'#'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">DAMAGED<\/span>\n                <span class=\"sc\">'.'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">OPERATIONAL<\/span>\n                <span class=\"sc\">'?'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">UNKNOWN<\/span>\n                <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Cannot represent '$char' as a [Condition]!\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents the condition record of a single row of springs.\n * \n * @property springs A list of the conditions of the springs.\n * @property damagedGroups A list of known sizes of damaged groups.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">ConditionRecord<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">springs<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Condition<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">damagedGroups<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ Parse the input lines!<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">str<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">ConditionRecord<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">conditionStr<\/span><span class=\"p\">,<\/span> <span class=\"py\">groupStr<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">str<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\" \"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">conditions<\/span> <span class=\"p\">=<\/span> <span class=\"n\">conditionStr<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">Condition<\/span><span class=\"o\">::<\/span><span class=\"n\">fromChar<\/span><span class=\"p\">)<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">groups<\/span> <span class=\"p\">=<\/span> <span class=\"n\">groupStr<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\",\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">ConditionRecord<\/span><span class=\"p\">(<\/span><span class=\"n\">conditions<\/span><span class=\"p\">,<\/span> <span class=\"n\">groups<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day12<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">ConditionRecord<\/span><span class=\"o\">::<\/span><span class=\"n\">fromString<\/span><span class=\"p\">)<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Not too much to say about parsing today. LOTS to say about solving the puzzle, though.<\/p>\n\n<h2>\n  \n  \n  Part One - Novel Algorithm\n<\/h2>\n\n<p>In part one, our goal is to figure out which springs are damaged,<br>\narmed with the knowledge of which springs <em>might<\/em> be damaged and how large all the damaged groups are. My first instinct was to try a depth-first search over the springs, and honestly, it might have taken that approach less time to run than it took me to type through my explanation for the dynamic programming approach I ended up taking. See, I had an inkling that I was dealing with overlapping sub-problems, and I was right! Now, on to the lengthy explanation!<\/p>\n<h3>\n  \n  \n  Example 1: .???.### 1,1,3\n<\/h3>\n\n<p>Note, my examples trim all the '.' from the original puzzle input and prepend one '.'. I'm not sure this is 100% necessary, but it made it easier for me to think through. In this example, we have three groups of damaged springs (of lengths 1, 1, and 3) and 8 total springs, of which 2 are operational ('.'), 3 are damaged ('#'), and the remaining 3 are unknown ('?'). The essence of the DP approach here is to repeatedly calculate the number of possible combinations of springs under sets of increasing constraints, which are, in order:<\/p>\n\n<ul>\n<li>no damaged springs<\/li>\n<li>one damaged group of <code>Damaged Groups<\/code>[0] length<\/li>\n<li>the first <em>and<\/em> second damaged groups<\/li>\n<li>all three damaged groups<\/li>\n<\/ul>\n\n<p>For this example, I'll walk through them one constraint at a time.<\/p>\n<h4>\n  \n  \n  First Constraint: No Damaged Groups\n<\/h4>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code> Damaged Groups: []\n Starting Conditions  :    [., ?, ?, ?, ., #, #, #]\n Possible Combinations: [1, 1, 1, 1, 1, 1, 0, 0, 0]\n                        \/   |  |  |  |  |   \\\n                       a    b  c  d  e  f    g\n<\/code><\/pre>\n\n<\/div>\n\n\n<p>Note, the list of possible combinations is one longer than the list of springs, and is offset from the spring list by -1 as we walk through. This means that the first value in the list represents the number of possible ways to construct an empty list of springs with the given groups (in this case, none). Conveniently, there is one way to construct an empty list, so the value at (a) is 1.<\/p>\n\n<p>The second value, (b) is also 1, because it is possible to construct a row with one operational spring when there are no damaged springs The values at (c-f) are similarly 1, because there is only one way a spring can be constructed of '.???.' springs with no damage, which is '.....'.<\/p>\n\n<p>On the other hand, (g) must be 0, because it is not possible to construct a row with one damaged section if there are no damaged springs allowed. This carries forward to the rest of the list, since '.....#' and '.....#?' are equally impossible.<\/p>\n<h4>\n  \n  \n  Second Constraint: One group of one damaged section\n<\/h4>\n\n<p>In this second round, we are required to construct a row with one group of damaged springs consisting of only a single spring. It is important here to remember that each group of damaged springs must be separated by at least one operational section.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code> Groups: [1]\n Starting Conditions  :    [., ?, ?, ?, ., #, #, #]\n Possible Combinations: [1, 1, 1, 1, 1, 1, 0, 0, 0] with no groups\n Possible Combinations: [0, 0, 1, 2, 3, 3, 1, 0, 0] add group of 1\n                        \/  \/   |  |  |  |  |   \\\n                       a  b    c  d  e  f  g    h\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>With a group length of 1, the pattern is readily recognized as<br>\n<code>current[i] = current[i - 1] + (previous[i - 2] ?: 0)<\/code>. I'm using the <code>?:<\/code> notation here to indicate 'zero if index out of bounds'.<\/p>\n\n<p>We see that (a, b) are zero, which makes sense because you can't construct a row with a 1-wide defect from '' or '.'. '.?' (c) <em>could<\/em> be '.#', so there's one possible configuration at this point that meets our criteria. '.??' (d) could be '.#.' or '..#' and '.???' (e) could be '.#..', '..#.', or '...#'. (f) is the same as (e) with an extra operational section at the end.<\/p>\n\n<p>(g) and (h) break the pattern, though because '#' is a damaged spring, which constrains our options for assigning the damaged group. At (g), there's only one way to assign a 1-wide group of damage, and at (h) there's more damage than we can accommodate. Notably, the value at (h) would be the same if the springs were '.???.#?' as well. This means we need to keep up with the width of the damaged groups up to our current position and determine when we can't carry over combinations that were available up to the current point. This would be when either the current group size is larger than the run of possibly damaged springs <em>or<\/em> the spring just prior to where the group would start is also DAMAGED (which would make the actual damaged group too large). The logic goes like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>      damage can fit = group size &lt;= run of DAMAGED and UNKNOWN\n                   AND spring just prior to group start point is not DAMAGED\n      current[i] = if current section is not DAMAGED and damage can fit:\n          (A) current[i - 1] + (previous[i - 2] ?: 0)\n      else if current section is DAMAGED and damage can fit:\n          (B) (previous[i - 2] ?: 0)\n      else if current section is not DAMAGED:\n          (C) current[i - 1]\n      else:\n          (D) 0\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That final <code>else<\/code> applies if the current spring <em>is<\/em> DAMAGED and the group size is larger than the current run of DAMAGED and UNKNOWN springs.<\/p>\n\n<h4>\n  \n  \n  Third Constraint: Two groups of 1 damaged spring each\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code> Groups: [1, 1]\n Starting Conditions  :    [., ?, ?, ?, ., #, #, #]\n Possible Combinations: [1, 1, 1, 1, 1, 1, 0, 0, 0] with no groups\n Possible Combinations: [0, 0, 1, 2, 3, 3, 1, 0, 0] add group of 1\n Possible Combinations: [0, 0, 0, 0, 1, 1, 3, 0, 0] add group of 1\n                              \/   |  |  |  |   \\\n                             a    b  c  d  e    f\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here, we see that (a) is behaving as expected. At (a), the run of possible damaged springs is 1 and the spring there is not damaged, so branch (A) of our logic applies, yielding 0. The same is true for (b-d). Logically, we can see that there's only one way to distribute two 1-wide damage regions into '.???.', which is '.#.#.'. Recall that the damaged groups must be separated by an operational spring.<\/p>\n\n<p>(e) is interesting because the spring there <em>is<\/em> damaged, which<br>\nties up one of the damage groups and, again logically, we see that this means that the <em>other<\/em> group of damaged springs can be distributed three different ways, as '.#...#', '..#..#', or '...#.#'. Because the section at (e) is damaged and the current group can fit in the run, this uses branch (B) of our logic above.<\/p>\n\n<p>(f) is a spring that <em>is<\/em> DAMAGED and the spring just prior to the<br>\ngroup start area is also DAMAGED (which would make a two-wide DAMAGED region), so branch (D) applies.<\/p>\n<h4>\n  \n  \n  Third Constraint: Two groups of 1 and one group of 3 DAMAGED springs\n<\/h4>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code> Groups: [1, 1, 3]\n Starting Conditions  :    [., ?, ?, ?, ., #, #, #]\n Possible Combinations: [1, 1, 1, 1, 1, 1, 0, 0, 0] with no groups\n Possible Combinations: [0, 0, 1, 2, 3, 3, 1, 0, 0] add group of 1\n Possible Combinations: [0, 0, 0, 0, 1, 1, 3, 0, 0] add group of 1\n Possible Combinations: [0, 0, 0, 0, 0, 0, 0, 0, 1] add group of 3\n                                    \/         |   \\\n                                   a          b    c\n<\/code><\/pre>\n\n<\/div>\n\n\n<p>Our options are much more limited now, needing to add a 3-wide DAMAGED group on top of the two 1-wide groups. This means that when we reach section (a), we'll only have space for either the two 1-wide groups or or the one 3-wide group, but not both. At point (a), considering the three-wide group, the current spring is <em>not<\/em> DAMAGED and we do have enough room to insert the group, so we take branch (B) of our logic.<\/p>\n\n<p>At section (b), the spring <em>is<\/em> damaged and we do <em>not<\/em> have space to insert our 3-wide DAMAGED group, so we take branch (D). Finally, at section (c), the section <em>is<\/em> DAMAGED and we <em>do<\/em> have space for our 3-wide group, so we take branch (B). Except, now branch (B) would yield a result of 0, but we can clearly see that there's one way to arrange all three DAMAGED groups: '.#.#.###'. If we examine the logic of branch (B), we can see that with the first two groups, we were selecting the number of possible combinations containing the previous groups at the point <em>before<\/em> we were inserting the current group. Making a slight modification yields the final algorithm:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>      damage can fit = group size &lt;= run of DAMAGED and UNKNOWN\n                   AND spring just prior to group start point is not DAMAGED\n      current[i] = if current section is not DAMAGED and damage can fit:\n          (A) current[i - 1] + (previous[i - (group size + 1)] ?: 0)\n      else if current section is DAMAGED and damage can fit:\n          (B) (previous[i - (group size + 1)] ?: 0)\n      else if current section is not DAMAGED:\n          (C) current[i - 1]\n      else:\n          (D) 0\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The code below will follow this logic, with some minor indexing tweaks to account for the fact that we can't <em>really<\/em> shift the row of springs representation over by one index as we did when visualizing these examples.<\/p>\n\n<p>I encourage you to apply the logic above to this second example of a row of springs from today's example input if you're not 100% clear on how it works yet.<\/p>\n\n<h3>\n  \n  \n  Example 2: .?###???????? 3,2,1\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code> Damaged Groups: [3, 2, 1]\n Starting Conditions  :    [., ?, #, #, #, ?, ?, ?, ?, ?, ?, ?, ?]\n Possible Combinations: [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]  with no groups\n Possible Combinations: [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]  add group of 3\n Possible Combinations: [0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6]  add group of 2\n Possible Combinations: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 6, 10] add group of 1\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And now, let's turn that logic into actual code!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ enum class Condition(val rep: Char) { ... }<\/span>\n\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">ConditionRecord<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">springs<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Condition<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">damagedGroups<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"k\">fun<\/span> <span class=\"nf\">countAllPossibleConditions<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ The list of conditions should start with _one_ OPERATIONAL<\/span>\n        <span class=\"c1\">\/\/ spring in order to support the algorithm for counting possible<\/span>\n        <span class=\"c1\">\/\/ combinations of conditions. Excess OPERATIONAL springs at the<\/span>\n        <span class=\"c1\">\/\/ beginning are removed.<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">springs<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">mutableListOf<\/span><span class=\"p\">(<\/span><span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">OPERATIONAL<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">springs<\/span><span class=\"p\">.<\/span><span class=\"nf\">addAll<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"n\">springs<\/span><span class=\"p\">.<\/span><span class=\"nf\">dropWhile<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">OPERATIONAL<\/span> <span class=\"p\">})<\/span>\n\n        <span class=\"c1\">\/\/ Note, the first value in this list does not correspond to the first<\/span>\n        <span class=\"c1\">\/\/ section, but to a hypothetical 'empty' section preceding the list<\/span>\n        <span class=\"c1\">\/\/ of springs. This means there is exactly 1 possible<\/span>\n        <span class=\"c1\">\/\/ configuration for an empty list of springs.<\/span>\n        <span class=\"kd\">var<\/span> <span class=\"py\">possibleCombinations<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"n\">springs<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"mi\">1L<\/span> <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ Starting with the first DAMAGED section all the way to the end,<\/span>\n        <span class=\"c1\">\/\/ set the number of possible combinations to zero, because there is<\/span>\n        <span class=\"c1\">\/\/ no way to make a spring with damaged springs if there is no<\/span>\n        <span class=\"c1\">\/\/ damage (our starting constraint).<\/span>\n        <span class=\"c1\">\/\/<\/span>\n        <span class=\"c1\">\/\/      Starting Conditions  :    [., ?, ?, ?, ., #, #, #]<\/span>\n        <span class=\"c1\">\/\/      Possible Combinations: [1, 1, 1, 1, 1, 1, 0, 0, 0]<\/span>\n        <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">idx<\/span><span class=\"p\">,<\/span> <span class=\"n\">_<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">springs<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">()<\/span>\n            <span class=\"p\">.<\/span><span class=\"nf\">dropWhile<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">c<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">c<\/span> <span class=\"p\">!=<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">DAMAGED<\/span> <span class=\"p\">})<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">possibleCombinations<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n        <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ For each group size of damaged springs, we successively build upon<\/span>\n        <span class=\"c1\">\/\/ the previous set of possible constraints, determining how many<\/span>\n        <span class=\"c1\">\/\/ combinations are possible after adding each group as a constraint.<\/span>\n        <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">checkedGroupSize<\/span> <span class=\"k\">in<\/span> <span class=\"n\">damagedGroups<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ Each new 'layer' of possibilities starts out empty.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">nextPossibleCombinations<\/span> <span class=\"p\">=<\/span>\n                <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"n\">springs<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"mi\">0L<\/span> <span class=\"p\">}<\/span>\n            <span class=\"kd\">var<\/span> <span class=\"py\">possiblyDamagedRunSize<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n\n            <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">idx<\/span><span class=\"p\">,<\/span> <span class=\"n\">condition<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">springs<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">().<\/span><span class=\"nf\">drop<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n                <span class=\"c1\">\/\/ Reset the 'group' of possibly DAMAGED springs to consider if<\/span>\n                <span class=\"c1\">\/\/ we encounter an OPERATIONAL section.<\/span>\n                <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">condition<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">OPERATIONAL<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"n\">possiblyDamagedRunSize<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n                <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"n\">possiblyDamagedRunSize<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span>\n                <span class=\"p\">}<\/span>\n\n                <span class=\"c1\">\/\/ Here is where we implement our logic described exhaustively<\/span>\n                <span class=\"c1\">\/\/ above:<\/span>\n\n                <span class=\"c1\">\/\/ damage can fit = group size &lt;= run of DAMAGED and UNKNOWN<\/span>\n                <span class=\"c1\">\/\/              AND section just prior to group insertion point is not DAMAGED<\/span>\n                <span class=\"c1\">\/\/ current[i] = if current section is not DAMAGED and damage can fit:<\/span>\n                <span class=\"c1\">\/\/     (A) current[i - 1] + (previous[i - (group size + 1)] ?: 0)<\/span>\n                <span class=\"c1\">\/\/ else if current section is DAMAGED and damage can fit:<\/span>\n                <span class=\"c1\">\/\/     (B) (previous[i - (group size + 1)] ?: 0)<\/span>\n                <span class=\"c1\">\/\/ else if current section is not DAMAGED:<\/span>\n                <span class=\"c1\">\/\/     (C) current[i - 1]<\/span>\n                <span class=\"c1\">\/\/ else:<\/span>\n                <span class=\"c1\">\/\/     (D) 0<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">groupCanFit<\/span> <span class=\"p\">=<\/span> <span class=\"n\">possiblyDamagedRunSize<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"n\">checkedGroupSize<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">precedingIdx<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">idx<\/span> <span class=\"p\">-<\/span> <span class=\"n\">checkedGroupSize<\/span><span class=\"p\">).<\/span><span class=\"nf\">coerceAtLeast<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">notContiguousDamage<\/span> <span class=\"p\">=<\/span>\n                    <span class=\"n\">springs<\/span><span class=\"p\">[<\/span><span class=\"n\">precedingIdx<\/span><span class=\"p\">]<\/span> <span class=\"p\">!=<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">DAMAGED<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">isNotDamaged<\/span> <span class=\"p\">=<\/span> <span class=\"n\">condition<\/span> <span class=\"p\">!=<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">DAMAGED<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">damageCanFit<\/span> <span class=\"p\">=<\/span> <span class=\"n\">groupCanFit<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"n\">notContiguousDamage<\/span>\n                <span class=\"n\">nextPossibleCombinations<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span>\n                    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">isNotDamaged<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"n\">damageCanFit<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                        <span class=\"n\">nextPossibleCombinations<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span> <span class=\"p\">+<\/span> <span class=\"n\">possibleCombinations<\/span><span class=\"p\">[<\/span><span class=\"n\">precedingIdx<\/span><span class=\"p\">]<\/span>\n                    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">condition<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">DAMAGED<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"n\">damageCanFit<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                        <span class=\"n\">possibleCombinations<\/span><span class=\"p\">[<\/span><span class=\"n\">precedingIdx<\/span><span class=\"p\">]<\/span>\n                    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">isNotDamaged<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                        <span class=\"n\">nextPossibleCombinations<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span>\n                    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n                        <span class=\"mi\">0L<\/span>\n                    <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"c1\">\/\/ Update the 'current' layer<\/span>\n            <span class=\"n\">possibleCombinations<\/span> <span class=\"p\">=<\/span> <span class=\"n\">nextPossibleCombinations<\/span>\n        <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ Update the number of possible combinations with the result of<\/span>\n        <span class=\"c1\">\/\/ determining possible combinations with the current group<\/span>\n        <span class=\"c1\">\/\/ of DAMAGED springs.<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">possibleCombinations<\/span><span class=\"p\">.<\/span><span class=\"nf\">last<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day12<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">countAllPossibleConditions<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Yes, I <em>know<\/em> that's a lot of comments in addition to the <em>book<\/em> that was this section. I told you it took a long time to write.<\/p>\n\n<h2>\n  \n  \n  Part Two - The Spring Has Sprung\n<\/h2>\n\n<p>I have <em>excellent<\/em> news! We're back to misunderstanding documentation! And, thankfully, it was just the <em>text<\/em> and not the <em>method<\/em>. Both the springs and the lists of damaged groups are 5 times longer than we thought. No big deal!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ enum class Condition(val rep: Char) { ... }<\/span>\n\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">ConditionRecord<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">springs<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Condition<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">damagedGroups<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"c1\">\/\/ fun countAllPossibleConditions(): Long { ... }<\/span>\n\n    <span class=\"k\">fun<\/span> <span class=\"nf\">unfold<\/span><span class=\"p\">():<\/span> <span class=\"nc\">ConditionRecord<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">conditions<\/span> <span class=\"p\">=<\/span>\n            <span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span><span class=\"n\">springs<\/span> <span class=\"p\">+<\/span> <span class=\"nc\">Condition<\/span><span class=\"p\">.<\/span><span class=\"nc\">UNKNOWN<\/span><span class=\"p\">).<\/span><span class=\"nf\">repeating<\/span><span class=\"p\">().<\/span><span class=\"nf\">asSequence<\/span><span class=\"p\">()<\/span>\n                <span class=\"p\">.<\/span><span class=\"nf\">take<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">).<\/span><span class=\"nf\">flatMap<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">toMutableList<\/span><span class=\"p\">().<\/span><span class=\"nf\">dropLast<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">damagedGroups<\/span> <span class=\"p\">=<\/span>\n            <span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span><span class=\"n\">damagedGroups<\/span><span class=\"p\">).<\/span><span class=\"nf\">repeating<\/span><span class=\"p\">().<\/span><span class=\"nf\">asSequence<\/span><span class=\"p\">().<\/span><span class=\"nf\">take<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">)<\/span>\n                <span class=\"p\">.<\/span><span class=\"nf\">flatMap<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">toList<\/span><span class=\"p\">()<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">ConditionRecord<\/span><span class=\"p\">(<\/span><span class=\"n\">conditions<\/span><span class=\"p\">,<\/span> <span class=\"n\">damagedGroups<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day12<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun solvePart1(): Long = ...<\/span>\n\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">unfold<\/span><span class=\"p\">().<\/span><span class=\"nf\">countAllPossibleConditions<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Nah, I don't have much to say about this one. Used up all my words today.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Dynamic programming is hard! And, for me at least, it's harder to <em>explain<\/em> than it is to do. Today was certainly good practice in both regards, though. I don't think I used any new Kotlin-specific goodies, which is probably a good thing. <\/p>\n\n"},{"title":"Advent of Code 2023 - Day 11","pubDate":"Mon, 11 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-11-1di6","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-11-1di6","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 11 - Cosmic Expansion\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/11\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Galaxy Brain\n<\/h2>\n\n<p>Back to 2D maps, are we? Well, I came prepared today. I added another input pre-processing function to read in a 2D grid like this as a <code>List&lt;List&lt;Char&gt;&gt;<\/code>. It\u2019s not much, but it\u2019s a nice convenience to have on the front-end. After that, I think all I\u2019ll need is a list of where the galaxies are and lists of which rows\/columns from the input I need to expand. Let\u2019s get that done.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"cm\">\/**\n * This class represents a position on our map of galaxies.\n *\n * @property row The row of this position.\n * @property col The col of this position.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">row<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">col<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Calculate the Manhattan distance between two Positions\n     *\n     * @param other The other position to calculate distance to.\n     * @return The Manhattan distance to the `other` position.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">manhattanDistanceTo<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nf\">abs<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">-<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"nf\">abs<\/span><span class=\"p\">(<\/span><span class=\"n\">col<\/span> <span class=\"p\">-<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents the map of galaxies from the input\n *\n * @property galaxies A list of [Position]s of galaxies on the map.\n * @property expandedRows A list of the row indices in the map with no galaxies.\n * @property expandedCols A list of the column indices in the map with no \n * galaxies.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">GalaxyMap<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">galaxies<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Position<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">expandedRows<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">expandedCols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"cm\">\/**\n         * Parse the input file into a [GalaxyMap]\n         *\n         * @param input The grid of characters from the input file.\n         * @return A [GalaxyMap] parsed from the input.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromInput<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Char<\/span><span class=\"p\">&gt;&gt;):<\/span> <span class=\"nc\">GalaxyMap<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ Every '#' is a galaxy. Everything else is just empty space.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">galaxies<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">()<\/span>\n                <span class=\"p\">.<\/span><span class=\"nf\">flatMap<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">rowIdx<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n                    <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">().<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">colIdx<\/span><span class=\"p\">,<\/span> <span class=\"n\">char<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n                        <span class=\"n\">char<\/span> <span class=\"n\">to<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">(<\/span>\n                            <span class=\"n\">rowIdx<\/span><span class=\"p\">,<\/span>\n                            <span class=\"n\">colIdx<\/span>\n                        <span class=\"p\">)<\/span>\n                    <span class=\"p\">}<\/span>\n                <span class=\"p\">}<\/span>\n                <span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">,<\/span> <span class=\"n\">_<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">char<\/span> <span class=\"p\">==<\/span> <span class=\"sc\">'#'<\/span> <span class=\"p\">}<\/span>\n                <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">position<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">position<\/span> <span class=\"p\">}<\/span>\n\n            <span class=\"c1\">\/\/ It seemed most straightforward to start with a set of all row<\/span>\n            <span class=\"c1\">\/\/ and column indices, then remove any row or column with a galaxy<\/span>\n            <span class=\"c1\">\/\/ on it.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">expandedRows<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"n\">indices<\/span><span class=\"p\">.<\/span><span class=\"nf\">toMutableSet<\/span><span class=\"p\">()<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">expandedCols<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">().<\/span><span class=\"n\">indices<\/span><span class=\"p\">.<\/span><span class=\"nf\">toMutableSet<\/span><span class=\"p\">()<\/span>\n            <span class=\"n\">galaxies<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span> <span class=\"p\">{<\/span> <span class=\"n\">position<\/span> <span class=\"p\">-&gt;<\/span>\n                <span class=\"n\">expandedRows<\/span><span class=\"p\">.<\/span><span class=\"nf\">remove<\/span><span class=\"p\">(<\/span><span class=\"n\">position<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span><span class=\"p\">)<\/span>\n                <span class=\"n\">expandedCols<\/span><span class=\"p\">.<\/span><span class=\"nf\">remove<\/span><span class=\"p\">(<\/span><span class=\"n\">position<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"c1\">\/\/ I'm sorting the expanded rows and columns lists here so that I<\/span>\n            <span class=\"c1\">\/\/ can binary search them later for _max velocity_.<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">GalaxyMap<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">galaxies<\/span><span class=\"p\">,<\/span>\n                <span class=\"n\">expandedRows<\/span><span class=\"p\">.<\/span><span class=\"nf\">toList<\/span><span class=\"p\">().<\/span><span class=\"nf\">sorted<\/span><span class=\"p\">(),<\/span>\n                <span class=\"n\">expandedCols<\/span><span class=\"p\">.<\/span><span class=\"nf\">toList<\/span><span class=\"p\">().<\/span><span class=\"nf\">sorted<\/span><span class=\"p\">()<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day11<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Char<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ Let's map the galaxy!<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">GalaxyMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromInput<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That wasn\u2019t too painful. I feel like I\u2019m getting more fluent with the available iterator chaining functions from the standard library, which is a nice benefit. Now, let\u2019s map this galaxy for real!<\/p>\n\n<h2>\n  \n  \n  Part One - The One That Got Away\n<\/h2>\n\n<p>So, I guess we decided we <em>didn\u2019t<\/em> have time to go track that random robot critter down and\u2026 I don\u2019t know, interrogate it about where to find parts? Probably a good call to just move on, but I\u2019m keeping my eye out for that thing to randomly reappear in another puzzle. Probably for us to play dice with or some such. As for the task at hand, it looks like if we can help this elvish astronomer calculate some astronomical distances, he\u2019ll lead us to the hot springs. Sounds like a real winner to me!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"k\">import<\/span> <span class=\"nn\">kotlin.math.abs<\/span>\n\n<span class=\"c1\">\/\/ data class Position(val row: Int, val col: Int) { ... }<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">GalaxyMap<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">galaxies<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Position<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">expandedRows<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">expandedCols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"cm\">\/**\n     * Count the number of expanded rows between two galaxies\n     *\n     * Because the expanded rows are sorted, we can binary search to determine\n     * how many expanded rows are between two rows that we know aren't in the\n     * list (because they have galaxies on them).\n     *\n     * @param galaxyA The first galaxy in the pair.\n     * @param galaxyB the other galaxy in the pair.\n     * @return The number of expanded rows between the pair of galaxies.\n     *\/<\/span>\n    <span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nf\">expandedRowsBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span>\n        <span class=\"nf\">abs<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">expandedRows<\/span><span class=\"p\">.<\/span><span class=\"nf\">binarySearch<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"p\">-<\/span> <span class=\"n\">expandedRows<\/span><span class=\"p\">.<\/span><span class=\"nf\">binarySearch<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">galaxyB<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n\n    <span class=\"cm\">\/**\n     * Count the number of expanded columns between two galaxies\n     *\n     * Because the expanded columns are sorted, we can binary search to determine\n     * how many expanded columns are between two columns that we know aren't in\n     * the list (because they have galaxies on them).\n     *\n     * @param galaxyA The first galaxy in the pair.\n     * @param galaxyB the other galaxy in the pair.\n     * @return The number of expanded columns between the pair of galaxies.\n     *\/<\/span>\n    <span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nf\">expandedColsBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span>\n        <span class=\"nf\">abs<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">expandedCols<\/span><span class=\"p\">.<\/span><span class=\"nf\">binarySearch<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span><span class=\"p\">)<\/span> <span class=\"p\">-<\/span> <span class=\"n\">expandedCols<\/span><span class=\"p\">.<\/span><span class=\"nf\">binarySearch<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">galaxyB<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n\n    <span class=\"cm\">\/**\n     * Calculate the real distance between two galaxies\n     *\n     * The distance between two galaxies consists of their Manhattan distance\n     * on the map, plus the expansion of the universe that occurred during\n     * the time it took the light to travel to our observation point. This\n     * is accomplished by doubling the \"width\" of rows and columns without\n     * any galaxies on them.\n     *\n     * @param galaxyA The first galaxy.\n     * @param galaxyB The second galaxy.\n     * @return The distance between the two galaxies.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">distanceBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">observedDistance<\/span> <span class=\"p\">=<\/span> <span class=\"n\">galaxyA<\/span><span class=\"p\">.<\/span><span class=\"nf\">manhattanDistanceTo<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">rowExpansions<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">expandedRowsBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">colExpansions<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">expandedColsBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\">\/\/ Because each expanded row\/columns counts as 2, and because we already<\/span>\n        <span class=\"c1\">\/\/ accounted for each of them once in the `observedDistance`, we just<\/span>\n        <span class=\"c1\">\/\/ add the \"extra width\" of 1 for each expanded row\/column to our final<\/span>\n        <span class=\"c1\">\/\/ distance.<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">observedDistance<\/span> <span class=\"p\">+<\/span> <span class=\"n\">rowExpansions<\/span> <span class=\"p\">+<\/span> <span class=\"n\">colExpansions<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Returns a sequence of non-repeating pairs of elements in a list\n *\n * This extension function defines a sequence of pairs of elements from the\n * original list such that all unique pairs are generated. For this purpose,\n * the pairs (A, B) and (B, A) are considered equivalent.\n *\n * @return A sequence of non-repeating pairs of elements in [List&lt;T&gt;].\n *\/<\/span>\n<span class=\"k\">fun<\/span> <span class=\"p\">&lt;<\/span><span class=\"nc\">T<\/span><span class=\"p\">&gt;<\/span> <span class=\"nf\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">T<\/span><span class=\"p\">&gt;.<\/span><span class=\"nf\">pairs<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Sequence<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">T<\/span><span class=\"p\">,<\/span> <span class=\"nc\">T<\/span><span class=\"p\">&gt;&gt;<\/span> <span class=\"p\">=<\/span>\n    <span class=\"nf\">sequence<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">i<\/span> <span class=\"k\">in<\/span> <span class=\"n\">indices<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">j<\/span> <span class=\"k\">in<\/span> <span class=\"n\">i<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">until<\/span> <span class=\"n\">size<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">yield<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"nd\">@pairs<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span> <span class=\"n\">to<\/span> <span class=\"k\">this<\/span><span class=\"nd\">@pairs<\/span><span class=\"p\">[<\/span><span class=\"n\">j<\/span><span class=\"p\">])<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day11<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Char<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part one, the galaxy has a static expansion. Since the \"shortest path\"<\/span>\n    <span class=\"c1\">\/\/ through empty space is just the distance, calculate the distance between<\/span>\n    <span class=\"c1\">\/\/ all unique pairs of galaxies and return the sum.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"n\">galaxies<\/span><span class=\"p\">.<\/span><span class=\"nf\">pairs<\/span><span class=\"p\">().<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n            <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">distanceBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>I\u2019m not going to lie, I\u2019m a <em>big<\/em> fan of that extension function on a <code>List&lt;T&gt;<\/code>that returns a sequence over that list. I feel like that\u2019s going to come in_handy_ in future days, so I\u2019m pretty excited to have found it today. Oddly, or at least, oddly to me, I tried to write an iterator at first, but found I needed to call <code>.toSequence()<\/code> on the iterator to include it in a chain of method calls. I felt like I should have been able to use it without, but maybe I just misunderstood the difference between iterators and sequences in Kotlin. More to learn, I guess, which is a good reason to keep going!<\/p>\n\n<h2>\n  \n  \n  Part Two - The Final Frontier\n<\/h2>\n\n<p>Of <em>course<\/em> the actual input evaluation is different that we originally thought. At least <em>this<\/em> time, it\u2019s not because we read the instructions too quickly or failed to look at the back or some other nonsense, it was someone <em>else\u2019s<\/em> mistake! Sweet vindication! Thankfully, we have everything we need from part one to adapt to this relatively minor change.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"k\">import<\/span> <span class=\"nn\">kotlin.math.abs<\/span>\n\n<span class=\"c1\">\/\/ data class Position(val row: Int, val col: Int) { ... }<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">GalaxyMap<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">galaxies<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Position<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">expandedRows<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">expandedCols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"c1\">\/\/ private fun expandedRowsBetween(<\/span>\n    <span class=\"c1\">\/\/ galaxyA: Position, <\/span>\n    <span class=\"c1\">\/\/ galaxyB: Position<\/span>\n    <span class=\"c1\">\/\/ ): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ private fun expandedColsBetween(<\/span>\n    <span class=\"c1\">\/\/ galaxyA: Position, <\/span>\n    <span class=\"c1\">\/\/ galaxyB: Position<\/span>\n    <span class=\"c1\">\/\/ ): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun distanceBetween(galaxyA: Position, galaxyB: Position): Int { ... }<\/span>\n\n    <span class=\"cm\">\/**\n     * Calculate the real distance between two galaxies with variable expansion\n     *\n     * The distance between two galaxies consists of their Manhattan distance\n     * on the map, plus the expansion of the universe that occurred during\n     * the time it took the light to travel to our observation point. For part\n     * two, the examples are for smaller levels of expansion than the expected\n     * answer, so this function accepts the multiple by which the empty rows\n     * and columns have expanded as a parameter.\n     *\n     * @param galaxyA The first galaxy.\n     * @param galaxyB The second galaxy.\n     * @param expansionFactor The multiple by which the empty rows\/columns have\n     * expanded.\n     * @return The distance between the two galaxies.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">enhancedDistanceBetween<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">galaxyA<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">galaxyB<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Position<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">expansionFactor<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span>\n    <span class=\"p\">):<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">observedDistance<\/span> <span class=\"p\">=<\/span> <span class=\"n\">galaxyA<\/span><span class=\"p\">.<\/span><span class=\"nf\">manhattanDistanceTo<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\">\/\/ We multiply the number of rows\/columns by the expansionFactor - 1<\/span>\n        <span class=\"c1\">\/\/ because, once again, the one-wide row\/column is already accounted<\/span>\n        <span class=\"c1\">\/\/ for in the `observedDistance`.<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">rowExpansions<\/span> <span class=\"p\">=<\/span>\n            <span class=\"nf\">expandedRowsBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span> <span class=\"p\">*<\/span> <span class=\"p\">(<\/span><span class=\"n\">expansionFactor<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">colExpansions<\/span> <span class=\"p\">=<\/span>\n            <span class=\"nf\">expandedColsBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span> <span class=\"p\">*<\/span> <span class=\"p\">(<\/span><span class=\"n\">expansionFactor<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">observedDistance<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLong<\/span><span class=\"p\">()<\/span> <span class=\"p\">+<\/span> <span class=\"n\">rowExpansions<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLong<\/span><span class=\"p\">()<\/span> <span class=\"p\">+<\/span> <span class=\"n\">colExpansions<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLong<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ fun &lt;T&gt; List&lt;T&gt;.pairs(): Sequence&lt;Pair&lt;T, T&gt;&gt; = ...<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day11<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Char<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part two, we need to accommodate a variable expansion factor if we want<\/span>\n    <span class=\"c1\">\/\/ to use the same function for testing the example and real inputs (we do<\/span>\n    <span class=\"c1\">\/\/ want to do that, by the way).<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">(<\/span><span class=\"n\">expansionFactor<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"n\">galaxies<\/span><span class=\"p\">.<\/span><span class=\"nf\">pairs<\/span><span class=\"p\">().<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n            <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">enhancedDistanceBetween<\/span><span class=\"p\">(<\/span><span class=\"n\">galaxyA<\/span><span class=\"p\">,<\/span> <span class=\"n\">galaxyB<\/span><span class=\"p\">,<\/span> <span class=\"n\">expansionFactor<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This was an interesting part two in that we didn\u2019t actually get an example answer with the real expansion factor. Thankfully, it was straightforward enough to include it as a parameter and calculate the example results and our answer with the same function.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Today\u2019s puzzle was interesting. Don\u2019t think I didn\u2019t catch all those \u201cshortest distance\u201d references trying to trick me into writing a breadth-first search (or, God forbid, Dijkstra\u2019s!) to find the distance between stars. To be honest, the line in one of the partial examples is what really gave it away. Also, sequences are awesome! Had fun, learned some more Kotlin. What more could you ask for?<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 10","pubDate":"Sun, 10 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-10-2m38","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-10-2m38","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 10 - Pipe Maze\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/10\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Loop the Loop\n<\/h2>\n\n<p>Today\u2019s puzzle had a serious amount of parsing, which is really more along the lines of what I\u2019d expect from a weekend at this point in the calendar. On the plus side, it made sense to <em>me<\/em> to use a builder pattern for building up our input one step at a time today.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"cm\">\/**\n * This class represents a location in a grid of PipeTiles\n *\n * @param row The row of this location in a grid of PipeTiles\n * @param col The column of this location in a grid of PipeTiles\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">row<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">col<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">toTheSouth<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Location<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">toTheNorth<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Location<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">toTheWest<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Location<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">toTheEast<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Location<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents a tile in the grid of pipes.\n *\n * Each tile is accessible via two different directions: north, south,\n * east, or west. The exceptions are tiles with no pipe, which aren't\n * accessible via any direction, and the default value for the start,\n * which is accessible in any direction. This will need to be corrected\n * before tracing the loop of pipes.\n *\n * @property north Is this tile accessible via the north?\n * @property south Is this tile accessible via the south?\n * @property east Is this tile accessible via the east?\n * @property west Is this tile accessible via the west?\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span>\n  <span class=\"kd\">var<\/span> <span class=\"py\">north<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">,<\/span> \n  <span class=\"kd\">var<\/span> <span class=\"py\">south<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">,<\/span> \n  <span class=\"kd\">var<\/span> <span class=\"py\">east<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">,<\/span> \n  <span class=\"kd\">var<\/span> <span class=\"py\">west<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">default<\/span><span class=\"p\">():<\/span> <span class=\"nc\">PipeTile<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"k\">false<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">fun<\/span> <span class=\"nf\">start<\/span><span class=\"p\">():<\/span> <span class=\"nc\">PipeTile<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"cm\">\/**\n         * Produce a [PipeTile] from a character.\n         *\n         * Maps the characters from the input file to the corresponding [PipeTile].\n         *\n         * @param char The character to map.\n         * @return The corresponding [PipeTile].\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromChar<\/span><span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Char<\/span><span class=\"p\">):<\/span> <span class=\"nc\">PipeTile<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sc\">'|'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">)<\/span>\n                <span class=\"sc\">'-'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n                <span class=\"sc\">'L'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">)<\/span>\n                <span class=\"sc\">'J'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n                <span class=\"sc\">'7'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n                <span class=\"sc\">'F'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">,<\/span> <span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">)<\/span>\n                <span class=\"sc\">'.'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nf\">default<\/span><span class=\"p\">()<\/span>\n                <span class=\"sc\">'S'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nf\">start<\/span><span class=\"p\">()<\/span>\n                <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span>\n                  <span class=\"s\">\"$char does not represent a valid pipe section!\"<\/span>\n                <span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Represents a two-dimensional grid of [PipeTile]s\n *\n * @property grid A two-dimensional array containing [PipeTile]s.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">PipeGrid<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">PipeTile<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"kd\">val<\/span> <span class=\"py\">rows<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span> <span class=\"k\">get<\/span><span class=\"p\">()<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">cols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span> <span class=\"k\">get<\/span><span class=\"p\">()<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">().<\/span><span class=\"n\">size<\/span>\n\n    <span class=\"cm\">\/**\n     * Override indexing operations so that the values in the grid can be\n     * accessed directly via [Location]. This operation includes bounds-checking,\n     * and will return a representation of an empty tile space for an attempt to\n     * access a location outside the grid.\n     *\n     * @param location The location of the tile to access.\n     *\/<\/span>\n    <span class=\"k\">operator<\/span> <span class=\"k\">fun<\/span> <span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">):<\/span> <span class=\"nc\">PipeTile<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">row<\/span><span class=\"p\">,<\/span> <span class=\"py\">col<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">location<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">indexOutOfBounds<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">&lt;<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">||<\/span> <span class=\"n\">row<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"n\">rows<\/span> <span class=\"p\">||<\/span> <span class=\"n\">col<\/span> <span class=\"p\">&lt;<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">||<\/span> <span class=\"n\">col<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"n\">cols<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">indexOutOfBounds<\/span><span class=\"p\">)<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">.<\/span><span class=\"nf\">default<\/span><span class=\"p\">()<\/span> <span class=\"k\">else<\/span> <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">row<\/span><span class=\"p\">][<\/span><span class=\"n\">col<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Provides a builder interface for producing a [PipeMap].\n *\n * Starting with the input file data, this class provides an API for\n * building up a [PipeMap] one step at a time.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">PipeMapBuilder<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">grid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">PipeGrid<\/span><span class=\"p\">?<\/span> <span class=\"p\">=<\/span> <span class=\"k\">null<\/span><span class=\"p\">,<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">start<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">?<\/span> <span class=\"p\">=<\/span> <span class=\"k\">null<\/span><span class=\"p\">,<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">loopTiles<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HashMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">&gt;?<\/span> <span class=\"p\">=<\/span> <span class=\"k\">null<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Read in the input file and fill in the [PipeGrid]\n     *\n     * @param input The list of lines from the input file.\n     * @return The partially completed [PipeMapBuilder] with grid added.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">readInputToGrid<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;):<\/span> <span class=\"nc\">PipeMapBuilder<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">grid<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">PipeGrid<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">line<\/span> <span class=\"p\">-&gt;<\/span>\n            <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">char<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromChar<\/span><span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n        <span class=\"p\">})<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * Identify the starting location of the [PipeGrid].\n     *\n     * Iterate through the grid tiles and pick out the starting Location. The\n     * starting [PipeTile] will need to be corrected from the default starting\n     * configuration based on its surrounding tiles.\n     *\n     * @return The partially completed [PipeMapBuilder] with starting location added.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">identifyStartLocation<\/span><span class=\"p\">():<\/span> <span class=\"nc\">PipeMapBuilder<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span> <span class=\"o\">?:<\/span> \n          <span class=\"k\">throw<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Must establish grid before identify start location.\"<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\">\/\/ Find the starting location.<\/span>\n        <span class=\"kd\">var<\/span> <span class=\"py\">startRow<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n        <span class=\"kd\">var<\/span> <span class=\"py\">startCol<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n        <span class=\"nd\">loop@<\/span> <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">rowIdx<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">colIdx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pipe<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">pipe<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">.<\/span><span class=\"nf\">start<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"n\">startRow<\/span> <span class=\"p\">=<\/span> <span class=\"n\">rowIdx<\/span>\n                    <span class=\"n\">startCol<\/span> <span class=\"p\">=<\/span> <span class=\"n\">colIdx<\/span>\n                    <span class=\"k\">break<\/span><span class=\"nd\">@loop<\/span>\n                <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">startLocation<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">startRow<\/span><span class=\"p\">,<\/span> <span class=\"n\">startCol<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\">\/\/ Correct the start location to identify which directions are actually valid<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">startPipe<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span><span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">startPipe<\/span><span class=\"p\">.<\/span><span class=\"n\">north<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"p\">!<\/span><span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">.<\/span><span class=\"nf\">toTheNorth<\/span><span class=\"p\">()].<\/span><span class=\"n\">south<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">].<\/span><span class=\"n\">north<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">startPipe<\/span><span class=\"p\">.<\/span><span class=\"n\">south<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"p\">!<\/span><span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">.<\/span><span class=\"nf\">toTheSouth<\/span><span class=\"p\">()].<\/span><span class=\"n\">north<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">].<\/span><span class=\"n\">south<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">startPipe<\/span><span class=\"p\">.<\/span><span class=\"n\">east<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"p\">!<\/span><span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">.<\/span><span class=\"nf\">toTheEast<\/span><span class=\"p\">()].<\/span><span class=\"n\">west<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">].<\/span><span class=\"n\">east<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">startPipe<\/span><span class=\"p\">.<\/span><span class=\"n\">west<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"p\">!<\/span><span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">.<\/span><span class=\"nf\">toTheWest<\/span><span class=\"p\">()].<\/span><span class=\"n\">east<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">startLocation<\/span><span class=\"p\">].<\/span><span class=\"n\">west<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"n\">start<\/span> <span class=\"p\">=<\/span> <span class=\"n\">startLocation<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * Trace the loop of pipes attached to the start location.\n     *\n     * Perform a breadth-first search through the pipes, producing a mapping\n     * of location to the number of steps that location is from the start.\n     *\n     * @return The partially completed [PipeMapBuilder] with completed `loopTiles`.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">tracePipeLoop<\/span><span class=\"p\">():<\/span> <span class=\"nc\">PipeMapBuilder<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span> <span class=\"o\">?:<\/span> \n          <span class=\"k\">throw<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Must establish grid before identify start location.\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">start<\/span> <span class=\"p\">=<\/span> <span class=\"n\">start<\/span> <span class=\"o\">?:<\/span> \n          <span class=\"k\">throw<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Must identify starting location before tracing the pipe loop!\"<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\">\/\/ We'll walk through using a Breadth-first search, so that we can walk away<\/span>\n        <span class=\"c1\">\/\/ from the starting location in both directions at the same time.<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">queue<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ArrayDeque<\/span><span class=\"p\">(<\/span><span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span> <span class=\"n\">to<\/span> <span class=\"n\">start<\/span><span class=\"p\">))<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">seenLocations<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HashMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">HashMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">&gt;()<\/span>\n\n        <span class=\"c1\">\/\/ So long as there are tiles left to visit...<\/span>\n        <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"n\">queue<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ Get the last location from the queue and add it to the<\/span>\n            <span class=\"c1\">\/\/ mapping of seen locations to number of steps taken, unless<\/span>\n            <span class=\"c1\">\/\/ we've already been there. That's probably not a concern with<\/span>\n            <span class=\"c1\">\/\/ this puzzle, but it's good practice.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">steps<\/span><span class=\"p\">,<\/span> <span class=\"py\">location<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">queue<\/span><span class=\"p\">.<\/span><span class=\"nf\">removeLast<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">seenLocations<\/span><span class=\"p\">.<\/span><span class=\"nf\">contains<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">))<\/span> <span class=\"k\">continue<\/span>\n            <span class=\"n\">seenLocations<\/span><span class=\"p\">[<\/span><span class=\"n\">location<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"n\">steps<\/span>\n\n            <span class=\"c1\">\/\/ Add all the neighbors that haven't been visited yet to the queue.<\/span>\n            <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">neighbor<\/span> <span class=\"k\">in<\/span> <span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"nf\">getNeighborsOf<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">seenLocations<\/span><span class=\"p\">.<\/span><span class=\"nf\">contains<\/span><span class=\"p\">(<\/span><span class=\"n\">neighbor<\/span><span class=\"p\">))<\/span> <span class=\"k\">continue<\/span>\n                <span class=\"n\">queue<\/span><span class=\"p\">.<\/span><span class=\"nf\">addFirst<\/span><span class=\"p\">(<\/span><span class=\"n\">steps<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"n\">neighbor<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n\n        <span class=\"n\">loopTiles<\/span> <span class=\"p\">=<\/span> <span class=\"n\">seenLocations<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * Finalize the [PipeMapBuilder] into a [PipeMap]\n     *\n     * @return A [PipeMap] with all the non-null properties of the [PipeMapBuilder].\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">toPipeMap<\/span><span class=\"p\">():<\/span> <span class=\"nc\">PipeMap<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span> <span class=\"o\">?:<\/span> \n          <span class=\"k\">throw<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Must establish grid before finalizing.\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">start<\/span> <span class=\"p\">=<\/span> <span class=\"n\">start<\/span> <span class=\"o\">?:<\/span> \n          <span class=\"k\">throw<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Must identify starting location before finalizing.\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">loopTiles<\/span> <span class=\"p\">=<\/span> <span class=\"n\">loopTiles<\/span> <span class=\"o\">?:<\/span> \n          <span class=\"k\">throw<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Must identify loop tiles before finalizing.\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">PipeMap<\/span><span class=\"p\">(<\/span><span class=\"n\">grid<\/span><span class=\"p\">,<\/span> <span class=\"n\">start<\/span><span class=\"p\">,<\/span> <span class=\"n\">loopTiles<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Represents a finalized [PipeMap].\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">PipeMap<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">PipeGrid<\/span><span class=\"p\">,<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">start<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">,<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">loopTiles<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HashMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> \n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day10<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ It's my first builder pattern in Kotlin!<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">PipeMapBuilder<\/span><span class=\"p\">()<\/span>\n      <span class=\"p\">.<\/span><span class=\"nf\">readInputToGrid<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n      <span class=\"p\">.<\/span><span class=\"nf\">identifyStartLocation<\/span><span class=\"p\">()<\/span>\n      <span class=\"p\">.<\/span><span class=\"nf\">tracePipeLoop<\/span><span class=\"p\">()<\/span>\n      <span class=\"p\">.<\/span><span class=\"nf\">toPipeMap<\/span><span class=\"p\">()<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Okay, to be fair, there\u2019s a good amount of the code that will eventually be used to solve part one in there. Thing is, it didn\u2019t make sense to walk over all the pipe tiles in order to identify which ones were in the loop <em>without<\/em> counting the steps while we did it. So, with this, we should pretty much be done with part one, right?<\/p>\n\n<h2>\n  \n  \n  Part One - Critter Chaser\n<\/h2>\n\n<p>In a strange and alien environment, a tiny robot flees into a tangle of pipes. Obviously, we need to go after it! But, we need to be smart about it. First, we\u2019ll figure out how far away from us it could <em>possibly<\/em> be by determining the maximum number of steps any piece of pipe could be from the starting location.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ data class Location(val row: Int, val col: Int) { ... }<\/span>\n\n<span class=\"c1\">\/\/ data class PipeTile(<\/span>\n<span class=\"c1\">\/\/ var north: Boolean, <\/span>\n<span class=\"c1\">\/\/ var south: Boolean, <\/span>\n<span class=\"c1\">\/\/ var east: Boolean, <\/span>\n<span class=\"c1\">\/\/ var west: Boolean<\/span>\n<span class=\"c1\">\/\/ ) { ... }<\/span>\n\n<span class=\"c1\">\/\/ data class PipeGrid(val grid: List&lt;List&lt;PipeTile&gt;&gt;) { ... }<\/span>\n\n<span class=\"c1\">\/\/ data class PipeMapBuilder(<\/span>\n<span class=\"c1\">\/\/ var grid: PipeGrid? = null,<\/span>\n<span class=\"c1\">\/\/ var start: Location? = null,<\/span>\n<span class=\"c1\">\/\/ var loopTiles: HashMap&lt;Location, Int&gt;? = null<\/span>\n<span class=\"c1\">\/\/ ) { ... }<\/span>\n\n<span class=\"cm\">\/**\n * Represents a finalized [PipeMap].\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">PipeMap<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">PipeGrid<\/span><span class=\"p\">,<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">start<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">,<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">loopTiles<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HashMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Return the maximum number of steps to any tile from the starting location.\n     *\n     * @return The maximum number of steps.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">stepsToFurthestPointFromStart<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">loopTiles<\/span><span class=\"p\">.<\/span><span class=\"n\">values<\/span><span class=\"p\">.<\/span><span class=\"nf\">max<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day10<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part one, we chase a furry critter through a loop of pipes.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">stepsToFurthestPointFromStart<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Yeah, I\u2019ll admit that most of the work was done by the parsing on this one. Unfortunately, that doesn\u2019t really hold true for part two\u2026<\/p>\n\n<h2>\n  \n  \n  Part Two - Enhance!\n<\/h2>\n\n<p>Having chased the \u201canimal\u201d into the tangled nest of pipes, we find it has eluded us. It probably has a nest somewhere! Clearly, disturbing this thing in its nest is likely to lead to us getting the machine parts we came for and <em>not<\/em> multiple lacerations from mechanical critter teeth. The thing is, our original map representation is poorly suited for determining which tiles are <em>completely<\/em> enclosed in the loop of pipes because it\u2019s too compact. By expanding the map\u2019s resolution, we can reliably determine which tiles can be accessed by walking between pipes (and thus excluded from our final count.)<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ data class Location(val row: Int, val col: Int) { ... }<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">PipeTile<\/span><span class=\"p\">(<\/span>\n  <span class=\"kd\">var<\/span> <span class=\"py\">north<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">,<\/span> \n  <span class=\"kd\">var<\/span> <span class=\"py\">south<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">,<\/span> \n  <span class=\"kd\">var<\/span> <span class=\"py\">east<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">,<\/span> \n  <span class=\"kd\">var<\/span> <span class=\"py\">west<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"cm\">\/**\n     * Expands a [PipeTile] from a 1x1 to a 3x3 representation.\n     *\n     * Expands this [PipeTile] so that it can occupy a 3x3 grid area for filling\n     * the tiles outside the loop in part two. Each direction that was accessible\n     * from the [PipeTile] now contains a corresponding PIPE variant, while the\n     * other tiles are PASSABLE. For example, if '#' is PIPE and '-' is PASSABLE,\n     * then the following transformations would apply:\n     *\n     * --- -#- -#- ---\n     * '7' -&gt; ##- 'J' -&gt; ##- '|' -&gt; -#- '-' -&gt; ###\n     * -#- --- -#- ---\n     *\n     * @return An [ExpandedMapTile]\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">expand<\/span><span class=\"p\">():<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">&gt;&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">pipes<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PASSABLE<\/span> <span class=\"p\">}<\/span> <span class=\"p\">}<\/span>\n        <span class=\"n\">pipes<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">][<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PIPE<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">north<\/span><span class=\"p\">)<\/span> <span class=\"n\">pipes<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">][<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PIPE<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">south<\/span><span class=\"p\">)<\/span> <span class=\"n\">pipes<\/span><span class=\"p\">[<\/span><span class=\"mi\">2<\/span><span class=\"p\">][<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PIPE<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">east<\/span><span class=\"p\">)<\/span> <span class=\"n\">pipes<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">][<\/span><span class=\"mi\">2<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PIPE<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">west<\/span><span class=\"p\">)<\/span> <span class=\"n\">pipes<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">][<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PIPE<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">pipes<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ data class PipeGrid(val grid: List&lt;List&lt;PipeTile&gt;&gt;) { ... }<\/span>\n\n<span class=\"c1\">\/\/ data class PipeMapBuilder(<\/span>\n<span class=\"c1\">\/\/ var grid: PipeGrid? = null,<\/span>\n<span class=\"c1\">\/\/ var start: Location? = null,<\/span>\n<span class=\"c1\">\/\/ var loopTiles: HashMap&lt;Location, Int&gt;? = null<\/span>\n<span class=\"c1\">\/\/ ) { ... }<\/span>\n\n<span class=\"c1\">\/\/ data class PipeMap(<\/span>\n<span class=\"c1\">\/\/ val grid: PipeGrid,<\/span>\n<span class=\"c1\">\/\/ var start: Location,<\/span>\n<span class=\"c1\">\/\/ var loopTiles: HashMap&lt;Location, Int&gt;<\/span>\n<span class=\"c1\">\/\/ ) { ... }<\/span>\n\n<span class=\"cm\">\/**\n * Represents a tile type in the [ExpandedPipeMap]\n *\/<\/span>\n<span class=\"k\">enum<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">ExpandedMapTile<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nc\">EMPTY<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ Nothing there<\/span>\n    <span class=\"nc\">PASSABLE<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ A passable tile next to a pipe<\/span>\n    <span class=\"nc\">PIPE<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ An impassable pipe tile<\/span>\n    <span class=\"nc\">OUTER<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ An empty tile outside the pipe loop<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Represents an expansion of the [PipeMap] for counting inner loop tiles.\n *\n * In Part two, we need to identify tiles _inside_ the loop of the pipes, which\n * means all tiles completely enclosed by the loop. The original grid makes\n * it difficult to determine which tiles are able to be traveled to from outside\n * the loop. By exapanding each original tile from a 1x1 to a 3x3 configuration,\n * we can walk the grid between the pipes.\n *\n * @param grid A two-dimensional grid of [ExpandedMapTile]s.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">ExpandedPipeMap<\/span><span class=\"p\">(<\/span><span class=\"kd\">var<\/span> <span class=\"py\">grid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">MutableList<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"cm\">\/**\n         * Expands a [PipeMap] into an [ExpandedPipeMap].\n         *\n         * @param pipeMap The [PipeMap] to expand.\n         * @return The expanded pipe map.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromPipeMap<\/span><span class=\"p\">(<\/span><span class=\"n\">pipeMap<\/span><span class=\"p\">:<\/span> <span class=\"nc\">PipeMap<\/span><span class=\"p\">):<\/span> <span class=\"nc\">ExpandedPipeMap<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ Expand all the original [PipeTile]s.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">expansions<\/span> <span class=\"p\">=<\/span>\n                <span class=\"n\">pipeMap<\/span><span class=\"p\">.<\/span><span class=\"n\">loopTiles<\/span><span class=\"p\">.<\/span><span class=\"n\">keys<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> \n                  <span class=\"n\">location<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">location<\/span> <span class=\"n\">to<\/span> <span class=\"n\">pipeMap<\/span><span class=\"p\">.<\/span><span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">location<\/span><span class=\"p\">].<\/span><span class=\"nf\">expand<\/span><span class=\"p\">()<\/span> \n                <span class=\"p\">}<\/span>\n\n            <span class=\"c1\">\/\/ For each expanded tile, transfer the [ExpandedPipeTile] variants to<\/span>\n            <span class=\"c1\">\/\/ correct location in a grid three times the size of the original grid.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">grid<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"n\">pipeMap<\/span><span class=\"p\">.<\/span><span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"n\">rows<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n              <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"n\">pipeMap<\/span><span class=\"p\">.<\/span><span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"n\">cols<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">EMPTY<\/span> <span class=\"p\">}<\/span> \n            <span class=\"p\">}<\/span>\n\n            <span class=\"c1\">\/\/ For each [ExpandedPipeTile] in each expansion, transfer it to the<\/span>\n            <span class=\"c1\">\/\/ appropriate location int the expanded grid.<\/span>\n            <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">location<\/span><span class=\"p\">,<\/span> <span class=\"n\">expansion<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">expansions<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">originalRow<\/span><span class=\"p\">,<\/span> <span class=\"py\">originalCol<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">location<\/span>\n                <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">rowIdx<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">expansion<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"kd\">val<\/span> <span class=\"py\">newRow<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">originalRow<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"n\">rowIdx<\/span>\n                    <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">colIdx<\/span><span class=\"p\">,<\/span> <span class=\"n\">isPipe<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n                        <span class=\"kd\">val<\/span> <span class=\"py\">newCol<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">originalCol<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"n\">colIdx<\/span>\n                        <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">newRow<\/span><span class=\"p\">][<\/span><span class=\"n\">newCol<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"n\">isPipe<\/span>\n                    <span class=\"p\">}<\/span>\n                <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"nc\">ExpandedPipeMap<\/span><span class=\"p\">(<\/span><span class=\"n\">grid<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"kd\">val<\/span> <span class=\"py\">rows<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span> <span class=\"k\">get<\/span><span class=\"p\">()<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">cols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span> <span class=\"k\">get<\/span><span class=\"p\">()<\/span> <span class=\"p\">=<\/span> <span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">().<\/span><span class=\"n\">size<\/span>\n\n    <span class=\"cm\">\/**\n     * Indicates whether the given location is accessible in the grid.\n     *\n     * In the expanded grid, a neighbor is accessible if it is in the grid\n     * and it _isn't_ a PIPE tile.\n     *\n     * @param location The [Location] to check.\n     * @return Whether the location is accessible\n     *\/<\/span>\n    <span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nf\">isAccessible<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Boolean<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span> <span class=\"p\">&lt;<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">||<\/span> <span class=\"n\">location<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"n\">rows<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"k\">false<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span> <span class=\"p\">&lt;<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">||<\/span> <span class=\"n\">location<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"n\">cols<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"k\">false<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">location<\/span><span class=\"p\">.<\/span><span class=\"n\">row<\/span><span class=\"p\">][<\/span><span class=\"n\">location<\/span><span class=\"p\">.<\/span><span class=\"n\">col<\/span><span class=\"p\">]<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">PIPE<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"k\">false<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">true<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * An updated function for finding neighbors in this new expanded grid.\n     *\n     * @param location The location to get neighbors for.\n     * @return A list of accessible neighbor locations.\n     *\/<\/span>\n    <span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nf\">getNeighborsOf<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Location<\/span><span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">row<\/span><span class=\"p\">,<\/span> <span class=\"py\">col<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">location<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">neighbors<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">&gt;()<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">isAccessible<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)))<\/span> <span class=\"n\">neighbors<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">isAccessible<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)))<\/span> <span class=\"n\">neighbors<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">isAccessible<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)))<\/span> <span class=\"n\">neighbors<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">isAccessible<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)))<\/span> <span class=\"n\">neighbors<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">neighbors<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * Count the tiles enclosed by the loop of pipe.\n     *\n     * In part two, we identify the tiles that _aren't_ enclosed in\n     * the loop by \"flood-filling\" from an identified outside tile. How\n     * was this starting tile identified? Visual inspection of the input!\n     *\n     * @return The number of tiles enclosed.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">countInnerTiles<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ Flood fill to populate the list of seen locations. Perform a<\/span>\n        <span class=\"c1\">\/\/ breadth-first search starting from a known outside tile and<\/span>\n        <span class=\"c1\">\/\/ convert any tile found into an OUTSIDE tile.<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">queue<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ArrayDeque<\/span><span class=\"p\">(<\/span><span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span><span class=\"nc\">Location<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)))<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">seenLocations<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HashSet<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">HashSet<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Location<\/span><span class=\"p\">&gt;()<\/span>\n\n        <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"n\">queue<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">location<\/span> <span class=\"p\">=<\/span> <span class=\"n\">queue<\/span><span class=\"p\">.<\/span><span class=\"nf\">removeLast<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">seenLocations<\/span><span class=\"p\">.<\/span><span class=\"nf\">contains<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">))<\/span> <span class=\"k\">continue<\/span>\n            <span class=\"n\">seenLocations<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">)<\/span>\n\n            <span class=\"c1\">\/\/ Mark the found tile as an OUTER tile<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">row<\/span><span class=\"p\">,<\/span> <span class=\"py\">col<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">location<\/span>\n            <span class=\"n\">grid<\/span><span class=\"p\">[<\/span><span class=\"n\">row<\/span><span class=\"p\">][<\/span><span class=\"n\">col<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">OUTER<\/span>\n\n            <span class=\"c1\">\/\/ Check each neighbor that hasn't been visited yet.<\/span>\n            <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">neighbor<\/span> <span class=\"k\">in<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">getNeighborsOf<\/span><span class=\"p\">(<\/span><span class=\"n\">location<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">seenLocations<\/span><span class=\"p\">.<\/span><span class=\"nf\">contains<\/span><span class=\"p\">(<\/span><span class=\"n\">neighbor<\/span><span class=\"p\">))<\/span> <span class=\"k\">continue<\/span>\n                <span class=\"n\">queue<\/span><span class=\"p\">.<\/span><span class=\"nf\">addFirst<\/span><span class=\"p\">(<\/span><span class=\"n\">neighbor<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ Return a count of all the EMPTY tiles. The total count is<\/span>\n        <span class=\"c1\">\/\/ divided by 9, because expanding a [PipeTile] to an [ExpandedMapTile]<\/span>\n        <span class=\"c1\">\/\/ increases the number of grid spaces by a factor of 9.<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">grid<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">row<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"nf\">count<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">ExpandedMapTile<\/span><span class=\"p\">.<\/span><span class=\"nc\">EMPTY<\/span> <span class=\"p\">}<\/span> <span class=\"p\">})<\/span> <span class=\"p\">\/<\/span> <span class=\"mi\">9<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day10<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part two we increase the resolution of the map to make it possible<\/span>\n    <span class=\"c1\">\/\/ to flag all the OUTER tiles, leaving the EMPTY tiles as the inner tiles.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">ExpandedPipeMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromPipeMap<\/span><span class=\"p\">(<\/span><span class=\"n\">parsed<\/span><span class=\"p\">).<\/span><span class=\"nf\">countInnerTiles<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>There\u2019s quite a bit of code there, and I <em>really<\/em> hope the comments are sufficient to explain what\u2019s going on here.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Today was a doozy! Not so much from the perspective of solving the puzzle, but just the sheer amount of code I wrote to parse, and then <em>re-parse<\/em> the parsed input into an expanded format. Granted, from the perspective of \u201clearning Kotlin\u201d, it was a good opportunity to write more code. And, I got to test-drive the builder pattern (even though it may not have been completely necessary). A lot of code on a weekend isn\u2019t anything to get upset about either. All told, it was a good day!<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 09","pubDate":"Sat, 09 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-09-4gkf","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-09-4gkf","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 9 - Mirage Maintenance\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/9\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Read the Room\n<\/h2>\n\n<p>Today\u2019s puzzle has us reading off lists of numbers from some fancy gadget we just happen to have in our pocket for checking environmental readings of oases. Sounds complicated, but it\u2019s really lines of space-separated numbers. This, we can handle.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day09<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ List of space-separated strings to list of lists of numbers,<\/span>\n    <span class=\"c1\">\/\/ coming up!<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">line<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\" \"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span> <span class=\"p\">}}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That\u2019s it? Yeah, that\u2019s going to be today\u2019s theme, didn\u2019t you hear?<\/p>\n\n<h2>\n  \n  \n  Part One - Getting to the Bottom of Things\n<\/h2>\n\n<p>Looks like we\u2019ve finally had a chance to rest, relax, and prepare for the next exciting leg of this journey. Good. We needed a bit of a break. Speaking of getting a break, part one of today\u2019s puzzle has us reading in a series of numbers, finding the next number in series, then adding up all the \u2019next numbers\u2019. It\u2019s some environmental stuff, so I hear. Thankfully, it\u2019s a straightforward recursive solution.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"cm\">\/**\n * Return the next number in the sequence.\n *\n * This is likely a very brittle approach (meaning the possibility of\n * recursing too deeply for generic lists of numbers), but for these\n * specially crafted sensor readings, it works just fine. This function\n * recursively generates the list of differences and adds the next\n * forecasted value from that list to the last value of the current list.\n *\n * @return The next forecasted value for this sequence of readings.\n *\/<\/span>\n<span class=\"k\">fun<\/span> <span class=\"nf\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;.<\/span><span class=\"nf\">nextSequenceValue<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Base case. No need to go to all zeros, oncw the sequence contains<\/span>\n    <span class=\"c1\">\/\/ all values the same, we know what the next value will be.<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"k\">this<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"p\">})<\/span> <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n\n    <span class=\"c1\">\/\/ Get the differences between each pair of values in `sequence`.<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">derivedSequence<\/span> <span class=\"p\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">windowed<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">left<\/span><span class=\"p\">,<\/span> <span class=\"n\">right<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">right<\/span> <span class=\"p\">-<\/span> <span class=\"n\">left<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">last<\/span><span class=\"p\">()<\/span> <span class=\"p\">+<\/span> <span class=\"n\">derivedSequence<\/span><span class=\"p\">.<\/span><span class=\"nf\">nextSequenceValue<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day09<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part one, we sum the next number in sequence for each list.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">nextSequenceValue<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Why, yes, there <em>is<\/em> more comment than code here. How very astute of you to notice!<\/p>\n\n<h2>\n  \n  \n  Part Two - Where Do You Come From, Where Do You Go?\n<\/h2>\n\n<p>Well, yes, I suppose it <em>would<\/em> be handy to know what the previous sensor value for each of these readings is. Granted, I don't know <em>what<\/em> each of these readings represents, so the value may be a <em>bit<\/em> limited, but more data is always better, right? I sure hope so!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ fun List&lt;Int&gt;.nextSequenceValue(): Int { ... }<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day09<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part two, we extrapolate each list _backwards_ by one, then sum<\/span>\n    <span class=\"c1\">\/\/ those results.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">reversed<\/span><span class=\"p\">().<\/span><span class=\"nf\">nextSequenceValue<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>I think I\u2019m going to go back to bed today!<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>It feels like today\u2019s puzzle was a bit of a break after yesterday\u2019s, although truth be told yesterday\u2019s puzzles wasn\u2019t <em>that<\/em> bad if you recalled the fondness of Advent of Code for problems with cyclical values. None of that today, though. Just do what the puzzle text says, earn stars, and move on. I wonder if this day was here to remind us all that <em>directions<\/em> and <em>puzzles<\/em> are two different things, and that <em>one<\/em> of those things is more fun than the other\u2026 Either way, I think I\u2019ll enjoy having the free time back today and spend it on something productive and festive. Happy Holidays!<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 08","pubDate":"Fri, 08 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-08-30ed","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-08-30ed","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 8 - Haunted Wasteland\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/7\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Mapping The Network Fantastic\n<\/h2>\n\n<p>Today\u2019s input offers a bit of a twist, with two distinct sections, but the lines of each part are pretty simple, so we won\u2019t have any issues there. I <em>considered<\/em> trying to map the input into a tree-based structure with nodes that pointed to each other, but it seemed like it might be a bit of a pain to make sure all the nodes got added, there might be cycles, etc. So, I opted for a simpler <code>String &gt; (left, right)<\/code> kind of structure that I thought I might change out in refactoring. Turns out, that was the right approach, but you\u2019ll have to read about part two to see why.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ More special utilities!<\/span>\n<span class=\"k\">import<\/span> <span class=\"nn\">dev.ericburden.aoc2023.Utils.repeating<\/span>\n\n<span class=\"cm\">\/**\n * This enum represents a direction, either left or right.\n *\/<\/span>\n<span class=\"k\">enum<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">Direction<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nc\">LEFT<\/span><span class=\"p\">,<\/span>\n    <span class=\"nc\">RIGHT<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromChar<\/span><span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Char<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Direction<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sc\">'L'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">LEFT<\/span>\n                <span class=\"sc\">'R'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">RIGHT<\/span>\n                <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$char cannot be parsed to a Direction!\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents a \"node\" on the map.\n *\n * Each node essentially serves as a signpost to the next node,\n * identifying the name of either the next node to the left or\n * the next node to the right.\n *\n * @property left The name of the next node to the left.\n * @property right The name of the next node to the right.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Signpost<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">left<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">right<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">nextFromDirection<\/span><span class=\"p\">(<\/span><span class=\"n\">direction<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Direction<\/span><span class=\"p\">):<\/span> <span class=\"nc\">String<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">direction<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nc\">Direction<\/span><span class=\"p\">.<\/span><span class=\"nc\">LEFT<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">left<\/span>\n            <span class=\"nc\">Direction<\/span><span class=\"p\">.<\/span><span class=\"nc\">RIGHT<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">right<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents an instance of our mysterious map.\n *\n * @property directions A private iterator that can continually\n * produce the next [Direction] to take.\n * @property map The mapping of \"node\" name to the signpost for\n * the next possible nodes.\n *\/<\/span>\n<span class=\"kd\">class<\/span> <span class=\"nc\">NodeMap<\/span><span class=\"p\">(<\/span><span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">directions<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Iterator<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Direction<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Map<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Signpost<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"cm\">\/**\n         * Parses a [NodeMap] from the input file chunks.\n         *\n         * @param input A list of \"chunks\" of the input file, where\n         * each \"chunk\" is a list of lines.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromInput<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;):<\/span> <span class=\"nc\">NodeMap<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">directionChunk<\/span><span class=\"p\">,<\/span> <span class=\"py\">nodeChunk<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">directions<\/span> <span class=\"p\">=<\/span> <span class=\"n\">directionChunk<\/span><span class=\"p\">.<\/span><span class=\"nf\">single<\/span><span class=\"p\">().<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">Direction<\/span><span class=\"o\">::<\/span><span class=\"n\">fromChar<\/span><span class=\"p\">).<\/span><span class=\"nf\">repeating<\/span><span class=\"p\">()<\/span>\n\n            <span class=\"c1\">\/\/ '.associate' is analagous to 'map().toMap().'<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span> <span class=\"p\">=<\/span> <span class=\"n\">nodeChunk<\/span><span class=\"p\">.<\/span><span class=\"nf\">associate<\/span> <span class=\"p\">{<\/span> <span class=\"n\">line<\/span> <span class=\"p\">-&gt;<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">re<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"\"\"(\\w+) = \\((\\w+), (\\w+)\\)\"\"\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">matchResult<\/span> <span class=\"p\">=<\/span>\n                    <span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">find<\/span><span class=\"p\">(<\/span><span class=\"n\">line<\/span><span class=\"p\">)<\/span>\n                        <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span>\n                            <span class=\"s\">\"$line is not formatted properly!\"<\/span>\n                        <span class=\"p\">)<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">label<\/span><span class=\"p\">,<\/span> <span class=\"py\">left<\/span><span class=\"p\">,<\/span> <span class=\"py\">right<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">matchResult<\/span><span class=\"p\">.<\/span><span class=\"n\">destructured<\/span>\n                <span class=\"n\">label<\/span> <span class=\"n\">to<\/span> <span class=\"nc\">Signpost<\/span><span class=\"p\">(<\/span><span class=\"n\">left<\/span><span class=\"p\">,<\/span> <span class=\"n\">right<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"nc\">NodeMap<\/span><span class=\"p\">(<\/span><span class=\"n\">directions<\/span><span class=\"p\">,<\/span> <span class=\"n\">map<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day08<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ Parse that input!<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">nodeMap<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">NodeMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromInput<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Today, I learned how to do one of my favorite things (implementing an iterator) in Kotlin. Yay! I\u2019ve added it to my utilities package, since it seems like it will be handy to have a way to make a list loop over and over. Here\u2019s what the implementation for that looks like:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\n\/**\n * Return an iterator that outputs the contents of the list infinitely.\n *\n * This function extends the functionality of a [List&lt;T&gt;] by adding\n * a 'repeating` function that returns an iterator that returns the\n * values of the list, in order, starting over when the list is\n * exhausted.\n *\n * @return A RepeatingList over the list.\n *\/\nfun&lt;T&gt; List&lt;T&gt;.repeating(): Iterator&lt;T&gt; = RepeatingList(this)\n\n\/**\n * This class represents an iterator that repeats the values in a list.\n *\n * @property list The list to repeat.\n *\/\nclass RepeatingList&lt;T&gt;(private val list: List&lt;T&gt;) : Iterator&lt;T&gt; {\n    private var currentIndex = 0\n\n    override fun hasNext(): Boolean {\n        return list.isNotEmpty()\n    }\n\n    override fun next(): T {\n        if (list.isEmpty()) {\n            throw NoSuchElementException(\"List is empty\")\n        }\n\n        val element = list[currentIndex]\n        currentIndex = (currentIndex + 1) % list.size\n        return element\n    }\n}\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>It may not be the <em>most<\/em> elegant way to handle this, but I like it!<\/p>\n\n<h2>\n  \n  \n  Part One - That Rude Sandstorm\n<\/h2>\n\n<p>The elf was a ghost! And she left us in the path of a sandstorm! At least we have a map. Hopefully it\u2019s a map to safety, although that isn\u2019t really specified. If nothing else, it\u2019s a bit of a network problem to work on while the storm rolls in\u2026 In true Advent of Code fashion, our goal is to find the shortest path through a ~graph~ desert.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"kd\">class<\/span> <span class=\"nc\">NodeMap<\/span><span class=\"p\">(<\/span><span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">directions<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Iterator<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Direction<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Map<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Signpost<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"cm\">\/**\n     * Advance from a position to some other position that satisfies a condition.\n     *\n     * Given the name of a node on the map, follow the directions and advance from\n     * node to node until the current node satisfies some condition.\n     *\n     * @param start The name of the node to start at.\n     * @param stop A predicate function that indicates when to stop advancing.\n     * @return A pair of the number of steps taken and the name of the node stopped on.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">advanceUntil<\/span><span class=\"p\">(<\/span><span class=\"n\">start<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"n\">stop<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">Boolean<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nc\">String<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">var<\/span> <span class=\"py\">currentLocation<\/span> <span class=\"p\">=<\/span> <span class=\"n\">start<\/span>\n        <span class=\"kd\">var<\/span> <span class=\"py\">steps<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n\n        <span class=\"k\">while<\/span> <span class=\"p\">(!<\/span><span class=\"nf\">stop<\/span><span class=\"p\">(<\/span><span class=\"n\">currentLocation<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">currentLocation<\/span> <span class=\"p\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">advanceOnce<\/span><span class=\"p\">(<\/span><span class=\"n\">currentLocation<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">steps<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span>\n        <span class=\"p\">}<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">steps<\/span> <span class=\"n\">to<\/span> <span class=\"n\">currentLocation<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day08<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val nodeMap = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part one, we follow the signs from our starting position<\/span>\n    <span class=\"c1\">\/\/ to our target and count the steps taken.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">nodeMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">advanceUntil<\/span><span class=\"p\">(<\/span><span class=\"s\">\"AAA\"<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"s\">\"ZZZ\"<\/span> <span class=\"p\">}.<\/span><span class=\"n\">first<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That wasn\u2019t so bad! Who needed that spooky elf anyway?<\/p>\n\n<h2>\n  \n  \n  Part Two - Splitting Headache\n<\/h2>\n\n<p>Wait. What? I can\u2019t tell if we\u2019re actually trying to ignore the laws of space-time and walk multiple simultaneous paths the way we <em>assume<\/em> the ghost can or if we\u2019re just kind of curious how the ghost managed to get away so fast. If I\u2019m being honest, I\u2019d suspect it has more to do with <em>being a ghost<\/em> than with map traversal, but what do I know? In part two, we need to somehow start on all the nodes that end with \u2018A\u2019 and walk to all the nodes that end with \u2018Z\u2019 all our versions land on a \u2018Z\u2019-ending node simultaneously. Guess ghosts don\u2019t know how to just stop and wait for the others to catch up. Oh, actually, that sort of makes sense\u2026<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"kd\">class<\/span> <span class=\"nc\">NodeMap<\/span><span class=\"p\">(<\/span><span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">directions<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Iterator<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Direction<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Map<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Signpost<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"c1\">\/\/ fun advanceUntil(start: String, stop: (String) -&gt; Boolean): Pair&lt;Int, String&gt; {<\/span>\n    <span class=\"c1\">\/\/ ...<\/span>\n    <span class=\"c1\">\/\/ }<\/span>\n\n    <span class=\"cm\">\/**\n     * Advance one step from a given node.\n     *\n     * Given the name of a node on the map, follow the directions and advance\n     * a single step forward.\n     *\n     * @param start The name of the node to start at.\n     * @return The name of the next node in sequence.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">advanceOnce<\/span><span class=\"p\">(<\/span><span class=\"n\">start<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">String<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">direction<\/span> <span class=\"p\">=<\/span> <span class=\"n\">directions<\/span><span class=\"p\">.<\/span><span class=\"nf\">next<\/span><span class=\"p\">()<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">node<\/span> <span class=\"p\">=<\/span> <span class=\"n\">map<\/span><span class=\"p\">[<\/span><span class=\"n\">start<\/span><span class=\"p\">]<\/span> <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$start is not a node on the map!\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">node<\/span><span class=\"p\">.<\/span><span class=\"nf\">nextFromDirection<\/span><span class=\"p\">(<\/span><span class=\"n\">direction<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day08<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val nodeMap = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ In part two we pretend to be some sort of quantum ghost and<\/span>\n    <span class=\"c1\">\/\/ try to take multiple paths simultaneously. This seems like it<\/span>\n    <span class=\"c1\">\/\/ might be _more_ traumatic than the sandstorm...<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">(<\/span><span class=\"n\">example<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Boolean<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ Predicates to select lists that end with 'A' or 'Z'.<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">endsWithA<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">Boolean<\/span> <span class=\"p\">=<\/span> <span class=\"p\">{<\/span> <span class=\"n\">str<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">str<\/span><span class=\"p\">[<\/span><span class=\"n\">str<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">==<\/span> <span class=\"sc\">'A'<\/span> <span class=\"p\">}<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">endsWithZ<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">Boolean<\/span> <span class=\"p\">=<\/span> <span class=\"p\">{<\/span> <span class=\"n\">str<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">str<\/span><span class=\"p\">[<\/span><span class=\"n\">str<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"p\">==<\/span> <span class=\"sc\">'Z'<\/span> <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ Our starting locations are the ones that end with 'A'<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">startingLocations<\/span> <span class=\"p\">=<\/span> <span class=\"n\">nodeMap<\/span><span class=\"p\">.<\/span><span class=\"n\">map<\/span><span class=\"p\">.<\/span><span class=\"n\">keys<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span><span class=\"p\">(<\/span><span class=\"n\">endsWithA<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">destinations<\/span> <span class=\"p\">=<\/span> <span class=\"n\">startingLocations<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">loc<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">nodeMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">advanceUntil<\/span><span class=\"p\">(<\/span><span class=\"n\">loc<\/span><span class=\"p\">,<\/span> <span class=\"n\">endsWithZ<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ Need to check and be sure that each 'path' starting from a node whose<\/span>\n        <span class=\"c1\">\/\/ name ends with 'A' is actually cyclical. If it _does_ take the same<\/span>\n        <span class=\"c1\">\/\/ number of steps to get back to the _same_ end node as it took to get<\/span>\n        <span class=\"c1\">\/\/ there originally, then we can calculate the number of steps needed to<\/span>\n        <span class=\"c1\">\/\/ get to _all_ end nodes as the least common multiple of the number of<\/span>\n        <span class=\"c1\">\/\/ steps in each path in a cycle. If not... then my only other option<\/span>\n        <span class=\"c1\">\/\/ (that I know of) is to turn on the brute force method of just taking<\/span>\n        <span class=\"c1\">\/\/ one step on each path then checking to see if all paths found an end.<\/span>\n        <span class=\"c1\">\/\/ Oddly enough, this enters an endless loop on the part two example<\/span>\n        <span class=\"c1\">\/\/ (it's that \"XXX = (XXX, XXX)\" line), so I need to skip this bit when<\/span>\n        <span class=\"c1\">\/\/ running my test on the example input. _Kind_ of a bummer that the apparent<\/span>\n        <span class=\"c1\">\/\/ intended solution fails on the example.<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(!<\/span><span class=\"n\">example<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">nextDestinations<\/span> <span class=\"p\">=<\/span> <span class=\"n\">destinations<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">loc<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">start<\/span> <span class=\"p\">=<\/span> <span class=\"n\">nodeMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">advanceOnce<\/span><span class=\"p\">(<\/span><span class=\"n\">loc<\/span><span class=\"p\">)<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">steps<\/span><span class=\"p\">,<\/span> <span class=\"py\">end<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">nodeMap<\/span><span class=\"p\">.<\/span><span class=\"nf\">advanceUntil<\/span><span class=\"p\">(<\/span><span class=\"n\">start<\/span><span class=\"p\">,<\/span> <span class=\"n\">endsWithZ<\/span><span class=\"p\">)<\/span>\n                <span class=\"n\">steps<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"n\">end<\/span><span class=\"c1\">\/\/ Account for that one extra step from the end<\/span>\n            <span class=\"p\">}<\/span>\n            <span class=\"nf\">assert<\/span><span class=\"p\">(<\/span><span class=\"n\">destinations<\/span> <span class=\"p\">==<\/span> <span class=\"n\">nextDestinations<\/span><span class=\"p\">)<\/span> <span class=\"c1\">\/\/ Cross your fingers!<\/span>\n        <span class=\"p\">}<\/span>\n\n        <span class=\"c1\">\/\/ I happen to know that this works, at least for my input.<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">destinations<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLong<\/span><span class=\"p\">()<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">lcm<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Pro Tip: When your naive brute-force solution starts to make your computer fan kick on and run for more than thirty seconds, you\u2019re missing something. Many times, that something is a cycle you can exploit in some way. In this case, it turns out that all the individual \u2018__A\u2019 -&gt; \u2018__Z\u2019 paths were cyclical <em>and<\/em> it took the same number of steps to go from \u2018__A\u2019 to \u2018__Z\u2019 as it took to make another trip around starting from that same endpoint. With <em>that<\/em> discovery in place, the number of steps is as many as it takes for the periodicity of all the paths to line up.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>This was a good day! To be fair, I\u2019m a <em>wee<\/em> bit miffed that the example input for part two breaks my code I used to check to see if the \u201cone weird trick\u201d for finding the total number of steps would work. That caused me a bit of a headache, I can tell you for free. On the other hand, I got to learn how to implement my own iterator, how to pass lambdas to functions (so <em>that\u2019s<\/em> how you get that \u201ccurly-braces after the parentheses\u201d syntax!), <em>and<\/em> how to extract regular expression matches from a string. All told, it was a very productive day for learning Kotlin, and that\u2019s what I\u2019m here for!<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 07","pubDate":"Thu, 07 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-07-p0p","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-07-p0p","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 7 - Camel Cards\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/7\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Dromedary Deck\n<\/h2>\n\n<p>Hmm, the input looks suspiciously straightforward to parse today. It\u2019s an odd-numbered, day, though, so I\u2019m still cautious about the difficulty level. Regardless, here we\u2019ve got input in lines, each one containing two strings separated by <em>a single space<\/em>, where we need a list of characters from the first string and a parsed integer from the second. That\u2019s do-able! I\u2019ll also be representing each card as hand type as an <code>enum<\/code> with an associated \u2018strength\u2019 that can help us when sorting later.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"cm\">\/**\n * This enumeration represents the various types of Camel Cards\n *\n * @param strength The strength of the card when it comes to sorting.\n *\/<\/span>\n<span class=\"k\">enum<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">CamelCard<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">strength<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nc\">ACE<\/span><span class=\"p\">(<\/span><span class=\"mi\">14<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">KING<\/span><span class=\"p\">(<\/span><span class=\"mi\">13<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">QUEEN<\/span><span class=\"p\">(<\/span><span class=\"mi\">12<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">JACK<\/span><span class=\"p\">(<\/span><span class=\"mi\">11<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">TEN<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">NINE<\/span><span class=\"p\">(<\/span><span class=\"mi\">9<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">EIGHT<\/span><span class=\"p\">(<\/span><span class=\"mi\">8<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">SEVEN<\/span><span class=\"p\">(<\/span><span class=\"mi\">7<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">SIX<\/span><span class=\"p\">(<\/span><span class=\"mi\">6<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">FIVE<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">FOUR<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">THREE<\/span><span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">TWO<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">JOKER<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ For Part Two<\/span>\n\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"cm\">\/**\n         * Parse a [CamelCard] from a [Char]\n         *\n         * @param char The Char value to parse.\n         * @return The corresponding [Camel Card].\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromChar<\/span><span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Char<\/span><span class=\"p\">):<\/span> <span class=\"nc\">CamelCard<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">char<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sc\">'A'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">ACE<\/span>\n                <span class=\"sc\">'K'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">KING<\/span>\n                <span class=\"sc\">'Q'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">QUEEN<\/span>\n                <span class=\"sc\">'J'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">JACK<\/span>\n                <span class=\"sc\">'T'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">TEN<\/span>\n                <span class=\"sc\">'9'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">NINE<\/span>\n                <span class=\"sc\">'8'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">EIGHT<\/span>\n                <span class=\"sc\">'7'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">SEVEN<\/span>\n                <span class=\"sc\">'6'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">SIX<\/span>\n                <span class=\"sc\">'5'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FIVE<\/span>\n                <span class=\"sc\">'4'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FOUR<\/span>\n                <span class=\"sc\">'3'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">THREE<\/span>\n                <span class=\"sc\">'2'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">TWO<\/span>\n                <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span>\n                  <span class=\"s\">\"$char does not represent a CamelCard!\"<\/span>\n                <span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This enumeration represents the various kinds of hands\n *\n * @param strength The strength of this kind of hand when it comes to sorting.\n *\/<\/span>\n<span class=\"k\">enum<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">strength<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nc\">FiveOfAKind<\/span><span class=\"p\">(<\/span><span class=\"mi\">7_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">FourOfAKind<\/span><span class=\"p\">(<\/span><span class=\"mi\">6_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">FullHouse<\/span><span class=\"p\">(<\/span><span class=\"mi\">5_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">ThreeOfAKind<\/span><span class=\"p\">(<\/span><span class=\"mi\">4_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">TwoPair<\/span><span class=\"p\">(<\/span><span class=\"mi\">3_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">OnePair<\/span><span class=\"p\">(<\/span><span class=\"mi\">2_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">HighCard<\/span><span class=\"p\">(<\/span><span class=\"mi\">1_000_000<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"cm\">\/**\n         * Classify a hand of [CamelCard]s into a [HandKind]\n         *\n         * Check a list of camel cards for special cases, like four of a kind, \n         * and return the highest-strength classification possible for that \n         * list of cards. The classifications are the variants of [HandKind].\n         *\n         * @param cards The list of cards to be classified.\n         * @return The [HandKind] representing the classification of the cards.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">classify<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CamelCard<\/span><span class=\"p\">&gt;):<\/span> <span class=\"nc\">HandKind<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">var<\/span> <span class=\"py\">counts<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"mi\">15<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">}<\/span>\n            <span class=\"n\">cards<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span> <span class=\"p\">{<\/span> <span class=\"n\">card<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">counts<\/span><span class=\"p\">[<\/span><span class=\"n\">card<\/span><span class=\"p\">.<\/span><span class=\"n\">strength<\/span><span class=\"p\">]<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span> <span class=\"p\">}<\/span>\n\n            <span class=\"kd\">val<\/span> <span class=\"py\">maxCount<\/span> <span class=\"p\">=<\/span> <span class=\"n\">counts<\/span><span class=\"p\">.<\/span><span class=\"nf\">max<\/span><span class=\"p\">()<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">pairCount<\/span> <span class=\"p\">=<\/span> <span class=\"n\">counts<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">count<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">maxCount<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"mi\">5<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FiveOfAKind<\/span>\n                <span class=\"mi\">4<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FourOfAKind<\/span>\n                <span class=\"mi\">3<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">pairCount<\/span> <span class=\"p\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"nc\">FullHouse<\/span> <span class=\"k\">else<\/span> <span class=\"nc\">ThreeOfAKind<\/span>\n                <span class=\"mi\">2<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">pairCount<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"nc\">TwoPair<\/span> <span class=\"k\">else<\/span> <span class=\"nc\">OnePair<\/span>\n                <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">HighCard<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents a hand of [CamelCard]s\n *\n * Each hand contains five cards, and the strength of that hand can be derived \n * from the identity and order of those cards. Each hand also includes the \n * accompanying bid, used to calculate the final result for both parts of \n * today's puzzle.\n *\n * @param cards The list of [CamelCard]s in hand.\n * @param bid The value of the bid.\n * @param kind The [HandKind] classification of the hand.\n * @param strength The strength of this hand when it comes to sorting.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">CamelCardHand<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">cards<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CamelCard<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">bid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">kind<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n        <span class=\"cm\">\/**\n         * Parse a [CamelCardHand] from a line of the input string.\n         *\n         * Each line includes the cards (as a string where each character\n         * represents a card) and a bid.\n         *\n         * @param string The input line to be parsed.\n         * @return A hand of Camel Cards.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">string<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">CamelCardHand<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">cardString<\/span><span class=\"p\">,<\/span> <span class=\"py\">bidString<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">string<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\" \"<\/span><span class=\"p\">)<\/span>\n            <span class=\"nf\">require<\/span><span class=\"p\">(<\/span><span class=\"n\">cardString<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">5<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"A hand must contain five cards!\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">cards<\/span> <span class=\"p\">=<\/span> <span class=\"n\">cardString<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"nc\">CamelCard<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromChar<\/span><span class=\"p\">(<\/span><span class=\"n\">it<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">bid<\/span> <span class=\"p\">=<\/span> <span class=\"n\">bidString<\/span><span class=\"p\">.<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">kind<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">.<\/span><span class=\"nf\">classify<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">CamelCardHand<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">,<\/span> <span class=\"n\">bid<\/span><span class=\"p\">,<\/span> <span class=\"n\">kind<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day07<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ With the data nicely modeled, parsing is a breeze!<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n      <span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n      <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"nc\">CamelCardHand<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">it<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That\u2019s still a fair bit of code, but the <code>enums<\/code> tend to make it look like more than it is. This should set us up nicely for part one.<\/p>\n\n<h2>\n  \n  \n  Part One - A Link in the Chain\n<\/h2>\n\n<p>I\u2019ve figured it out! We\u2019re in a Zelda game. \u201cFetch me that sword!\u201d \u201cYou can have my sword, but before I give it to you, fetch me a sandwich!\u201d \u201cI\u2019d love to make you a sandwich, but this bug in my house is driving me mad. What, you don\u2019t have a bug net? Maybe the raccoon in the woods has one.\u201d That\u2019s what we\u2019re doing here. I\u2019m going to be both extremely amused and a bit exasperated if those jokers on the ground with the trebuchet have the last piece of this quest chain\u2026 Ah well, at least we get to play a lovely game of poker while traveling via camel. That actually sounds kind of fun! Let\u2019s sort out these hands of cards!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ I made my own!<\/span>\n<span class=\"k\">import<\/span> <span class=\"nn\">dev.ericburden.aoc2023.Utils.pow<\/span>\n\n<span class=\"c1\">\/\/ enum class CamelCard(val strength: Int) { ... }<\/span>\n\n<span class=\"c1\">\/\/ enum class HandKind(val strength: Int) { ... }<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">CamelCardHand<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">cards<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CamelCard<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">bid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">kind<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span> <span class=\"o\">..<\/span><span class=\"p\">.<\/span> <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * Calculate and return the total strength of this hand.\n     * \n     * The strength of a hand is derived from the individual cards in it, their \n     * order, and what kind of hand is formed by those cards. Each card in the \n     * hand is worth it's own strength times its place value. The place value is \n     * 14 (the maximum card strength) raised to the place index (descending from \n     * left to right). For example, the cards [2, 2, 2, 2, 2] would have place \n     * values of [2 * 14^4, 2 * 14^3, 2 * 14^2, 2 * 14^1, 2 * 14^0]. The strength \n     * derived from the _kind_ of hand is the most influential, since hands are \n     * sorted based on kind, then on the order of the cards. For this reason, \n     * each kind contributes an extra 1_000_000 to the strength, which is \n     * greater than the maximum possible strength derived from any set of cards \n     * ([A, A, A, A, A] = 579,194), and they're nice round numbers! These values \n     * contribute to a strength score such that, when sorted by that strength, \n     * hands will be sorted first on the kind of hand then on the order of the\n     * individual cards.\n     * \n     * @return The total strength of this hand.\n     *\/<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">strength<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span>\n        <span class=\"k\">get<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">maxCardIdx<\/span> <span class=\"p\">=<\/span> <span class=\"n\">cards<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">cardStrength<\/span> <span class=\"p\">=<\/span>\n                    <span class=\"n\">cards<\/span><span class=\"p\">.<\/span><span class=\"nf\">zip<\/span><span class=\"p\">(<\/span><span class=\"n\">maxCardIdx<\/span> <span class=\"n\">downTo<\/span> <span class=\"mi\">0<\/span><span class=\"p\">).<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">card<\/span><span class=\"p\">,<\/span> <span class=\"n\">exp<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n                        <span class=\"n\">card<\/span><span class=\"p\">.<\/span><span class=\"n\">strength<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">14<\/span><span class=\"p\">.<\/span><span class=\"nf\">pow<\/span><span class=\"p\">(<\/span><span class=\"n\">exp<\/span><span class=\"p\">)<\/span>\n                    <span class=\"p\">}<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">cardStrength<\/span> <span class=\"p\">+<\/span> <span class=\"n\">kind<\/span><span class=\"p\">.<\/span><span class=\"n\">strength<\/span>\n        <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day07<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ The trickiest bit to part one was telling the difference between a hand with<\/span>\n    <span class=\"c1\">\/\/ on pair and a hand with two pair.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span>\n            <span class=\"n\">parsed<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">sortedBy<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">strength<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">()<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">idx<\/span><span class=\"p\">,<\/span> <span class=\"n\">hand<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"p\">(<\/span><span class=\"n\">idx<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">*<\/span> <span class=\"n\">hand<\/span><span class=\"p\">.<\/span><span class=\"n\">bid<\/span> <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>There we go! A bit of math to make sure that all the hands are scored and sorted correctly. I do feel a bit clever basically treating the different types of cards as a base-14 number and converting it to decimal. Snaps for me! I also decided to stop complaining about the lack of an exponentiation function for integers and just make my own. So there!<\/p>\n\n<h2>\n  \n  \n  Part Two - Speaking of Jokers\u2026\n<\/h2>\n\n<p>Now this game is about to get <em>wild<\/em>! (Yes, I did that. I\u2019m not ashamed.) Looks like all the Jacks were really Jokers which can <em>pretend<\/em> to be anything else! While at first this seems like a major twist, it ends up being not too tricky to handle.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ enum class CamelCard(val strength: Int) { ... }<\/span>\n\n<span class=\"k\">enum<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">strength<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nc\">FiveOfAKind<\/span><span class=\"p\">(<\/span><span class=\"mi\">7_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">FourOfAKind<\/span><span class=\"p\">(<\/span><span class=\"mi\">6_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">FullHouse<\/span><span class=\"p\">(<\/span><span class=\"mi\">5_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">ThreeOfAKind<\/span><span class=\"p\">(<\/span><span class=\"mi\">4_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">TwoPair<\/span><span class=\"p\">(<\/span><span class=\"mi\">3_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">OnePair<\/span><span class=\"p\">(<\/span><span class=\"mi\">2_000_000<\/span><span class=\"p\">),<\/span>\n    <span class=\"nc\">HighCard<\/span><span class=\"p\">(<\/span><span class=\"mi\">1_000_000<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ fun classify(cards: List&lt;CamelCard&gt;): HandKind { ... }<\/span>\n\n        <span class=\"cm\">\/**\n         * Classify a hand of cards containing Jokers\n         *\n         * This could have been included in the `HandKind.classify` function, \n         * but I separated it out because it's only used in part 2. For hands \n         * that contain Jokers (and treat them as wildcards), we determine what \n         * the hand _would be_ without the jokers, then promote the \n         * classification one step for each Joker found.\n         *\n         * @param cards A list of cards where Joker are wild.\n         * @return The [HandKind] representing the classification of the cards.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">classifyWithJokers<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CamelCard<\/span><span class=\"p\">&gt;):<\/span> <span class=\"nc\">HandKind<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ What kind of hand would it be without the Jokers?<\/span>\n            <span class=\"kd\">var<\/span> <span class=\"py\">handKind<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">classify<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">!=<\/span> <span class=\"nc\">CamelCard<\/span><span class=\"p\">.<\/span><span class=\"nc\">JOKER<\/span> <span class=\"p\">})<\/span>\n\n            <span class=\"c1\">\/\/ For every Joker in the hand, increase the value of the hand by <\/span>\n            <span class=\"c1\">\/\/ one step, always choosing the next possible kind with the highest<\/span>\n            <span class=\"c1\">\/\/ strength possible.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">jokerCount<\/span> <span class=\"p\">=<\/span> <span class=\"n\">cards<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">CamelCard<\/span><span class=\"p\">.<\/span><span class=\"nc\">JOKER<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">count<\/span><span class=\"p\">()<\/span>\n            <span class=\"nf\">repeat<\/span><span class=\"p\">(<\/span><span class=\"n\">jokerCount<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"n\">handKind<\/span> <span class=\"p\">=<\/span>\n                        <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">handKind<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                            <span class=\"nc\">FiveOfAKind<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FiveOfAKind<\/span> <span class=\"c1\">\/\/ Best we can do<\/span>\n                            <span class=\"nc\">FourOfAKind<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FiveOfAKind<\/span>\n                            <span class=\"nc\">FullHouse<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FourOfAKind<\/span>\n                            <span class=\"nc\">ThreeOfAKind<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FourOfAKind<\/span>\n                            <span class=\"nc\">TwoPair<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">FullHouse<\/span>\n                            <span class=\"nc\">OnePair<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">ThreeOfAKind<\/span>\n                            <span class=\"nc\">HighCard<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">OnePair<\/span>\n                        <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"n\">handKind<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">CamelCardHand<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">cards<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CamelCard<\/span><span class=\"p\">&gt;,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">bid<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">kind<\/span><span class=\"p\">:<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n    <span class=\"c1\">\/\/ val strength: Int get() { ... }<\/span>\n\n    <span class=\"cm\">\/**\n     * Replace all the Jacks in a hand with Jokers\n     * \n     * Recalculates the [HandKind] of this hand with Jokers included.\n     * \n     * @return A copy of this hand with all Jacks replaced with Jokers.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">replaceJacksWithJokers<\/span><span class=\"p\">():<\/span> <span class=\"nc\">CamelCardHand<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">cards<\/span> <span class=\"p\">=<\/span> <span class=\"n\">cards<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">it<\/span> <span class=\"p\">==<\/span> <span class=\"nc\">CamelCard<\/span><span class=\"p\">.<\/span><span class=\"nc\">JACK<\/span><span class=\"p\">)<\/span> <span class=\"nc\">CamelCard<\/span><span class=\"p\">.<\/span><span class=\"nc\">JOKER<\/span> <span class=\"k\">else<\/span> <span class=\"n\">it<\/span> <span class=\"p\">}<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">kind<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">HandKind<\/span><span class=\"p\">.<\/span><span class=\"nf\">classifyWithJokers<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">CamelCardHand<\/span><span class=\"p\">(<\/span><span class=\"n\">cards<\/span><span class=\"p\">,<\/span> <span class=\"n\">bid<\/span><span class=\"p\">,<\/span> <span class=\"n\">kind<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day07<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n    <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n    <span class=\"c1\">\/\/ The trickiest bit to part two was that one hand with all Jacks!<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span>\n            <span class=\"n\">parsed<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">replaceJacksWithJokers<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">sortedBy<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">strength<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">()<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">idx<\/span><span class=\"p\">,<\/span> <span class=\"n\">hand<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"p\">(<\/span><span class=\"n\">idx<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">*<\/span> <span class=\"n\">hand<\/span><span class=\"p\">.<\/span><span class=\"n\">bid<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The \u201cone weird trick\u201d here is realizing you don\u2019t need to actually know what card the Jokers are pretending to be, you just need to know what effect they have on the hand. And that effect is to make it one stage better than it was!<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Now, this was a <em>fun<\/em> puzzle! I got to explore some Kotlin features I hadn\u2019t touched yet (<code>enum<\/code> and importing my own extension function from a \u2018Utils.kt` module), do a bit of math, and generally have a good time! I think I needed that. Here\u2019s to hoping I\u2019m not being lulled into a false sense of security.<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 06","pubDate":"Wed, 06 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-06-5b35","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-06-5b35","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 6 - Wait For It\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/6\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Hold, Hold, Hold Your Boat\n<\/h2>\n\n<p>Today\u2019s input is <em>really<\/em> short. Two lines, with whitespace-separated numbers being all we care about. I did try to be a <em>bit<\/em> fancy with it, but it\u2019s still very straightforward. I did make use of the ability to assign an anonymous function to a variable, which is new for me in Kotlin. A welcome break from yesterday!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>    <span class=\"cm\">\/**\n     * Class that represents one of the current distance records\n     *\n     * Each race can be represented as the time limit and the last record distance.\n     *\n     * @property time The time available to complete the race.\n     * @property distance The last record distance (we need to beat).\n     *\/<\/span>\n    <span class=\"kd\">data class<\/span> <span class=\"nc\">RaceRecord<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">time<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Double<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">distance<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Double<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n            <span class=\"cm\">\/**\n             * Parse the input from a string representing the input file\n             *\n             * Today's input is only two lines and they both mean different things, so we'll parse the\n             * input as a single string, convert each line to a list of numbers, and zip them together\n             * to make our [RaceRecord]s\n             *\/<\/span>\n            <span class=\"k\">fun<\/span> <span class=\"nf\">parseInput<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">RaceRecord<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">toDoubleOrThrow<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">Double<\/span> <span class=\"p\">=<\/span> <span class=\"p\">{<\/span> <span class=\"n\">n<\/span> <span class=\"p\">-&gt;<\/span>\n                    <span class=\"n\">n<\/span><span class=\"p\">.<\/span><span class=\"nf\">toDoubleOrNull<\/span><span class=\"p\">()<\/span>\n                            <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$n cannot be parsed to a Double!\"<\/span><span class=\"p\">)<\/span>\n                <span class=\"p\">}<\/span>\n\n                <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">raceTimes<\/span><span class=\"p\">,<\/span> <span class=\"py\">raceDistances<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span>\n                        <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">().<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\n\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">line<\/span> <span class=\"p\">-&gt;<\/span>\n                            <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">replaceFirst<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\w+:\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">(),<\/span> <span class=\"s\">\"\"<\/span><span class=\"p\">)<\/span>\n                                    <span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">()<\/span>\n                                    <span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\s+\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">())<\/span>\n                                    <span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"n\">toDoubleOrThrow<\/span><span class=\"p\">)<\/span>\n                        <span class=\"p\">}<\/span>\n\n                <span class=\"k\">return<\/span> <span class=\"n\">raceTimes<\/span><span class=\"p\">.<\/span><span class=\"nf\">zip<\/span><span class=\"p\">(<\/span><span class=\"n\">raceDistances<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">time<\/span><span class=\"p\">,<\/span> <span class=\"n\">distance<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nc\">RaceRecord<\/span><span class=\"p\">(<\/span><span class=\"n\">time<\/span><span class=\"p\">,<\/span> <span class=\"n\">distance<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"kd\">class<\/span> <span class=\"nc\">Day06<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ One string to one list. Piece of cake.<\/span>\n        <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">RaceRecord<\/span><span class=\"p\">.<\/span><span class=\"nf\">parseInput<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We\u2019ve seen a pattern of alternating difficulty levels on puzzles so far this year, and today seems to be no exception.<\/p>\n\n<h2>\n  \n  \n  Part One - We\u2019re Going Quadratic!\n<\/h2>\n\n<p>Do you ever get that feeling when you\u2019re reading a problem statement that there\u2019s_probably_ some easy way to solve it if you just used math? Sometimes I get that feeling, and it <em>really<\/em> grinds my gears because I can\u2019t figure out <em>what<\/em> the math is. And sometimes, the math reveals itself. Today, the math came through! Here in part one, we need to figure out how many ways we can win a boat race based on how long we need to charge up the boat.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n    <span class=\"c1\">\/\/ My first imports!<\/span>\n    <span class=\"k\">import<\/span> <span class=\"nn\">kotlin.math.ceil<\/span>\n    <span class=\"k\">import<\/span> <span class=\"nn\">kotlin.math.floor<\/span>\n    <span class=\"k\">import<\/span> <span class=\"nn\">kotlin.math.sqrt<\/span>\n\n    <span class=\"kd\">data class<\/span> <span class=\"nc\">RaceRecord<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">time<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Double<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">distance<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Double<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n        <span class=\"cm\">\/**\n         * Return the number of different ways we can win the race!\n         *\n         * @ return An Int indicating just how many different hold times will get us\n         * the winning distance.\n         *\/<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">countWinningStrategies<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ For: Hold Time -&gt; h; Race Time -&gt; t; Distance to Beat -&gt; d<\/span>\n            <span class=\"c1\">\/\/ We can derive a formula for beating the previous record as:<\/span>\n            <span class=\"c1\">\/\/ - (t - h) * h &gt; d<\/span>\n            <span class=\"c1\">\/\/<\/span>\n            <span class=\"c1\">\/\/ Which rearranges to: (-1)*h^2 + (t * h) - d &gt; 0<\/span>\n            <span class=\"c1\">\/\/ Now, that there is a quadratic expression! You know, the old<\/span>\n            <span class=\"c1\">\/\/ `ax^2 + bx + c = 0`? We can solve it like:<\/span>\n            <span class=\"c1\">\/\/ h = (-t +\/- sqrt(t^2 - 4 * (-1) * (-d))) \/ 2 * (-1)<\/span>\n            <span class=\"c1\">\/\/<\/span>\n            <span class=\"c1\">\/\/ That's math! The 'tricky' part is that we don't want to know the _exact_<\/span>\n            <span class=\"c1\">\/\/ hold time to _equal_ the previous record, we want to know the smallest<\/span>\n            <span class=\"c1\">\/\/ and largest hold times that will _beat_ the record. For that, we round<\/span>\n            <span class=\"c1\">\/\/ _away_ from the mean possible hold time and then adjust our value towards<\/span>\n            <span class=\"c1\">\/\/ the mean by 1. For example, the results of this formula for the first<\/span>\n            <span class=\"c1\">\/\/ example race (7ms, 9mm) indicate that you could travel the 9mm by holding<\/span>\n            <span class=\"c1\">\/\/ the button for 1.697ms or 5.303ms. The minimum number of whole milliseconds,<\/span>\n            <span class=\"c1\">\/\/ then is `floor(1.697) + 1` and the maximum is `ceil(5.303) - 1`. This<\/span>\n            <span class=\"c1\">\/\/ correctly handles cases where the exact time is an integer as well.<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">sqrtFormulaPart<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">sqrt<\/span><span class=\"p\">((<\/span><span class=\"n\">time<\/span> <span class=\"p\">*<\/span> <span class=\"n\">time<\/span><span class=\"p\">)<\/span> <span class=\"p\">-<\/span> <span class=\"p\">(<\/span><span class=\"mi\">4<\/span> <span class=\"p\">*<\/span> <span class=\"n\">distance<\/span><span class=\"p\">))<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">minWinningHold<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">floor<\/span><span class=\"p\">((-<\/span><span class=\"n\">time<\/span> <span class=\"p\">+<\/span> <span class=\"n\">sqrtFormulaPart<\/span><span class=\"p\">)<\/span> <span class=\"p\">\/<\/span> <span class=\"p\">-<\/span><span class=\"mi\">2<\/span><span class=\"p\">).<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">maxWinningHold<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">ceil<\/span><span class=\"p\">((-<\/span><span class=\"n\">time<\/span> <span class=\"p\">-<\/span> <span class=\"n\">sqrtFormulaPart<\/span><span class=\"p\">)<\/span> <span class=\"p\">\/<\/span> <span class=\"p\">-<\/span><span class=\"mi\">2<\/span><span class=\"p\">).<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span>\n\n            <span class=\"c1\">\/\/ The total number of winning holds is the length of the inclusive range<\/span>\n            <span class=\"c1\">\/\/ of all possible winning holds.<\/span>\n            <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">maxWinningHold<\/span> <span class=\"p\">-<\/span> <span class=\"n\">minWinningHold<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"kd\">class<\/span> <span class=\"nc\">Day06<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ One string to one list. Piece of cake.<\/span>\n        <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n        <span class=\"c1\">\/\/ In part 1, we calculate all our winning hold times and return<\/span>\n        <span class=\"c1\">\/\/ the product of that count from each race.<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span>\n          <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">countWinningStrategies<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n          <span class=\"p\">.<\/span><span class=\"nf\">reduce<\/span> <span class=\"p\">{<\/span> <span class=\"n\">acc<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">acc<\/span> <span class=\"p\">*<\/span> <span class=\"n\">n<\/span> <span class=\"p\">}<\/span>\n\n    <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Yay, math!<\/p>\n\n<h2>\n  \n  \n  Part Two - Kerning for Dummies\n<\/h2>\n\n<p>You know, one of these days, we\u2019re going to stop and take a second look at an input <em>before<\/em> we start writing code. Of course, that would take half the fun out of solving these puzzles, so there\u2019s that. Turns out, there\u2019s only one race, so we just need to figure out how many ways we can win that one.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n    <span class=\"kd\">data class<\/span> <span class=\"nc\">RaceRecord<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">time<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Double<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">distance<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Double<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n        <span class=\"c1\">\/\/ fun countWinningStrategies(): Int { ... }<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"kd\">class<\/span> <span class=\"nc\">Day06<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ One string to one list. Piece of cake.<\/span>\n        <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n        <span class=\"c1\">\/\/ In part 1, we calculate all our winning hold times and return<\/span>\n        <span class=\"c1\">\/\/ the product of that count from each race.<\/span>\n        <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n        <span class=\"c1\">\/\/ In part 2, we learn what 'kerning' is and get mad about it. Then<\/span>\n        <span class=\"c1\">\/\/ we concatenate all the race times\/records into one and figure how<\/span>\n        <span class=\"c1\">\/\/ how many ways we can win that one race.<\/span>\n        <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">uberRaceTime<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">joinToString<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\"<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">().<\/span><span class=\"nf\">toString<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">toDouble<\/span><span class=\"p\">()<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">uberDistance<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">joinToString<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\"<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">distance<\/span><span class=\"p\">.<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">().<\/span><span class=\"nf\">toString<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">toDouble<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">RaceRecord<\/span><span class=\"p\">(<\/span><span class=\"n\">uberRaceTime<\/span><span class=\"p\">,<\/span> <span class=\"n\">uberDistance<\/span><span class=\"p\">).<\/span><span class=\"nf\">countWinningStrategies<\/span><span class=\"p\">()<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Yep, the same math works for part 2!<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Well, well, well, here we are again with a lighter day. I don\u2019t have too much to say about today\u2019s puzzle, probably because I\u2019m still recovering from yesterday. I do appreciate the opportunity to get caught back up, though, which is nice. Let\u2019s all enjoy this lighter day, and get ready for the fresh trial that the next odd-numbered day is likely to bring!<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 05","pubDate":"Tue, 05 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-05-5ap","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-05-5ap","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 5 - If You Give A Seed A Fertilizer\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/5\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - It\u2019s Honest Work\n<\/h2>\n\n<p>\u201cAdvent of Parsing\u201d indeed! This was the first day I got to break out my<code>resourceAsLineChunks()<\/code> file reading function, though, which is pretty cool. As you might have guessed, today\u2019s input takes a hefty amount of parsing to get it into shape. The heavy lifting is the <code>Map<\/code> used to trace one resource number\/range to another, and it is a bit gnarly.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code>\n<span class=\"c1\">\/\/ This is a bit of a complicated type. Essentially, we are representing one<\/span>\n<span class=\"c1\">\/\/ translation from one resource type to another. For example, to the mapping of<\/span>\n<span class=\"c1\">\/\/ the 'seed-to-soil' group from the example:<\/span>\n<span class=\"c1\">\/\/<\/span>\n<span class=\"c1\">\/\/ seed-to-soil map:<\/span>\n<span class=\"c1\">\/\/ 50 98 2<\/span>\n<span class=\"c1\">\/\/ 52 50 48<\/span>\n<span class=\"c1\">\/\/<\/span>\n<span class=\"c1\">\/\/ is represented as (\"seed\", (\"soil\", [(98..99, -48), (50..97, 2)])). This makes<\/span>\n<span class=\"c1\">\/\/ it a bit easier to use in the code below, as the list of them can be easily<\/span>\n<span class=\"c1\">\/\/ converted to a HashMap.<\/span>\n<span class=\"k\">typealias<\/span> <span class=\"nc\">ResourceRangeTranslationGroup<\/span> <span class=\"p\">=<\/span> \n  <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">LongRange<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;&gt;&gt;<\/span>\n\n<span class=\"cm\">\/**\n * This class represents the contents of the elf's Almanac\n *\n * @property seeds A list of the seed numbers in (\"seed\", &lt;seed number&gt;) format.\n * @property mappings A map used to determine what type of resource is required.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Almanac<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">seeds<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">mappings<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Map<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">LongRange<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;&gt;&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Parse the input from a list of input chunks.\n     *\n     * @param chunks A list of line chunks from the input.\n     * @return The parsed Almanac.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">fromInputChunks<\/span><span class=\"p\">(<\/span><span class=\"n\">chunks<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;):<\/span> <span class=\"nc\">Almanac<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ This bit isn't too bad. We parse the first line into a list of<\/span>\n      <span class=\"c1\">\/\/ (\"seed\", &lt;number&gt;) pairs. This is so, when we attempt to go from one<\/span>\n      <span class=\"c1\">\/\/ resource to another later on, we've tagged this number with the type<\/span>\n      <span class=\"c1\">\/\/ of resource it represents.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">seeds<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">chunks<\/span>\n          <span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">()<\/span>\n          <span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">()<\/span>\n          <span class=\"p\">.<\/span><span class=\"nf\">removePrefix<\/span><span class=\"p\">(<\/span><span class=\"s\">\"seeds: \"<\/span><span class=\"p\">)<\/span>\n          <span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\s+\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span>\n            <span class=\"kd\">val<\/span> <span class=\"py\">seedNumber<\/span> <span class=\"p\">=<\/span>\n                <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLongOrNull<\/span><span class=\"p\">()<\/span> <span class=\"o\">?:<\/span> \n                  <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$it cannot be parsed to Long!\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"s\">\"seed\"<\/span> <span class=\"n\">to<\/span> <span class=\"n\">seedNumber<\/span>\n          <span class=\"p\">}<\/span>\n\n      <span class=\"c1\">\/\/ Parsing the \"x-to-y map\" chunks was a bit involved, so I've moved<\/span>\n      <span class=\"c1\">\/\/ that logic to its own function.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">mappings<\/span> <span class=\"p\">=<\/span> <span class=\"n\">chunks<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">drop<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"nf\">parseChunk<\/span><span class=\"p\">(<\/span><span class=\"n\">it<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">toMap<\/span><span class=\"p\">()<\/span>\n\n      <span class=\"k\">return<\/span> <span class=\"nc\">Almanac<\/span><span class=\"p\">(<\/span><span class=\"n\">seeds<\/span><span class=\"p\">,<\/span> <span class=\"n\">mappings<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"cm\">\/**\n     * Parse one chunk of the input file\n     *\n     * This is where we're using the gnarly type alias defined at the top. The \n     * idea is to produce a list that can be converted to a Map that can be used \n     * to look up, for each resource, what numbers for the next resource it needs.\n     *\n     * @param lines The input lines for one chunk of the input file.\n     * @return An object that can become an entry in the [Almanac.mappings] map.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">parseChunk<\/span><span class=\"p\">(<\/span><span class=\"n\">lines<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;):<\/span> <span class=\"nc\">ResourceRangeTranslationGroup<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ Get which resource types we're dealing with.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">sourceType<\/span><span class=\"p\">,<\/span> <span class=\"py\">targetType<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">lines<\/span><span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">().<\/span><span class=\"nf\">removeSuffix<\/span><span class=\"p\">(<\/span><span class=\"s\">\" map:\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"-to-\"<\/span><span class=\"p\">)<\/span>\n\n      <span class=\"c1\">\/\/ For each subsequent line in the chunk, we extract two pieces of information:<\/span>\n      <span class=\"c1\">\/\/ 1. The range of the source resource<\/span>\n      <span class=\"c1\">\/\/ 2. The magnitude of the offset of the destination resource range from <\/span>\n      <span class=\"c1\">\/\/ the source range. This works because the source range and destination <\/span>\n      <span class=\"c1\">\/\/ ranges are constrained to be the same size by the input.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">rangeMappings<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">lines<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">drop<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">line<\/span> <span class=\"p\">-&gt;<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">destinationRangeStart<\/span><span class=\"p\">,<\/span> <span class=\"py\">sourceRangeStart<\/span><span class=\"p\">,<\/span> <span class=\"py\">rangeLength<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span>\n                    <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\s+\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span>\n                      <span class=\"c1\">\/\/ Yes, I'm being paranoid.<\/span>\n                      <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLongOrNull<\/span><span class=\"p\">()<\/span>\n                          <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$it cannot be parsed to Long!\"<\/span><span class=\"p\">)<\/span>\n                    <span class=\"p\">}<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">sourceRange<\/span> <span class=\"p\">=<\/span> <span class=\"n\">sourceRangeStart<\/span> <span class=\"nf\">until<\/span> <span class=\"p\">(<\/span><span class=\"n\">sourceRangeStart<\/span> <span class=\"p\">+<\/span> <span class=\"n\">rangeLength<\/span><span class=\"p\">)<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">rangeShift<\/span> <span class=\"p\">=<\/span> <span class=\"n\">destinationRangeStart<\/span> <span class=\"p\">-<\/span> <span class=\"n\">sourceRangeStart<\/span>\n                <span class=\"n\">sourceRange<\/span> <span class=\"n\">to<\/span> <span class=\"n\">rangeShift<\/span> <span class=\"c1\">\/\/ Pair&lt;LongRange, Long&gt;<\/span>\n              <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">sortedBy<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"p\">}<\/span>\n      <span class=\"k\">return<\/span> <span class=\"n\">sourceType<\/span> <span class=\"nf\">to<\/span> <span class=\"p\">(<\/span><span class=\"n\">targetType<\/span> <span class=\"n\">to<\/span> <span class=\"n\">rangeMappings<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day05<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ And this was the easy part...<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Almanac<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromInputChunks<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Yes, I\u2019m serious. That was the easy part. Well, in hindsight, now that I know all the edge cases and little mistakes, it\u2019s not <em>that<\/em> bad. Still, though, get ready for round 1.<\/p>\n\n<h2>\n  \n  \n  Part One - Agricultural Delivery\n<\/h2>\n\n<p>You know what? It\u2019s kind of rare that we see an elf suffering the inevitable consequences of someone <em>else\u2019s<\/em> poor design decisions. I kind of feel sorry for this guy. How is <em>anyone<\/em> supposed to map out the instructions included in this almanac? Also, who numbers seeds? Seems like a system designed to fail. Maybe the almanac sellers run a paid support plan\u2026 Well, we\u2019re here now. Time to figure out where these seeds go.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">Almanac<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">seeds<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">mappings<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Map<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">LongRange<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;&gt;&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n  <span class=\"cm\">\/**\n   * Given a resource, traces it's requirements all the way to a location\n   *\n   * This is why I'm tagging the resource numbers like (\"seed\", 1). So I can \n   * pass that pair to this function and have it recursively search through the \n   * [Almanac] until the corresponding location is found.\n   *\n   * @param resource A pair of (\"resource type\", &lt;number&gt;) to find the location for.\n   * @return A pair of (\"location\", &lt;location number&gt;)\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceToLocation<\/span><span class=\"p\">(<\/span><span class=\"n\">resource<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;):<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">type<\/span><span class=\"p\">,<\/span> <span class=\"py\">id<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">resource<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">type<\/span> <span class=\"p\">==<\/span> <span class=\"s\">\"location\"<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"n\">resource<\/span>\n\n    <span class=\"c1\">\/\/ Get the mappings of source type ranges to destination type ranges<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">destinationType<\/span><span class=\"p\">,<\/span> <span class=\"py\">possibleDestinations<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">mappings<\/span><span class=\"p\">.<\/span><span class=\"k\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">type<\/span><span class=\"p\">)<\/span>\n            <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Could not find a destination for $type.\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\">\/\/ If there is a matching mapping, then map the source number to the<\/span>\n    <span class=\"c1\">\/\/ destination number and return it.<\/span>\n    <span class=\"k\">try<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">destination<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">possibleDestinations<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">range<\/span><span class=\"p\">,<\/span> <span class=\"n\">_<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">id<\/span> <span class=\"k\">in<\/span> <span class=\"n\">range<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">offset<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">id<\/span> <span class=\"p\">+<\/span> <span class=\"n\">offset<\/span> <span class=\"p\">}<\/span>\n              <span class=\"p\">.<\/span><span class=\"nf\">single<\/span><span class=\"p\">()<\/span>\n      <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">resourceToLocation<\/span><span class=\"p\">(<\/span><span class=\"n\">destinationType<\/span> <span class=\"n\">to<\/span> <span class=\"n\">destination<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">catch<\/span> <span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ If there is no mapping, then we know that the destination number<\/span>\n      <span class=\"c1\">\/\/ is the same as the source number.<\/span>\n      <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">resourceToLocation<\/span><span class=\"p\">(<\/span><span class=\"n\">destinationType<\/span> <span class=\"n\">to<\/span> <span class=\"n\">id<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day05<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ Told you this was the easy part.<\/span>\n  <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n  <span class=\"c1\">\/\/ In part one, we have a few seeds to follow all the way to their<\/span>\n  <span class=\"c1\">\/\/ ideal planting locations. Easy enough.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">=<\/span>\n      <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"n\">seeds<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">resourceToLocation<\/span><span class=\"p\">(<\/span><span class=\"n\">it<\/span><span class=\"p\">)<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">minOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">id<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">id<\/span> <span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Ok, fine, that wasn\u2019t <em>too<\/em> bad. But wait, there\u2019s more!<\/p>\n\n<h2>\n  \n  \n  Part Two - Sow, Sow Many\n<\/h2>\n\n<p>I seriously doubt the elf has access to the literal <em>billions<\/em> of <em>unique<\/em> seeds indicated by this almanac. Not to mention all those unique locations! How big is this island, anyway. Not that big, that\u2019s for sure. In part two, it seems we\u2019ve once again misinterpreted plain text and the seed \u201cnumbers\u201d are seed number \u201cranges\u201d. We still need to find the closest location (which kind of makes sense, some of these are probably in outer space), though, but individually tracing each seed to its location isn\u2019t going to cut it.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">Almanac<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">seeds<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">mappings<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Map<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">LongRange<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Long<\/span><span class=\"p\">&gt;&gt;&gt;&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n  <span class=\"c1\">\/\/ fun resourceToLocation(resource: Pair&lt;String, Long&gt;): Pair&lt;String, Long&gt; { ... }<\/span>\n\n  <span class=\"cm\">\/**\n   * Given a range of resource numbers, return all the possible location ranges\n   *\n   * In Part 2, the numbers are just too big for us to map each seed to its \n   * location individually. Instead, we need to map the resources by the entire \n   * range. The catch here is that the input range won't always slot neatly \n   * inside an output range and may instead encompass several ranges.\n   * For that reason, we return a list of (\"resource type\", &lt;range&gt;) pairs.\n   *\n   * @param resourceRange A pair of (\"resource type\", &lt;range&gt;) to find location \n   * ranges for.\n   * @return A list of all the location ranges the input range maps to.\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceRangeToLocationRanges<\/span><span class=\"p\">(<\/span>\n      <span class=\"n\">resourceRange<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">LongRange<\/span><span class=\"p\">&gt;<\/span>\n  <span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"nc\">LongRange<\/span><span class=\"p\">&gt;&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">type<\/span><span class=\"p\">,<\/span> <span class=\"py\">sourceRange<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">resourceRange<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">type<\/span> <span class=\"p\">==<\/span> <span class=\"s\">\"location\"<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span><span class=\"n\">resourceRange<\/span><span class=\"p\">)<\/span> <span class=\"c1\">\/\/ Base case<\/span>\n\n    <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">destinationType<\/span><span class=\"p\">,<\/span> <span class=\"py\">possibleDestinations<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">mappings<\/span><span class=\"p\">.<\/span><span class=\"k\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">type<\/span><span class=\"p\">)<\/span>\n            <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Could not find a destination for $type.\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\">\/\/ Still paranoid<\/span>\n\n    <span class=\"c1\">\/\/ This will house all the destination ranges we find.<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">destinationRanges<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">LongRange<\/span><span class=\"p\">&gt;()<\/span>\n\n    <span class=\"c1\">\/\/ If the `sourceRange` starts before the first `possibleDestinationRange`, <\/span>\n    <span class=\"c1\">\/\/ then we need to add that non-overlapping part to the destinations as-is<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">firstPossibleDestinationRange<\/span><span class=\"p\">,<\/span> <span class=\"py\">_<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">possibleDestinations<\/span><span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"p\">&lt;<\/span> <span class=\"n\">firstPossibleDestinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">prefixRangeEnd<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">minOf<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> \n        <span class=\"n\">firstPossibleDestinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span>\n      <span class=\"p\">)<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">prefixRange<\/span> <span class=\"p\">=<\/span> <span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"n\">until<\/span> <span class=\"n\">prefixRangeEnd<\/span>\n      <span class=\"n\">destinationRanges<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">prefixRange<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ Now, check over all the `possibleDestinations` and, for every destinationRange<\/span>\n    <span class=\"c1\">\/\/ that overlaps `range`, apply the offset to the overlapping portion of `range`<\/span>\n    <span class=\"c1\">\/\/ and add it to the destinations<\/span>\n    <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">destinationRange<\/span><span class=\"p\">,<\/span> <span class=\"n\">destinationOffset<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span>\n        <span class=\"n\">possibleDestinations<\/span><span class=\"p\">.<\/span><span class=\"nf\">sortedBy<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"p\">})<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"p\">&lt;=<\/span> <span class=\"n\">destinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span> <span class=\"p\">&amp;&amp;<\/span>\n              <span class=\"n\">destinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"p\">&lt;=<\/span> <span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span>\n      <span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">overlappingRangeStart<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">maxOf<\/span><span class=\"p\">(<\/span><span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">,<\/span> <span class=\"n\">destinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">overlappingRangeEnd<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">minOf<\/span><span class=\"p\">(<\/span>\n          <span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span><span class=\"p\">,<\/span> \n          <span class=\"n\">destinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span>\n        <span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">overlappingRange<\/span> <span class=\"p\">=<\/span>\n            <span class=\"p\">(<\/span><span class=\"n\">overlappingRangeStart<\/span> <span class=\"p\">+<\/span> <span class=\"n\">destinationOffset<\/span><span class=\"p\">)<\/span> <span class=\"nf\">until<\/span>\n                <span class=\"p\">(<\/span><span class=\"n\">overlappingRangeEnd<\/span> <span class=\"p\">+<\/span> <span class=\"n\">destinationOffset<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">destinationRanges<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">overlappingRange<\/span><span class=\"p\">)<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ Finally, if `sourceRange` extends past the end of the last `destinationRange`,<\/span>\n    <span class=\"c1\">\/\/ then we need to add that non-overlapping part to the destinations as-is.<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"p\">(<\/span><span class=\"py\">lastPossibleDestinationRange<\/span><span class=\"p\">,<\/span> <span class=\"py\">_<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">possibleDestinations<\/span><span class=\"p\">.<\/span><span class=\"nf\">last<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span> <span class=\"p\">&gt;<\/span> <span class=\"n\">lastPossibleDestinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">suffixRangeStart<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">maxOf<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">,<\/span> \n        <span class=\"n\">lastPossibleDestinationRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span>\n      <span class=\"p\">)<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">suffixRange<\/span> <span class=\"p\">=<\/span> <span class=\"n\">suffixRangeStart<\/span> <span class=\"n\">until<\/span> <span class=\"n\">sourceRange<\/span><span class=\"p\">.<\/span><span class=\"n\">endInclusive<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span>\n      <span class=\"n\">destinationRanges<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">suffixRange<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ Now with our list of destination ranges, we need to recursively search<\/span>\n    <span class=\"c1\">\/\/ for the ranges of the final locations.<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">destinationRanges<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">resourceRangeToLocationRanges<\/span><span class=\"p\">(<\/span><span class=\"n\">destinationType<\/span> <span class=\"n\">to<\/span> <span class=\"n\">it<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">flatten<\/span><span class=\"p\">()<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day05<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ Told you this was the easy part.<\/span>\n  <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n  <span class=\"c1\">\/\/ How you like me now?<\/span>\n  <span class=\"c1\">\/\/ fun solvePart1(): Long = ...<\/span>\n\n  <span class=\"c1\">\/\/ In part two, we have a _tremendous_ number of seeds to track down.<\/span>\n  <span class=\"c1\">\/\/ Instead, we need to keep track of ranges of numbers to finish in a<\/span>\n  <span class=\"c1\">\/\/ reasonable amount of time.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Long<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Convert the seed numbers to ranges as specified in the puzzle text.<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">seedRanges<\/span> <span class=\"p\">=<\/span>\n        <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"n\">seeds<\/span><span class=\"p\">.<\/span><span class=\"nf\">chunked<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">first<\/span><span class=\"p\">,<\/span> <span class=\"n\">second<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span>\n          <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">_<\/span><span class=\"p\">,<\/span> <span class=\"py\">rangeStart<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">first<\/span>\n          <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">_<\/span><span class=\"p\">,<\/span> <span class=\"py\">rangeLength<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">second<\/span>\n          <span class=\"s\">\"seed\"<\/span> <span class=\"nf\">to<\/span> <span class=\"p\">(<\/span><span class=\"n\">rangeStart<\/span> <span class=\"nf\">until<\/span> <span class=\"p\">(<\/span><span class=\"n\">rangeStart<\/span> <span class=\"p\">+<\/span> <span class=\"n\">rangeLength<\/span><span class=\"p\">))<\/span>\n        <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ For all the possible location ranges, find the smallest possible location.<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">seedRanges<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">seedRange<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">resourceRangeToLocationRanges<\/span><span class=\"p\">(<\/span><span class=\"n\">seedRange<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">flatten<\/span><span class=\"p\">()<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">minOf<\/span> <span class=\"p\">{<\/span> <span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">range<\/span><span class=\"p\">)<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">range<\/span><span class=\"p\">.<\/span><span class=\"n\">start<\/span> <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Yes, <em>of course<\/em> I tried searching the seeds one at a time. What do you take me for? No, it didn\u2019t work. I exceeded the JVM\u2019s memory allocation. I could have_probably_ worked around that, but the algorithm change seemed like the right idea.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>That was Day <strong>5<\/strong>!? I checked, and last year Day 5 was the crate-moving day. And yes, while that <em>did<\/em> require a bit of tricky parsing (assuming you didn\u2019t just hard-code the input), the algorithm bit was simplicity itself. And that took me around 260 lines of <em>Rust<\/em> code (which is heckin\u2019 verbose) compared to today\u2019s 222 lines of Kotlin code. That probably doesn\u2019t seem like a bad comparison, but you have to remember that Rust tends to have a <em>lot<\/em> (relatively) of boilerplate. Strip all the comments, and it might even be <em>less<\/em> Rust code. Typically, by this point, I\u2019d expect either a bit of a tougher parse or a bit of a trickier algorithm, but today was a double whammy. Now, I\u2019m not complaining, mind you, I enjoy a good challenge. Given how the last few days have gone, though, I\u2019m starting to get a bit concerned for my sleep schedule! We\u2019ll see what Day 6 has in store.<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 04","pubDate":"Mon, 04 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-04-jnk","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-04-jnk","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 4 - Scratchcards\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/4\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Scratching the Itch\n<\/h2>\n\n<p>Today\u2019s elf friend seems to have a bit of a problem\u2026 Which is that his \u201cfriends\u201d decided that a big pile of scratchcards would make an appropriate gift. I\u2019m not judging, but it looks like it\u2019s put our elf friend to a lot of effort for dubious reward. Regardless, our first job is to translate this text into something representing these scratchers, so here we go!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"cm\">\/**\n * This class represents one of the elf's scratchcards\n *\n * @property id The id number assigned to this card.\n * @property luckyNumbers The winning scratchard numbers.\n * @property myNumbers The numbers revealed for the elf.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Card<\/span> <span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">id<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">matches<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Parses a [Card] from a String\n     *\n     * @param input The string to be parsed.\n     * @return A [Card] represented by the input.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Card<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ Split a string like \"Card 1: 1 2 | 2 3 4\" into [\"Card 1\", \"1 2\", \"2 3 4\"]<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">parts<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"[:|]\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n      <span class=\"nf\">require<\/span><span class=\"p\">(<\/span><span class=\"n\">parts<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"$input cannot be parsed to a [Card]!\"<\/span> <span class=\"p\">}<\/span>\n\n      <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">cardPart<\/span><span class=\"p\">,<\/span> <span class=\"py\">luckyNumbersPart<\/span><span class=\"p\">,<\/span> <span class=\"py\">myNumbersPart<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parts<\/span>\n\n      <span class=\"c1\">\/\/ Remove the \"Card \" prefix. Note, the example only included one space<\/span>\n      <span class=\"c1\">\/\/ after \"Card\", but the real input included multiple for formatting.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">id<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">cardPart<\/span><span class=\"p\">.<\/span><span class=\"nf\">replaceFirst<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Card\\\\s+\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">(),<\/span> <span class=\"s\">\"\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">toIntOrNull<\/span><span class=\"p\">()<\/span>\n              <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$cardPart cannot be parsed to a card id!\"<\/span><span class=\"p\">)<\/span>\n\n      <span class=\"c1\">\/\/ Parse lists of space-separated numeric strings into integers.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">luckyNumbers<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">luckyNumbersPart<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\s+\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toIntOrNull<\/span><span class=\"p\">()<\/span> <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$it is not a number!\"<\/span><span class=\"p\">)<\/span>\n          <span class=\"p\">}<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">myNumbers<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">myNumbersPart<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\\\s+\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">toRegex<\/span><span class=\"p\">()).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toIntOrNull<\/span><span class=\"p\">()<\/span> <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$it is not a number!\"<\/span><span class=\"p\">)<\/span>\n          <span class=\"p\">}<\/span>\n\n      <span class=\"c1\">\/\/ Turns out, we don't care about the numbers at all. Just count how many<\/span>\n      <span class=\"c1\">\/\/ of 'myNumbers' are in `luckyNumbers' and keep track of that.`<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">matches<\/span> <span class=\"p\">=<\/span> <span class=\"n\">myNumbers<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">luckyNumbers<\/span><span class=\"p\">.<\/span><span class=\"nf\">contains<\/span><span class=\"p\">(<\/span><span class=\"n\">it<\/span><span class=\"p\">)<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">count<\/span><span class=\"p\">()<\/span>\n\n      <span class=\"k\">return<\/span> <span class=\"nc\">Card<\/span><span class=\"p\">(<\/span><span class=\"n\">id<\/span><span class=\"p\">,<\/span> <span class=\"n\">matches<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day04<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ Except for the trailing empty line, parse all the lines from<\/span>\n  <span class=\"c1\">\/\/ the input into [Card]s.<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isNotEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">Card<\/span><span class=\"o\">::<\/span><span class=\"n\">fromString<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In my original iteration, I kept the lists of numbers as well. Since it turned out we didn\u2019t really need to keep them around, I\u2019ve left them out of this final version.<\/p>\n\n<h2>\n  \n  \n  Part One - Counting Card\u2019s Value\n<\/h2>\n\n<p>Ok, looks like the reward for all these scratchcards are \u201cpoints\u201d of unspecified value. On a value-scaling basis, they\u2019re probably worth about as much as likes or upvotes, I figure. Given how precious these points are, we want to make sure we tally them correctly! Each card is worth a number of points based on how many of the revealed numbers match the winning numbers displayed on the card. Let\u2019s see how rich this elf is!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">Card<\/span> <span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">id<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">matches<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ companion object { ... }<\/span>\n\n  <span class=\"cm\">\/**\n   * Calculate the score for this card\n   *\n   * The score is 1 for a single match, doubled for every subsequent match. Mathematically, this\n   * works out to 2 ** (matches - 1) for one or more matches.\n   *\n   * @return The calculated score for this card\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">score<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Apparently, Kotlin doesn't have a \"nice\" way to exponentiate integers<\/span>\n    <span class=\"c1\">\/\/ without first casting it to a double. I don't _want_ to do type<\/span>\n    <span class=\"c1\">\/\/ conversion for exponents! So, I'm just doubling the value in a loop.<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">score<\/span> <span class=\"p\">=<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">matches<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"mi\">0<\/span> <span class=\"k\">else<\/span> <span class=\"mi\">1<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">matches<\/span> <span class=\"p\">&gt;<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nf\">repeat<\/span><span class=\"p\">(<\/span><span class=\"n\">matches<\/span> <span class=\"p\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"n\">score<\/span> <span class=\"p\">=<\/span> <span class=\"n\">score<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">score<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day04<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n  <span class=\"c1\">\/\/ In Part 1, we score each card and return the sum of all the scores.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">score<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now that we\u2019ve counted the elf\u2019s vast wealth (in points), we should probably figure out how to spend them!<\/p>\n\n<h2>\n  \n  \n  Part Two - The House Always Wins\n<\/h2>\n\n<p>Ah, I see, seems like we should have looked more closely at these cards. Turns out, our elf friend\u2019s fabulous prize is\u2026 more scratchcards! Not sure how this translates, but at least he should have plenty of kindling or paper m\u00e2ch\u00e9 materials. Elves are pretty crafty, so I\u2019m sure he\u2019s excited to find out just how many of these cards he\u2019s entitled to. Let\u2019s help him out.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">class<\/span> <span class=\"nc\">Day04<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ private val parsed = ...<\/span>\n\n  <span class=\"c1\">\/\/ fun solvePart1(): Int = ...<\/span>\n\n  <span class=\"c1\">\/\/ In Part 2, we re-learn that reading is key and calculate the number<\/span>\n  <span class=\"c1\">\/\/ of cards our elf friend ends up with.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Each winning card increases the number of copies of subsequent cards<\/span>\n    <span class=\"c1\">\/\/ by one. The number of matches on the winning card indicates how many<\/span>\n    <span class=\"c1\">\/\/ of the following cards we \"win\" new copies of. So, a card with four<\/span>\n    <span class=\"c1\">\/\/ matches gets us one extra copy of the next four cards. We start<\/span>\n    <span class=\"c1\">\/\/ by initializing a list of card counts. Since cards are 1-indexed,<\/span>\n    <span class=\"c1\">\/\/ we make a list a little bigger than we need and just zero the first<\/span>\n    <span class=\"c1\">\/\/ value (no \"Card 0\").<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">cardsCounted<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">MutableList<\/span><span class=\"p\">(<\/span><span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"mi\">1<\/span> <span class=\"p\">}<\/span>\n    <span class=\"n\">cardsCounted<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n\n    <span class=\"c1\">\/\/ Here, we increase subsequent cards by the number of existing cards,<\/span>\n    <span class=\"c1\">\/\/ so that 10 copies of a winning card with three matches will add ten<\/span>\n    <span class=\"c1\">\/\/ more copies to each of the following three card types.<\/span>\n    <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">forEach<\/span> <span class=\"p\">{<\/span> <span class=\"n\">card<\/span> <span class=\"p\">-&gt;<\/span>\n      <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">i<\/span> <span class=\"k\">in<\/span> <span class=\"mi\">1<\/span><span class=\"o\">..<\/span><span class=\"n\">card<\/span><span class=\"p\">.<\/span><span class=\"n\">matches<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">cardsCounted<\/span><span class=\"p\">[<\/span><span class=\"n\">card<\/span><span class=\"p\">.<\/span><span class=\"n\">id<\/span> <span class=\"p\">+<\/span> <span class=\"n\">i<\/span><span class=\"p\">]<\/span> <span class=\"p\">+=<\/span> <span class=\"n\">cardsCounted<\/span><span class=\"p\">[<\/span><span class=\"n\">card<\/span><span class=\"p\">.<\/span><span class=\"n\">id<\/span><span class=\"p\">]<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">cardsCounted<\/span><span class=\"p\">.<\/span><span class=\"nf\">sum<\/span><span class=\"p\">()<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Gotta be honest, I think I\u2019d prefer to have the points!<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>I was starting to get a bit worried after the relatively involved parsing of yesterday\u2019s input, but it seems like we\u2019re back on track in terms of relative difficulty for where we are in the calendar. I feel like I\u2019m starting to get a handle on some of the standard library stuff, although the need to call<code>.toRegex()<\/code> on my strings in order to split the input by regular expressions threw me for a bit of a loop. Other than that, though, today\u2019s puzzle seemed really straightforward. Oh, also, no integer exponentiation? Really? That seems like a bit of an odd gap. Thankfully, it\u2019s easy enough to roll your own. Probably the biggest \u2019efficiency\u2019 was adding the won cards in batches instead of one at a time, so I felt pretty good about that.<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 03","pubDate":"Sun, 03 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-03-37f","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-03-37f","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 3 - Gear Ratios\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/3\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - All The Horsepower\n<\/h2>\n\n<p>And, it looks like we\u2019ve gone right back to \u201cparsing is the puzzle\u201d for today\u2019s Advent of Code. Well, more or less. I suspect I could have shifted some of the workload out of the parsing phase, but I\u2019m kind of a fan of trying to model the inputs in such a way as to make the operations more tractable. So, here\u2019s a bunch of input parsing!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"k\">import<\/span> <span class=\"nn\">kotlin.collections.mutableMapOf<\/span>\n\n<span class=\"c1\">\/\/ There are two possible items on the schematic, either a number that<\/span>\n<span class=\"c1\">\/\/ may span multiple grid spaces, or a non-numeric character called a<\/span>\n<span class=\"c1\">\/\/ 'symbol'. Each number needs to be uniquely identified, so we can have<\/span>\n<span class=\"c1\">\/\/ numbers with duplicate values in the schematic representation below.<\/span>\n<span class=\"k\">sealed<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">SchematicItem<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">data class<\/span> <span class=\"nc\">Number<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">id<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">number<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">()<\/span>\n  <span class=\"kd\">data class<\/span> <span class=\"nc\">Symbol<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">char<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Char<\/span><span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ Convenience!<\/span>\n<span class=\"k\">typealias<\/span> <span class=\"nc\">Coordinate<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span>\n\n<span class=\"cm\">\/**\n * This class represents the engine schematic\n *\n * @property map A mapping of coordinates to schematic items\n * @property numbers A list allowing for easy iteration over numeric schematic items\n * @property symbols A list allowing for easy iteration over symbol schematic items\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">EngineSchematic<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span><span class=\"p\">:<\/span> <span class=\"nc\">MutableMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">,<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">numbers<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">symbols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Symbol<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * This factory function serves as the constructor\n     *\n     * Parses an [EngineSchematic] from the input string\n     *\n     * @param input The input string\n     * @return An [EngineSchematic] represented by the input string\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">EngineSchematic<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableMapOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">,<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">&gt;()<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">numbers<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;&gt;()<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">symbols<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Symbol<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;()<\/span>\n\n      <span class=\"c1\">\/\/ Iterate over the lines with support for skipping forward when<\/span>\n      <span class=\"c1\">\/\/ a multi-digit number is encountered.<\/span>\n      <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">line<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">trimEnd<\/span><span class=\"p\">().<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\\n\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">withIndex<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">var<\/span> <span class=\"py\">col<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n        <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"n\">col<\/span> <span class=\"p\">&lt;<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">line<\/span><span class=\"p\">[<\/span><span class=\"n\">col<\/span><span class=\"p\">])<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sc\">'.'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">col<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span> <span class=\"c1\">\/\/ Skip periods<\/span>\n            <span class=\"k\">in<\/span> <span class=\"sc\">'0'<\/span><span class=\"o\">..<\/span><span class=\"sc\">'9'<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"p\">{<\/span>\n              <span class=\"c1\">\/\/ If the current character is a numeric digit, parse the full <\/span>\n              <span class=\"c1\">\/\/ number, add it to the [map], and skip ahead to the end of the<\/span>\n              <span class=\"c1\">\/\/ number string<\/span>\n              <span class=\"kd\">var<\/span> <span class=\"py\">buffer<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">StringBuilder<\/span><span class=\"p\">()<\/span>\n              <span class=\"kd\">val<\/span> <span class=\"py\">first_col<\/span> <span class=\"p\">=<\/span> <span class=\"n\">col<\/span>\n              <span class=\"kd\">val<\/span> <span class=\"py\">id<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">row<\/span> <span class=\"p\">*<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"n\">col<\/span> <span class=\"c1\">\/\/ The ID for this number<\/span>\n              <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"n\">col<\/span> <span class=\"p\">&lt;<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"n\">line<\/span><span class=\"p\">[<\/span><span class=\"n\">col<\/span><span class=\"p\">].<\/span><span class=\"nf\">isDigit<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n                <span class=\"n\">buffer<\/span><span class=\"p\">.<\/span><span class=\"nf\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">line<\/span><span class=\"p\">[<\/span><span class=\"n\">col<\/span><span class=\"p\">])<\/span>\n                <span class=\"n\">col<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span>\n              <span class=\"p\">}<\/span>\n\n              <span class=\"c1\">\/\/ No need to check the string, we guaranteed it only contains digits<\/span>\n              <span class=\"kd\">val<\/span> <span class=\"py\">partNumber<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">(<\/span><span class=\"n\">id<\/span><span class=\"p\">,<\/span> <span class=\"n\">buffer<\/span><span class=\"p\">.<\/span><span class=\"nf\">toString<\/span><span class=\"p\">().<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">())<\/span>\n\n              <span class=\"c1\">\/\/ We'll also keep a list of numbers and the coordinates <\/span>\n              <span class=\"c1\">\/\/ associated with all the digits of that number.<\/span>\n              <span class=\"kd\">var<\/span> <span class=\"py\">numberCoords<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;()<\/span>\n              <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">digit_col<\/span> <span class=\"k\">in<\/span> <span class=\"n\">first_col<\/span> <span class=\"n\">until<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"kd\">val<\/span> <span class=\"py\">coordinate<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">digit_col<\/span><span class=\"p\">)<\/span>\n                <span class=\"n\">map<\/span><span class=\"p\">.<\/span><span class=\"nf\">put<\/span><span class=\"p\">(<\/span><span class=\"n\">coordinate<\/span><span class=\"p\">,<\/span> <span class=\"n\">partNumber<\/span><span class=\"p\">)<\/span>\n                <span class=\"n\">numberCoords<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">coordinate<\/span><span class=\"p\">)<\/span>\n              <span class=\"p\">}<\/span>\n\n              <span class=\"n\">numbers<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">partNumber<\/span> <span class=\"n\">to<\/span> <span class=\"n\">numberCoords<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n            <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"p\">{<\/span>\n              <span class=\"c1\">\/\/ Otherwise, we're dealing with a symbol. A symbol gets added to <\/span>\n              <span class=\"c1\">\/\/ the map and to the list of symbols and their coordinates.<\/span>\n              <span class=\"kd\">val<\/span> <span class=\"py\">symbol<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Symbol<\/span><span class=\"p\">(<\/span><span class=\"n\">line<\/span><span class=\"p\">[<\/span><span class=\"n\">col<\/span><span class=\"p\">])<\/span>\n              <span class=\"kd\">val<\/span> <span class=\"py\">coordinate<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n              <span class=\"n\">map<\/span><span class=\"p\">.<\/span><span class=\"nf\">put<\/span><span class=\"p\">(<\/span><span class=\"n\">coordinate<\/span><span class=\"p\">,<\/span> <span class=\"n\">symbol<\/span><span class=\"p\">)<\/span>\n              <span class=\"n\">symbols<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">symbol<\/span> <span class=\"n\">to<\/span> <span class=\"n\">coordinate<\/span><span class=\"p\">)<\/span>\n              <span class=\"n\">col<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span>\n            <span class=\"p\">}<\/span>\n          <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">}<\/span>\n\n      <span class=\"k\">return<\/span> <span class=\"nc\">EngineSchematic<\/span><span class=\"p\">(<\/span><span class=\"n\">map<\/span><span class=\"p\">,<\/span> <span class=\"n\">numbers<\/span><span class=\"p\">,<\/span> <span class=\"n\">symbols<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day03<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ The real work is done here<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">schematic<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">EngineSchematic<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That\u2019s kind of a lot of parsing for Day 3, but the gist of it is that we end up with a data structure that maps all the \u201cfilled\u201d grid coordinates to either the number of symbol found there and contains lists of both the numbers and symbols associated with their coordinates for efficient iteration of either.<\/p>\n\n<h2>\n  \n  \n  Part One - When is a Number not a Number?\n<\/h2>\n\n<p>When it\u2019s apart! Ok, fine, that wasn\u2019t a good joke. I couldn\u2019t help myself. In_part_ 1 of today\u2019s puzzle (fine, I\u2019ll stop), we are tasked with reviewing a gondola schematic and deciding which numbers are real-life part numbers and which ones we can safely ignore. The part numbers are all adjacent (counting diagonally) to \u201csymbols\u201d on the schematic which likely represent some sort of fancy widget or dongle or somesuch. Doesn\u2019t matter to us, though, we\u2019re all about those numbers!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">EngineSchematic<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span><span class=\"p\">:<\/span> <span class=\"nc\">MutableMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">,<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">numbers<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">symbols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Symbol<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ companion_object { ... }<\/span>\n\n  <span class=\"cm\">\/**\n   * Extract the true part numbers from the schematic\n   *\n   * Just because there's a number in the schematic doesn't mean it's a \n   * _part_ number. Which is weird. A real part number is adjacent to a symbol. \n   * This function checks around each number for a symbol and returns all \n   * [SchematicItem.Number]s with an adjacent symbol.\n   *\n   * @return A list of [SchematicItem.Number] objects\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">partNumbers<\/span><span class=\"p\">():<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">offsets<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span>\n      <span class=\"p\">-<\/span><span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span> <span class=\"n\">to<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> \n       <span class=\"mi\">0<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">1<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">partNumbers<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">&gt;()<\/span>\n\n    <span class=\"c1\">\/\/ For each number\/list of coordinates pair in the [numbers] list,<\/span>\n    <span class=\"c1\">\/\/ check all around the number for a symbol. Technically, we're<\/span>\n    <span class=\"c1\">\/\/ re-checking several indices for numbers with multiple digits.<\/span>\n    <span class=\"c1\">\/\/ It's possible to keep track of coordinates checked, but I'm not<\/span>\n    <span class=\"c1\">\/\/ convinced it's worth the extra effort.<\/span>\n    <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">number<\/span><span class=\"p\">,<\/span> <span class=\"n\">coordinates<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">numbers<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nd\">number@<\/span> <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">coordinate<\/span> <span class=\"k\">in<\/span> <span class=\"n\">coordinates<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">offset<\/span> <span class=\"k\">in<\/span> <span class=\"n\">offsets<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"c1\">\/\/ Get the neighboring coordinate to check<\/span>\n          <span class=\"kd\">val<\/span> <span class=\"py\">row<\/span> <span class=\"p\">=<\/span> <span class=\"n\">coordinate<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span> <span class=\"p\">+<\/span> <span class=\"n\">offset<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span>\n          <span class=\"kd\">val<\/span> <span class=\"py\">col<\/span> <span class=\"p\">=<\/span> <span class=\"n\">coordinate<\/span><span class=\"p\">.<\/span><span class=\"n\">second<\/span> <span class=\"p\">+<\/span> <span class=\"n\">offset<\/span><span class=\"p\">.<\/span><span class=\"n\">second<\/span>\n          <span class=\"kd\">val<\/span> <span class=\"py\">checkAt<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n\n          <span class=\"c1\">\/\/ If there's a value at that coordinate and that value is<\/span>\n          <span class=\"c1\">\/\/ a [SchematicItem.Symbol], then this number really is<\/span>\n          <span class=\"c1\">\/\/ a part number! Add it to our list and move on.<\/span>\n          <span class=\"kd\">val<\/span> <span class=\"py\">maybeSymbol<\/span> <span class=\"p\">=<\/span> <span class=\"n\">map<\/span><span class=\"p\">.<\/span><span class=\"k\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">checkAt<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span><span class=\"p\">?<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Symbol<\/span>\n          <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">maybeSymbol<\/span> <span class=\"p\">!=<\/span> <span class=\"k\">null<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">partNumbers<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">number<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">break<\/span><span class=\"nd\">@number<\/span>\n          <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">partNumbers<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day03<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ The real work is done here<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">schematic<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">EngineSchematic<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n  <span class=\"c1\">\/\/ In part one, we figure out which numbers really represent parts<\/span>\n  <span class=\"c1\">\/\/ and return the sum of all of them.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">schematic<\/span><span class=\"p\">.<\/span><span class=\"nf\">partNumbers<\/span><span class=\"p\">().<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">number<\/span> <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>There we go, not too stressful. Just check around each number for a symbol, and if we find one then it\u2019s a part number. The tricky bit is that each number may take up more than one space on the grid. It might <em>also<\/em> be adjacent to more than one symbol (a quick scan of my input doesn\u2019t reveal any, but I\u2019m too paranoid to trust that). So, we need to make sure we consider each digit of each number and include or reject it only once.<\/p>\n\n<h2>\n  \n  \n  Part Two - That\u2019s What Grinds My Gears\n<\/h2>\n\n<p>You know, I had a feeling that it <em>would<\/em> actually matter what those symbols meant eventually. Sure enough, any \u2018*\u2019 that\u2019s adjacent to two (and only two) numbers is a gear, and we kind of need to know what those numbers are so we can calculate the gear ratio. Also, I\u2019m pretty sure that\u2019s not how most people use the term \u201cgear ratio\u201d, but what do I know?<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">EngineSchematic<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">constructor<\/span><span class=\"p\">(<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">map<\/span><span class=\"p\">:<\/span> <span class=\"nc\">MutableMap<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">,<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">numbers<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span><span class=\"p\">,<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;&gt;,<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">symbols<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Pair<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Symbol<\/span><span class=\"p\">,<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">&gt;&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ companion_object { ... }<\/span>\n\n  <span class=\"c1\">\/\/ fun partNumbers(): List&lt;SchematicItem.Number&gt; { ... }<\/span>\n\n  <span class=\"cm\">\/**\n   * Calculate and return all gear ratios in the schematic\n   *\n   * Some symbols are gears. Each gear is associated with two numbers, and the \n   * 'gear ratio' is the product of those two numbers.\n   *\n   * @return A list of all gear ratios represeted on the schematic\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">gearRatios<\/span><span class=\"p\">():<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">offsets<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">listOf<\/span><span class=\"p\">(<\/span>\n      <span class=\"p\">-<\/span><span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span> <span class=\"n\">to<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> \n       <span class=\"mi\">0<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"p\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span> <span class=\"n\">to<\/span> <span class=\"mi\">1<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">ratios<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableListOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;()<\/span>\n\n    <span class=\"c1\">\/\/ For each symbol\/coordinate pair in the symbols list, check around that<\/span>\n    <span class=\"c1\">\/\/ symbol for exactly two numbers. If two numbers are found, add their<\/span>\n    <span class=\"c1\">\/\/ product to the gear ratio list.<\/span>\n    <span class=\"nd\">symbol@<\/span> <span class=\"k\">for<\/span> <span class=\"p\">((<\/span><span class=\"n\">symbol<\/span><span class=\"p\">,<\/span> <span class=\"n\">coordinate<\/span><span class=\"p\">)<\/span> <span class=\"k\">in<\/span> <span class=\"n\">symbols<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">symbol<\/span><span class=\"p\">.<\/span><span class=\"n\">char<\/span> <span class=\"p\">!=<\/span> <span class=\"sc\">'*'<\/span><span class=\"p\">)<\/span> <span class=\"k\">continue<\/span> <span class=\"c1\">\/\/ skip it, not a gear<\/span>\n\n      <span class=\"c1\">\/\/ We _do_ need to keep track of which numbers we've already seen,<\/span>\n      <span class=\"c1\">\/\/ since each number can have multiple digits and the symbol may<\/span>\n      <span class=\"c1\">\/\/ be adjacent to more than one of them.<\/span>\n      <span class=\"kd\">var<\/span> <span class=\"py\">numbersSeen<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mutableSetOf<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;()<\/span>\n      <span class=\"kd\">var<\/span> <span class=\"py\">numbersAdded<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n      <span class=\"kd\">var<\/span> <span class=\"py\">ratio<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">1<\/span>\n\n      <span class=\"c1\">\/\/ Check all around the symbol...<\/span>\n      <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">offset<\/span> <span class=\"k\">in<\/span> <span class=\"n\">offsets<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">row<\/span> <span class=\"p\">=<\/span> <span class=\"n\">coordinate<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span> <span class=\"p\">+<\/span> <span class=\"n\">offset<\/span><span class=\"p\">.<\/span><span class=\"n\">first<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">col<\/span> <span class=\"p\">=<\/span> <span class=\"n\">coordinate<\/span><span class=\"p\">.<\/span><span class=\"n\">second<\/span> <span class=\"p\">+<\/span> <span class=\"n\">offset<\/span><span class=\"p\">.<\/span><span class=\"n\">second<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">checkAt<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">Coordinate<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\">\/\/ If the neighboring coordinate contains a value that can be<\/span>\n        <span class=\"c1\">\/\/ coerced to a [SchematicItem.Number], we haven't added that<\/span>\n        <span class=\"c1\">\/\/ number to the gear ratio yet, and it's not the third (or<\/span>\n        <span class=\"c1\">\/\/ greater) number we've found, then we add (by multiplying) that<\/span>\n        <span class=\"c1\">\/\/ number to the gear ratio and add the number's ID to the set<\/span>\n        <span class=\"c1\">\/\/ of seen numbers.<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">maybeNumber<\/span> <span class=\"p\">=<\/span> <span class=\"n\">map<\/span><span class=\"p\">.<\/span><span class=\"k\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">checkAt<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span><span class=\"p\">?<\/span> <span class=\"nc\">SchematicItem<\/span><span class=\"p\">.<\/span><span class=\"nc\">Number<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">maybeNumber<\/span> <span class=\"p\">!=<\/span> <span class=\"k\">null<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"p\">!<\/span><span class=\"n\">numbersSeen<\/span><span class=\"p\">.<\/span><span class=\"nf\">contains<\/span><span class=\"p\">(<\/span><span class=\"n\">maybeNumber<\/span><span class=\"p\">.<\/span><span class=\"n\">id<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n          <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">numbersAdded<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"k\">continue<\/span><span class=\"nd\">@symbol<\/span> <span class=\"c1\">\/\/ more than two numbers<\/span>\n          <span class=\"n\">ratio<\/span> <span class=\"p\">*=<\/span> <span class=\"n\">maybeNumber<\/span><span class=\"p\">.<\/span><span class=\"n\">number<\/span>\n          <span class=\"n\">numbersSeen<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">maybeNumber<\/span><span class=\"p\">.<\/span><span class=\"n\">id<\/span><span class=\"p\">)<\/span>\n          <span class=\"n\">numbersAdded<\/span> <span class=\"p\">+=<\/span> <span class=\"mi\">1<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">}<\/span>\n\n      <span class=\"c1\">\/\/ Only add the raio to ratios if we saw two numbers<\/span>\n      <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">numbersAdded<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"n\">ratios<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">ratio<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">ratios<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day03<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ The real work is done here<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">schematic<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">EngineSchematic<\/span><span class=\"p\">.<\/span><span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">)<\/span>\n\n  <span class=\"c1\">\/\/ In part one, we figure out which numbers really represent parts<\/span>\n  <span class=\"c1\">\/\/ and return the sum of all of them.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">schematic<\/span><span class=\"p\">.<\/span><span class=\"nf\">partNumbers<\/span><span class=\"p\">().<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">number<\/span> <span class=\"p\">}<\/span>\n\n  <span class=\"c1\">\/\/ In part two, we find the gears (which are a bit trickier) and return<\/span>\n  <span class=\"c1\">\/\/ the sum of all the gear ratios.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">schematic<\/span><span class=\"p\">.<\/span><span class=\"nf\">gearRatios<\/span><span class=\"p\">().<\/span><span class=\"nf\">sum<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here, we iterate over the list of symbols and check around them for any number. If we find one number, that goes in the \u2018gear ratio\u2019. Same for the second one. A third one, though, and we\u2019re out; that\u2019s not a gear. Calculating the gear ratio for all the \u2018*\u2019 that are really gears, we just need to sum them and we\u2019re good to go.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>I\u2019ve heard this year (so far) being referred to as the \u201cAdvent of Parsing\u201d, and there\u2019s a certain truth to that. Granted, there\u2019s a certain truth to that_every_ year, but these first three days have been pretty heavy with it. It may have something to do with these first few days falling on a weekend. Regardless, it\u2019s certainly given me an opportunity to write a decent amount of code in Kotlin, which is helping the learning process. I was delighted to find the mechanism for tagging loops and choosing which one to <code>break<\/code>\/<code>continue<\/code> for the loops within loops of today\u2019s solutions. I\u2019d <em>like<\/em> to be writing these in a more \u201cfunctional\u201d style as opposed to the \u201cinitialize then loop\u201d pattern I\u2019ve got here, but I\u2019m not sure how to do that with all the side-effects I\u2019m engaging here. Probably just need to spend a bit more time on it, reduce with a data structure, etc.<\/p>\n\n<p>Lastly, I\u2019ll point out the <a href=\"https:\/\/kotlinlang.org\/docs\/advent-of-code.html#advent-of-code-2022\">JetBrains Livestreams<\/a>for Advent of Code. I\u2019ve found them really helpful for hearing how other people have approached these problems in the same language who have a much greater breadth of knowledge about what\u2019s in the standard library and ecosystem. It really helps me to listen in after I\u2019ve solved the problem (or at least worked on it) so I can more easily follow along. Give it a watch\/listen!<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 02","pubDate":"Sat, 02 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-02-2g0j","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-02-2g0j","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 2 - Cube Conundrum\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/2\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Cubist Collection\n<\/h2>\n\n<p>It seems we\u2019ve rounded the corner from yesterday\u2019s \u201cparsing is the puzzle\u201d and now we\u2019re back on more familiar footing. The puzzle description states that we need to keep track of games and handfuls of cubes, so that\u2019s what we\u2019re going to do!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"cm\">\/**\n * This is a data class that represents a set of colored cubes\n *\n * @property red The number of red cubes\n * @property green The number of green cubes\n * @property blue The number of blue cubes\n * @constructor Create a new [CubeSet] with the given number of [red], [blue], \n * and [green] cubes.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">red<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">green<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">blue<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Parse a [CubeSet] from a String\n     *\n     * @param input The string to be parsed\n     * @throws IllegalArgumentException When the input string is not formatted \n     * properly\n     * @return A [CubeSet]\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">CubeSet<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">var<\/span> <span class=\"py\">red<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n      <span class=\"kd\">var<\/span> <span class=\"py\">green<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n      <span class=\"kd\">var<\/span> <span class=\"py\">blue<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n\n      <span class=\"c1\">\/\/ Split a string like \"1 red, 2 green, 3 blue\" on commas and trim each.<\/span>\n      <span class=\"c1\">\/\/ For each number\/color combination, split a string like \"1 red\" into<\/span>\n      <span class=\"c1\">\/\/ [1, \"red\"] and check to be sure we got the parts we were expecting. If<\/span>\n      <span class=\"c1\">\/\/ so, increase the number of cubes indicated by the color. Once all color<\/span>\n      <span class=\"c1\">\/\/ cubes are counted, return a [CubeSet] with those counts.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">colorCounts<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\",\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n      <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">colorCount<\/span> <span class=\"k\">in<\/span> <span class=\"n\">colorCounts<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">parts<\/span> <span class=\"p\">=<\/span> <span class=\"n\">colorCount<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\" \"<\/span><span class=\"p\">)<\/span>\n        <span class=\"nf\">require<\/span><span class=\"p\">(<\/span><span class=\"n\">parts<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"$colorCount does not match expected format!\"<\/span> <span class=\"p\">}<\/span>\n\n        <span class=\"kd\">val<\/span> <span class=\"py\">count<\/span> <span class=\"p\">=<\/span>\n            <span class=\"n\">parts<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"nf\">toIntOrNull<\/span><span class=\"p\">()<\/span>\n                <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span>\n                  <span class=\"s\">\"$colorCount does not contain a valid count!\"<\/span>\n                <span class=\"p\">)<\/span>\n        <span class=\"kd\">val<\/span> <span class=\"py\">color<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parts<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"nf\">lowercase<\/span><span class=\"p\">()<\/span>\n\n        <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"n\">color<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"s\">\"red\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">red<\/span> <span class=\"p\">+=<\/span> <span class=\"n\">count<\/span>\n          <span class=\"s\">\"green\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">green<\/span> <span class=\"p\">+=<\/span> <span class=\"n\">count<\/span>\n          <span class=\"s\">\"blue\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"n\">blue<\/span> <span class=\"p\">+=<\/span> <span class=\"n\">count<\/span>\n          <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span>\n            <span class=\"s\">\"$colorCount does not contain a valid color!\"<\/span>\n          <span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">}<\/span>\n\n      <span class=\"k\">return<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">(<\/span><span class=\"n\">red<\/span><span class=\"p\">,<\/span> <span class=\"n\">green<\/span><span class=\"p\">,<\/span> <span class=\"n\">blue<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * This class represents one round of the [Game]\n *\n * Each round, the elf reveals a handful of cubes. This class holds the [id] of \n * the game and maintains a list of the [handfuls] of cubes revealed by the elf.\n *\n * @property id The unique game identifier.\n * @property handfules The [CubSet]s revealed by the elf.\n * @constructor Creates a new [CubSet] with the given [id] and [handfuls] of \n * revealed cubes.\n *\/<\/span>\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Game<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">id<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">handfuls<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CubeSet<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">companion<\/span> <span class=\"k\">object<\/span> <span class=\"p\">{<\/span>\n    <span class=\"cm\">\/**\n     * Parse a [Game] from a line of the input file\n     *\n     * @param input A line from the input file.\n     * @throws IllegalArgumentException When the input is malformed.\n     * @return A [Game] parsed from the input line.\n     *\/<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">fromString<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Game<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ Input in the format of \"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; <\/span>\n      <span class=\"c1\">\/\/ 2 green\". Split on the colon to get [\"Game 1\", \"3 blue, 4 red; 1 red, <\/span>\n      <span class=\"c1\">\/\/ 2 green, 6 blue; 2 green\"].<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">mainParts<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\":\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n      <span class=\"nf\">require<\/span><span class=\"p\">(<\/span><span class=\"n\">mainParts<\/span><span class=\"p\">.<\/span><span class=\"n\">size<\/span> <span class=\"p\">==<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"$input is not a valid Game format!\"<\/span> <span class=\"p\">}<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"p\">(<\/span><span class=\"py\">gamePart<\/span><span class=\"p\">,<\/span> <span class=\"py\">cubePart<\/span><span class=\"p\">)<\/span> <span class=\"p\">=<\/span> <span class=\"n\">mainParts<\/span>\n\n      <span class=\"c1\">\/\/ Get the Game ID from a string like \"Game 1\". If this part of the input <\/span>\n      <span class=\"c1\">\/\/ line is not formed correctly, throw an exception.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">gameParts<\/span> <span class=\"p\">=<\/span> <span class=\"n\">gamePart<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\" \"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n      <span class=\"nf\">require<\/span><span class=\"p\">(<\/span><span class=\"n\">gameParts<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"p\">==<\/span> <span class=\"s\">\"Game\"<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"$gamePart is not a valid Game format!\"<\/span><span class=\"p\">)<\/span>\n      <span class=\"p\">}<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">id<\/span> <span class=\"p\">=<\/span>\n          <span class=\"n\">gameParts<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"nf\">toIntOrNull<\/span><span class=\"p\">()<\/span> <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span>\n            <span class=\"s\">\"$gamePart does not contain a valid id!\"<\/span>\n          <span class=\"p\">)<\/span>\n\n      <span class=\"c1\">\/\/ Get the handfuls of cubes revealed. For each string like <\/span>\n      <span class=\"c1\">\/\/ \"1 red, 2 green, 6 blue\", parse that string into a [CubeSet] and <\/span>\n      <span class=\"c1\">\/\/ set `handfuls` to that list of cubesets.<\/span>\n      <span class=\"kd\">val<\/span> <span class=\"py\">handfuls<\/span> <span class=\"p\">=<\/span> <span class=\"n\">cubePart<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"s\">\";\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">CubeSet<\/span><span class=\"o\">::<\/span><span class=\"n\">fromString<\/span><span class=\"p\">)<\/span>\n\n      <span class=\"k\">return<\/span> <span class=\"nc\">Game<\/span><span class=\"p\">(<\/span><span class=\"n\">id<\/span><span class=\"p\">,<\/span> <span class=\"n\">handfuls<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day02<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ Parse the input by constructing a Game from each non-empty line.<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"p\">!<\/span><span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">Game<\/span><span class=\"o\">::<\/span><span class=\"n\">fromString<\/span><span class=\"p\">)<\/span>\n\n <span class=\"c1\">\/\/ ...<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>So, here we go. We\u2019ve got <code>CubSet<\/code>s and we\u2019ve got <code>Game<\/code>s and we can parse each of them from a line of the input. Nice.<\/p>\n\n<h2>\n  \n  \n  Part One - Bag of Holding\n<\/h2>\n\n<p>We\u2019ve (barely) arrived safely on an island in the sky that I kind of wish we\u2019d known about <em>before<\/em> being launched like a pumpkin (look it up, it\u2019s a thing). Ah well, at least we have a tour guide. And, he wants to play a guessing game with us. Our guide will be pulling cubes out of his bag and we\u2019re supposed to figure out whether or not his bag contains more or less than some predefined number of red, green, and blue cubes. Not the worst way to spend a leisurely stroll across a sky island.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">red<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">green<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">blue<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ ...<\/span>\n\n  <span class=\"cm\">\/**\n   * Determines whether this [CubeSet] is valid\n   *\n   * A [CubSet] is valid if the number of cubes in it can be contained in the \n   * [max] cubeset it is being compared to.\n   *\n   * @param max A [CubeSet] to compare against\n   * @return A boolean indicating whether this [CubeSet] is valid\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">isValid<\/span><span class=\"p\">(<\/span><span class=\"n\">max<\/span><span class=\"p\">:<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Boolean<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">red<\/span> <span class=\"p\">&lt;=<\/span> <span class=\"n\">max<\/span><span class=\"p\">.<\/span><span class=\"n\">red<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"n\">green<\/span> <span class=\"p\">&lt;=<\/span> <span class=\"n\">max<\/span><span class=\"p\">.<\/span><span class=\"n\">green<\/span> <span class=\"p\">&amp;&amp;<\/span> <span class=\"n\">blue<\/span> <span class=\"p\">&lt;=<\/span> <span class=\"n\">max<\/span><span class=\"p\">.<\/span><span class=\"n\">blue<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Game<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">id<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">handfuls<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CubeSet<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ ...<\/span>\n\n  <span class=\"cm\">\/**\n   * Indicate whether this [Game] is valid\n   *\n   * A valid game is one where every revealed handful of cubes can be contained \n   * within the [max] cubeset.\n   *\n   * @param max A [CubeSet] to compare against\n   * @return A Boolean indicating whether the [Game] is valid.\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">isValid<\/span><span class=\"p\">(<\/span><span class=\"n\">max<\/span><span class=\"p\">:<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">):<\/span> <span class=\"nc\">Boolean<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">handfuls<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isValid<\/span><span class=\"p\">(<\/span><span class=\"n\">max<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day02<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">maxCubeSet<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">(<\/span><span class=\"mi\">12<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">,<\/span> <span class=\"mi\">14<\/span><span class=\"p\">)<\/span>\n\n  <span class=\"c1\">\/\/ Parse the input by constructing a Game from each non-empty line.<\/span>\n  <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">parsed<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"p\">!<\/span><span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">Game<\/span><span class=\"o\">::<\/span><span class=\"n\">fromString<\/span><span class=\"p\">)<\/span>\n\n  <span class=\"c1\">\/\/ In part 1, we compare our games to a static maximum cubeset, determine<\/span>\n  <span class=\"c1\">\/\/ which games are valid, and return the sum of their game ids.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isValid<\/span><span class=\"p\">(<\/span><span class=\"n\">maxCubeSet<\/span><span class=\"p\">)<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">id<\/span> <span class=\"p\">}<\/span>\n\n  <span class=\"c1\">\/\/ ...<\/span>\n\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>There we go, a shiny new member function for each of our classes to determine whether a particular <code>CubeSet<\/code> is valid and therefor whether the entire <code>Game<\/code>is valid. Sum the ID\u2019s of the valid games, and we\u2019ve got our answer.<\/p>\n\n<h2>\n  \n  \n  Part Two - In the Eye of the Beholder\n<\/h2>\n\n<p>Who knew a bag of cubes could be so entertaining? Well, I suppose you get very creative stranded on an island in the sky. Our tour guide clearly needed some company in a bad way. And <em>we\u2019re<\/em> company, so now\u2019s the chance to up the level of the game. In part 2, we need to decide on the minimum possible contents of the bag (per game) based on what we\u2019ve seen, then provide an answer based on these contents. Sounds do-able.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"kd\">data class<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">red<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">green<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">blue<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ ...<\/span>\n\n  <span class=\"cm\">\/**\n   * Calculate the power of this [CubeSet]\n   *\n   * Power is the product of the number of red, green, and blue cubes\n   *\n   * @return The calculated power\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">power<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">red<\/span> <span class=\"p\">*<\/span> <span class=\"n\">green<\/span> <span class=\"p\">*<\/span> <span class=\"n\">blue<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">data class<\/span> <span class=\"nc\">Game<\/span><span class=\"p\">(<\/span><span class=\"kd\">val<\/span> <span class=\"py\">id<\/span><span class=\"p\">:<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">,<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">handfuls<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">CubeSet<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ ...<\/span>\n\n  <span class=\"cm\">\/**\n   * Identify the smallest [CubSet] that can contain all [handfuls]\n   *\n   * Calculate the smallest number of red, green, and blue cubes that could be \n   * represented by the handfuls of cubes revealed by the elf.\n   *\n   * @return The smallest possible [CubeSet]\n   *\/<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">localMinimum<\/span><span class=\"p\">():<\/span> <span class=\"nc\">CubeSet<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">red<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">green<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"py\">blue<\/span> <span class=\"p\">=<\/span> <span class=\"mi\">0<\/span>\n\n    <span class=\"c1\">\/\/ The smallest possible cubeset must contain at least as many red,<\/span>\n    <span class=\"c1\">\/\/ green, and blue cubes as revealed in any given handful of cubes.<\/span>\n    <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"n\">handful<\/span> <span class=\"k\">in<\/span> <span class=\"n\">handfuls<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"n\">red<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">maxOf<\/span><span class=\"p\">(<\/span><span class=\"n\">red<\/span><span class=\"p\">,<\/span> <span class=\"n\">handful<\/span><span class=\"p\">.<\/span><span class=\"n\">red<\/span><span class=\"p\">)<\/span>\n      <span class=\"n\">green<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">maxOf<\/span><span class=\"p\">(<\/span><span class=\"n\">green<\/span><span class=\"p\">,<\/span> <span class=\"n\">handful<\/span><span class=\"p\">.<\/span><span class=\"n\">green<\/span><span class=\"p\">)<\/span>\n      <span class=\"n\">blue<\/span> <span class=\"p\">=<\/span> <span class=\"nf\">maxOf<\/span><span class=\"p\">(<\/span><span class=\"n\">blue<\/span><span class=\"p\">,<\/span> <span class=\"n\">handful<\/span><span class=\"p\">.<\/span><span class=\"n\">blue<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nc\">CubeSet<\/span><span class=\"p\">(<\/span><span class=\"n\">red<\/span><span class=\"p\">,<\/span> <span class=\"n\">green<\/span><span class=\"p\">,<\/span> <span class=\"n\">blue<\/span><span class=\"p\">)<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day02<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n  <span class=\"c1\">\/\/ ...<\/span>\n\n  <span class=\"c1\">\/\/ In part 2, we identify the smallest valid set of cubes for each game, <\/span>\n  <span class=\"c1\">\/\/ calculate the 'power' of that minimum set, then return the sum of all<\/span>\n  <span class=\"c1\">\/\/ the power from all the games.<\/span>\n  <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">parsed<\/span><span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">localMinimum<\/span><span class=\"p\">().<\/span><span class=\"nf\">power<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>There we go! Again, just a couple more member functions on our two classes and we\u2019re good to go.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Now this is more in line with the difficulty level of a Day 2 Advent of Code puzzle. There\u2019s probably a ton of minor ways this solution could be tweaked, but it boils down to parsing strings and keeping track of your data structures. I was a bit concerned after Day 1\u2019s relative difficulty (and knowing today was a weekend), but it appears to be all for naught. As for Kotlin, I find the whole \u201ccompanion object\u201d structure for class methods to be a bit odd and I kind of miss the <code>FromStr<\/code> trait in Rust, but so far it\u2019s felt like mostly familiar territory.<\/p>\n\n"},{"title":"Advent of Code 2023 - Day 01","pubDate":"Fri, 01 Dec 2023 00:00:00 +0000","link":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-01-5e4b","guid":"https:\/\/dev.to\/ericwburden\/advent-of-code-2023-day-01-5e4b","description":"<p>It\u2019s that time of year again! Just like last year, I\u2019ll be posting my solutions to the <a href=\"https:\/\/adventofcode.com\/\">Advent of Code<\/a> puzzles. This year, I\u2019ll be solving the puzzles in <a href=\"https:\/\/kotlinlang.org\/\">Kotlin<\/a>. I\u2019ll post my solutions and code to <a href=\"https:\/\/github.com\/ericwburden\/advent_of_code_2023\">GitHub<\/a> as well. If you haven\u2019t given AoC a try, I encourage you to do so along with me!<\/p>\n\n<h1>\n  \n  \n  Day 1 - Trebuchet?!\n<\/h1>\n\n<p>Find the problem description <a href=\"https:\/\/adventofcode.com\/2023\/day\/1\">HERE<\/a>.<\/p>\n\n<h2>\n  \n  \n  The Input - Numbers Every Which Way\n<\/h2>\n\n<p>Well, well, well\u2026 Here we are again. Another year, another catastrophic threat to Christmas cheer. Thankfully, we\u2019ve advanced to<a href=\"https:\/\/en.wikipedia.org\/wiki\/Trebuchet\"><em>trebuchet<\/em><\/a> technology to tackle this looming crisis. It looks like this year we\u2019ll be working to restore snow production, which will hopefully result in a few snow days! What\u2019s that? Remote work is a thing now? Ah well, at least snow is pretty\u2026<\/p>\n\n<p>Our input for today is the \u201ccalibration document\u201d for the trebuchet we\u2019re apparently <em>about to be fired out of<\/em> (no snow days doesn\u2019t seem like such a big sacrifice now, huh?). We need to read in a list of strings from a text file, extract all the numbers, then use the first and last number to calculate the \u201ccalibration value\u201d on each line. Because (spoiler alert!) the parsing strategy_changes a bit_ from part 1 to part 2, I\u2019ll address each one individually. Instead, I\u2019ll use this section to share my \u201cread the input file\u201d code I cleverly prepared ahead of time this year, and that I hope will continue to be handy.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"k\">import<\/span> <span class=\"nn\">java.io.File<\/span>\n<span class=\"k\">import<\/span> <span class=\"nn\">java.net.URI<\/span>\n\n<span class=\"k\">internal<\/span> <span class=\"kd\">object<\/span> <span class=\"nc\">Resources<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nc\">String<\/span><span class=\"p\">.<\/span><span class=\"nf\">toURI<\/span><span class=\"p\">():<\/span> <span class=\"nc\">URI<\/span> <span class=\"p\">=<\/span>\n      <span class=\"nc\">Resources<\/span><span class=\"p\">.<\/span><span class=\"n\">javaClass<\/span><span class=\"p\">.<\/span><span class=\"n\">classLoader<\/span><span class=\"p\">.<\/span><span class=\"nf\">getResource<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">)<\/span><span class=\"o\">?.<\/span><span class=\"nf\">toURI<\/span><span class=\"p\">()<\/span>\n          <span class=\"o\">?:<\/span> <span class=\"k\">throw<\/span> <span class=\"nc\">IllegalArgumentException<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Cannot find Resource: $this\"<\/span><span class=\"p\">)<\/span>\n\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceAsText<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">String<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">File<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">.<\/span><span class=\"nf\">toURI<\/span><span class=\"p\">()).<\/span><span class=\"nf\">readText<\/span><span class=\"p\">()<\/span>\n\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceAsLines<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">=<\/span> <span class=\"nc\">File<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">.<\/span><span class=\"nf\">toURI<\/span><span class=\"p\">()).<\/span><span class=\"nf\">readLines<\/span><span class=\"p\">()<\/span>\n\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceAsLineChunks<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"n\">delimiter<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"\\n\\n\"<\/span><span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;&gt;<\/span> <span class=\"p\">=<\/span>\n      <span class=\"nf\">resourceAsText<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">).<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"n\">delimiter<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">lines<\/span><span class=\"p\">().<\/span><span class=\"nf\">takeWhile<\/span> <span class=\"p\">{<\/span> <span class=\"p\">!<\/span><span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">isEmpty<\/span><span class=\"p\">()<\/span> <span class=\"p\">}.<\/span><span class=\"nf\">toList<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceAsString<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">,<\/span> <span class=\"n\">delimiter<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"\"<\/span><span class=\"p\">):<\/span> <span class=\"nc\">String<\/span> <span class=\"p\">=<\/span>\n      <span class=\"nf\">resourceAsLines<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">).<\/span><span class=\"nf\">reduce<\/span> <span class=\"p\">{<\/span> <span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"s\">\"$a$delimiter$b\"<\/span> <span class=\"p\">}<\/span>\n\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceAsListOfInt<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">=<\/span>\n      <span class=\"nf\">resourceAsLines<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n\n  <span class=\"k\">fun<\/span> <span class=\"nf\">resourceAsListOfLong<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">:<\/span> <span class=\"nc\">String<\/span><span class=\"p\">):<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Long<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">=<\/span>\n      <span class=\"nf\">resourceAsLines<\/span><span class=\"p\">(<\/span><span class=\"n\">fileName<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toLong<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>These aren\u2019t terribly complicated, but they\u2019re general enough to be useful almost every day, I suspect. We can read the input file as a single string, as a list of lines (strings), as a list of line chunks (with a delimiter), as a list of strings from a single line (with optional delimiter), as a list of integers (one per line), and as a list of longs (again, one per line). There\u2019s a good chance I\u2019ll come up with others over the course of the month (I\u2019m already thinking I\u2019d like a <code>resourceAsParsedLines<\/code> that takes a parsing function as a second argument), but as long as I get to re-use some of these, it will have been worth it.<\/p>\n\n<h2>\n  \n  \n  Part One - Artistic Expression\n<\/h2>\n\n<ul>\n<li>Bad news: You\u2019re being hoisted into a trebuchet to be launched into the sky.<\/li>\n<li>Good news: The elves can\u2019t calibrate their siege weapon! We\u2019re saved!<\/li>\n<\/ul>\n\n<p>Wait, did we volunteer to <em>decipher<\/em> the calibration document to <em>help<\/em> the elves propel us into the stratosphere? Guess we\u2019d better get to it, then.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"cm\">\/**\n * Extracts all digit characters from a string as numbers.\n *\n * @return A list of all digits in the input String as Ints.\n *\/<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nc\">String<\/span><span class=\"p\">.<\/span><span class=\"nf\">extractDigitsPart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Take the string, convert to a list of characters, filter to<\/span>\n    <span class=\"c1\">\/\/ only characters that are digits, then convert those digit<\/span>\n    <span class=\"c1\">\/\/ characters to integers.<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">toList<\/span><span class=\"p\">().<\/span><span class=\"nf\">filter<\/span><span class=\"p\">(<\/span><span class=\"nc\">Char<\/span><span class=\"o\">::<\/span><span class=\"n\">isDigit<\/span><span class=\"p\">).<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">Char<\/span><span class=\"o\">::<\/span><span class=\"n\">digitToInt<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Derive the calibration value from a list of numbers\n *\n * This function \"concatenates\" the first digit in a list of numbers and the \n * last digit in a list of\n * numbers into a single two-digit number.\n *\n * @return The calibration value extracted from a list of numbers.\n *\/<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nf\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;.<\/span><span class=\"nf\">toCalibrationValue<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ This works because the 'numbers' are all single digits. So, it's<\/span>\n    <span class=\"c1\">\/\/ the ten's place * 10 plus the one's place (times 1, technically).<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">first<\/span><span class=\"p\">()<\/span> <span class=\"p\">*<\/span> <span class=\"mi\">10<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nf\">last<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day01<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">input<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n\n    <span class=\"c1\">\/\/ In part one, the valid numbers in the string are all digits.<\/span>\n    <span class=\"c1\">\/\/ Take the input, extract all the digits from each line, then <\/span>\n    <span class=\"c1\">\/\/ sum the calibration values of each line.<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"o\">::<\/span><span class=\"n\">extractDigitsPart1<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toCalibrationValue<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Part Two - Burning Out My Fuse Up Here Alone\n<\/h2>\n\n<p>I feel like we\u2019re being a bit <em>too<\/em> accommodating when it comes to helping the elves in this endeavor. I can\u2019t help but think that, if the trebuchet weren\u2019t an option, we could borrow some sort of flying vehicle (perhaps reindeer-propelled) to make this trip. Probably with fewer life-threatening injuries, which would be a big plus. Must just be me. Anyway, part two asks us to parse words that represent numbers (like \u2018one\u2019 or \u2018fiveight\u2019) as well as digits from the lines of the input.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight kotlin\"><code><span class=\"cm\">\/**\n * Extract all digits from a string as numbers\n *\n * This function also extracts digits in \"word\" form, such as \"one\" or \"two\". \n * Note, this function will also extract number-words whose letters overlap, \n * such as \"twoone\" or \"fiveight\".\n *\n * @return A list of all digits in the input String as Ints.\n *\/<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nc\">String<\/span><span class=\"p\">.<\/span><span class=\"nf\">extractDigitsPart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">Int<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">val<\/span> <span class=\"py\">pattern<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"\"\"(?=(one|two|three|four|five|six|seven|eight|nine|\\d))\"\"\"<\/span>\n\n    <span class=\"c1\">\/\/ Because we have to account for overlaps, I'm using the \"non-consuming\" regular<\/span>\n    <span class=\"c1\">\/\/ expression above. This does weird things (IMO) to the match values, causing<\/span>\n    <span class=\"c1\">\/\/ `findAll()` to return a list of values for each match where the first value<\/span>\n    <span class=\"c1\">\/\/ is an empty string. Probably just means I need to learn more about regex.<\/span>\n    <span class=\"c1\">\/\/ Regardless, the result is that I need to flatten the results and remove empty<\/span>\n    <span class=\"c1\">\/\/ strings before converting the matches to numbers.<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Regex<\/span><span class=\"p\">(<\/span><span class=\"n\">pattern<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"nf\">findAll<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"nf\">flatMap<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"n\">groupValues<\/span> <span class=\"p\">}<\/span>\n            <span class=\"p\">.<\/span><span class=\"nf\">filter<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"o\">::<\/span><span class=\"n\">isNotBlank<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"o\">::<\/span><span class=\"n\">toNumberUnchecked<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"nf\">toList<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"cm\">\/**\n * Convert a String to an Int\n *\n * This function will numeric strings _and_ words that represent digits into\n * integers.\n *\n * @return The Int representation of a String\n *\/<\/span>\n<span class=\"k\">private<\/span> <span class=\"k\">fun<\/span> <span class=\"nc\">String<\/span><span class=\"p\">.<\/span><span class=\"nf\">toNumberUnchecked<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ I wouldn't recommend using this in production anywhere, since we're<\/span>\n    <span class=\"c1\">\/\/ not actually checking to see whether any numeric strings are<\/span>\n    <span class=\"c1\">\/\/ (a) valid numbers or (b) single digits. Just gotta count on the<\/span>\n    <span class=\"c1\">\/\/ puzzle input for this one.<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">when<\/span> <span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"s\">\"one\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">1<\/span>\n        <span class=\"s\">\"two\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">2<\/span>\n        <span class=\"s\">\"three\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">3<\/span>\n        <span class=\"s\">\"four\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">4<\/span>\n        <span class=\"s\">\"five\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">5<\/span>\n        <span class=\"s\">\"six\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">6<\/span>\n        <span class=\"s\">\"seven\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">7<\/span>\n        <span class=\"s\">\"eight\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">8<\/span>\n        <span class=\"s\">\"nine\"<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"mi\">9<\/span>\n        <span class=\"k\">else<\/span> <span class=\"p\">-&gt;<\/span> <span class=\"nf\">toInt<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nc\">Day01<\/span><span class=\"p\">(<\/span><span class=\"n\">input<\/span><span class=\"p\">:<\/span> <span class=\"nc\">List<\/span><span class=\"p\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"p\">&gt;)<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"k\">private<\/span> <span class=\"kd\">val<\/span> <span class=\"py\">input<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n\n    <span class=\"c1\">\/\/ In part one, the valid numbers in the string are all digits<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart1<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"o\">::<\/span><span class=\"n\">extractDigitsPart1<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toCalibrationValue<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ In part two, we also have to account for \"number-words\" like \"one\" <\/span>\n    <span class=\"c1\">\/\/ and \"twone\"<\/span>\n    <span class=\"k\">fun<\/span> <span class=\"nf\">solvePart2<\/span><span class=\"p\">():<\/span> <span class=\"nc\">Int<\/span> <span class=\"p\">=<\/span> <span class=\"n\">input<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"o\">::<\/span><span class=\"n\">extractDigitsPart2<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">sumOf<\/span> <span class=\"p\">{<\/span> <span class=\"n\">it<\/span><span class=\"p\">.<\/span><span class=\"nf\">toCalibrationValue<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>I may or may not have submitted an incorrect answer for part two, re-read the example input (suspiciously a different example than part one), called<a href=\"https:\/\/techhub.social\/@ericwastl@hachyderm.io\">Eric Wastl<\/a> an unkind name under my breath, then proceeded to figure out how to parse \u2019twone\u2019 into <code>[2, 1]<\/code>.<\/p>\n\n<h2>\n  \n  \n  Wrap Up\n<\/h2>\n\n<p>Another year, another set of coding puzzles! From a historical perspective, Day 1 this represents a bit of a bump in difficulty level from previous years. I don\u2019t know if this means we\u2019re in for a more challenging year overall or if this is a deliberate attempt to keep the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Large_language_model\">LLMs<\/a> at bay. Either way, I know <em>I<\/em> spent more time on a Day 1 puzzle today than I have in the past.<\/p>\n\n<p>This year I\u2019m picking up a complete new (to me) language in Kotlin. So far, the biggest challenge has been figuring out enough about how Maven works to get my project setup in place, but that\u2019s probably a <em>me<\/em> issue. I\u2019m really excited to learn a lot this year and looking forward to giving Kotlin a workout.<\/p>\n\n<p>Finally, if you enjoy Advent of Code as much as I do, consider <a href=\"https:\/\/adventofcode.com\/2023\/support\">helping out<\/a> with this completely free (to use, not to run) educational and community event. And, if you\u2019re not in a position to support financially (or even if you are), you can support the community over on the <a href=\"https:\/\/www.reddit.com\/r\/adventofcode\/\">r\/adventofcode<\/a>with code reviews, advice, visualizations, or hilarious memes. Happy Holidays!<\/p>\n\n"}]}}