advent of code solutions aoc.oppi.li
haskell aoc

2025: add d6

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 7abe1780 0e556048

verified
+453 -9
+1 -1
book/highlight.theme
··· 61 61 "underline": false 62 62 }, 63 63 "DataType": { 64 - "text-color": "#8888C7", 64 + "text-color": "#8f4e8b", 65 65 "background-color": null, 66 66 "bold": false, 67 67 "italic": false,
+44 -1
book/style.css
··· 1 + :root { 2 + --bg-color: #ffffff; 3 + --text-color: #1a1a1a; 4 + --border-color: #e0e0e0; 5 + --link-color: #0066cc; 6 + --link-hover: #004499; 7 + --link-visited: #551a8b; 8 + --syntax-datatype: #8f4e8b; 9 + --syntax-comment: #6a737d; 10 + --syntax-keyword: #1a1a1a; 11 + } 12 + 13 + @media (prefers-color-scheme: dark) { 14 + :root { 15 + --bg-color: #000000; 16 + --text-color: #e8e8e8; 17 + --border-color: #404040; 18 + --link-color: #6eb5ff; 19 + --link-hover: #9fcdff; 20 + --link-visited: #d4a5ff; 21 + --syntax-datatype: #c792ea; 22 + --syntax-comment: #b0b0b0; 23 + --syntax-keyword: #e8e8e8; 24 + } 25 + } 26 + 1 27 body { 2 28 max-width: 1400px; 3 29 margin-left: auto; ··· 5 31 box-sizing: border-box; 6 32 padding: 0 5vw; 7 33 font-family: "Libre Baskerville", serif; 34 + background-color: var(--bg-color); 35 + color: var(--text-color); 8 36 } 9 37 10 38 .sitenav { ··· 35 63 overflow: auto; 36 64 } 37 65 66 + a { 67 + color: var(--link-color); 68 + } 69 + 70 + a:hover { 71 + color: var(--link-hover); 72 + } 73 + 74 + a:visited { 75 + color: var(--link-visited); 76 + } 77 + 78 + code span.dt { color: var(--syntax-datatype); } 79 + code span.co { color: var(--syntax-comment); font-style: italic; } 80 + code span.kw { color: var(--syntax-keyword); font-weight: bold; } 81 + 38 82 @media (max-width: 768px) { 39 83 body { 40 84 max-width: 100%; ··· 54 98 padding: 0; 55 99 } 56 100 } 57 -
+1 -1
out/1.1-day-1.html
··· 62 62 code span.co { font-style: italic; } /* Comment */ 63 63 code span.cv { font-style: italic; } /* CommentVar */ 64 64 code span.do { font-style: italic; } /* Documentation */ 65 - code span.dt { color: #8888c7; } /* DataType */ 65 + code span.dt { color: #8f4e8b; } /* DataType */ 66 66 code span.er { font-weight: bold; } /* Error */ 67 67 code span.in { font-style: italic; } /* Information */ 68 68 code span.kw { font-weight: bold; } /* Keyword */
+1 -1
out/1.2-day-2.html
··· 62 62 code span.co { font-style: italic; } /* Comment */ 63 63 code span.cv { font-style: italic; } /* CommentVar */ 64 64 code span.do { font-style: italic; } /* Documentation */ 65 - code span.dt { color: #8888c7; } /* DataType */ 65 + code span.dt { color: #8f4e8b; } /* DataType */ 66 66 code span.er { font-weight: bold; } /* Error */ 67 67 code span.in { font-style: italic; } /* Information */ 68 68 code span.kw { font-weight: bold; } /* Keyword */
+1 -1
out/2.1-day-2-1.html
··· 62 62 code span.co { font-style: italic; } /* Comment */ 63 63 code span.cv { font-style: italic; } /* CommentVar */ 64 64 code span.do { font-style: italic; } /* Documentation */ 65 - code span.dt { color: #8888c7; } /* DataType */ 65 + code span.dt { color: #8f4e8b; } /* DataType */ 66 66 code span.er { font-weight: bold; } /* Error */ 67 67 code span.in { font-style: italic; } /* Information */ 68 68 code span.kw { font-weight: bold; } /* Keyword */
+1 -1
out/2.2-day-4.html
··· 62 62 code span.co { font-style: italic; } /* Comment */ 63 63 code span.cv { font-style: italic; } /* CommentVar */ 64 64 code span.do { font-style: italic; } /* Documentation */ 65 - code span.dt { color: #8888c7; } /* DataType */ 65 + code span.dt { color: #8f4e8b; } /* DataType */ 66 66 code span.er { font-weight: bold; } /* Error */ 67 67 code span.in { font-style: italic; } /* Information */ 68 68 code span.kw { font-weight: bold; } /* Keyword */
+2 -1
out/2.3-day-5.html
··· 62 62 code span.co { font-style: italic; } /* Comment */ 63 63 code span.cv { font-style: italic; } /* CommentVar */ 64 64 code span.do { font-style: italic; } /* Documentation */ 65 - code span.dt { color: #8888c7; } /* DataType */ 65 + code span.dt { color: #8f4e8b; } /* DataType */ 66 66 code span.er { font-weight: bold; } /* Error */ 67 67 code span.in { font-style: italic; } /* Information */ 68 68 code span.kw { font-weight: bold; } /* Keyword */ ··· 89 89 <span class="navlink-label">Previous:</span> <a href="2.2-day-4.html" accesskey="p" rel="previous">Day 4</a> 90 90 </span> 91 91 <span class="navlink"> 92 + <span class="navlink-label">Next:</span> <a href="2.4-day-6.html" accesskey="n" rel="next">Day 6</a> 92 93 </span> 93 94 </div> 94 95 </nav>
+262
out/2.4-day-6.html
··· 1 + <!DOCTYPE html> 2 + <html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang=""> 3 + <head> 4 + <meta charset="utf-8" /> 5 + <meta name="generator" content="pandoc" /> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> 7 + <title>Day 6</title> 8 + <style> 9 + code{white-space: pre-wrap;} 10 + span.smallcaps{font-variant: small-caps;} 11 + div.columns{display: flex; gap: min(4vw, 1.5em);} 12 + div.column{flex: auto; overflow-x: auto;} 13 + div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} 14 + /* The extra [class] is a hack that increases specificity enough to 15 + override a similar rule in reveal.js */ 16 + ul.task-list[class]{list-style: none;} 17 + ul.task-list li input[type="checkbox"] { 18 + font-size: inherit; 19 + width: 0.8em; 20 + margin: 0 0.8em 0.2em -1.6em; 21 + vertical-align: middle; 22 + } 23 + .display.math{display: block; text-align: center; margin: 0.5rem auto;} 24 + /* CSS for syntax highlighting */ 25 + html { -webkit-text-size-adjust: 100%; } 26 + pre > code.sourceCode { white-space: pre; position: relative; } 27 + pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } 28 + pre > code.sourceCode > span:empty { height: 1.2em; } 29 + .sourceCode { overflow: visible; } 30 + code.sourceCode > span { color: inherit; text-decoration: inherit; } 31 + div.sourceCode { margin: 1em 0; } 32 + pre.sourceCode { margin: 0; } 33 + @media screen { 34 + div.sourceCode { overflow: auto; } 35 + } 36 + @media print { 37 + pre > code.sourceCode { white-space: pre-wrap; } 38 + pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } 39 + } 40 + pre.numberSource code 41 + { counter-reset: source-line 0; } 42 + pre.numberSource code > span 43 + { position: relative; left: -4em; counter-increment: source-line; } 44 + pre.numberSource code > span > a:first-child::before 45 + { content: counter(source-line); 46 + position: relative; left: -1em; text-align: right; vertical-align: baseline; 47 + border: none; display: inline-block; 48 + -webkit-touch-callout: none; -webkit-user-select: none; 49 + -khtml-user-select: none; -moz-user-select: none; 50 + -ms-user-select: none; user-select: none; 51 + padding: 0 4px; width: 4em; 52 + } 53 + pre.numberSource { margin-left: 3em; padding-left: 4px; } 54 + div.sourceCode 55 + { } 56 + @media screen { 57 + pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } 58 + } 59 + code span.al { font-weight: bold; } /* Alert */ 60 + code span.an { font-style: italic; } /* Annotation */ 61 + code span.cf { font-weight: bold; } /* ControlFlow */ 62 + code span.co { font-style: italic; } /* Comment */ 63 + code span.cv { font-style: italic; } /* CommentVar */ 64 + code span.do { font-style: italic; } /* Documentation */ 65 + code span.dt { color: #8f4e8b; } /* DataType */ 66 + code span.er { font-weight: bold; } /* Error */ 67 + code span.in { font-style: italic; } /* Information */ 68 + code span.kw { font-weight: bold; } /* Keyword */ 69 + code span.pp { font-weight: bold; } /* Preprocessor */ 70 + code span.wa { font-style: italic; } /* Warning */ 71 + </style> 72 + <link rel="stylesheet" href="style.css" /> 73 + <link rel="preconnect" href="https://fonts.googleapis.com"> 74 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 75 + <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Libre+Baskerville:ital,wght@0,400..700;1,400..700&display=swap" rel="stylesheet"> 76 + </head> 77 + <body> 78 + <nav id="sitenav"> 79 + <div class="sitenav"> 80 + <span class="navlink"> 81 + <span class="navlink-label">Up:</span> <a href="2-section-1.html" accesskey="u" rel="up">2025</a> 82 + </span> 83 + <span class="navlink"> 84 + <span class="navlink-label">Top:</span> <a href="index.html" accesskey="t" rel="top"></a> 85 + </span> 86 + </div> 87 + <div class="sitenav"> 88 + <span class="navlink"> 89 + <span class="navlink-label">Previous:</span> <a href="2.3-day-5.html" accesskey="p" rel="previous">Day 5</a> 90 + </span> 91 + <span class="navlink"> 92 + </span> 93 + </div> 94 + </nav> 95 + 96 + <h2 data-number="2.4" id="day-6">Day 6</h2> 97 + <div class="row"> 98 + <p>This day is largely string munging, which is quite boring, but 99 + also quite easy to do with Haskell!</p> 100 + <div class="code"> 101 + 102 + </div> 103 + </div> 104 + <h3 data-number="2.4.1" id="part-1-5">Part 1</h3> 105 + <div class="row"> 106 + <p>This part needs us to consider each operation on a column. 107 + <code>Data.List.transpose</code> fortunately makes this very 108 + simple. If we are able to massage our input into the form 109 + <code>["+", "1", "2", "3"]</code>, we can use this simple 110 + <code>solve</code> function to produce the result. The only 111 + motivation to use this format is the ease of pattern-matching over 112 + the start of the list.</p> 113 + <div class="code"> 114 + <div class="sourceCode" id="cb1"><pre 115 + class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>solve (<span class="st">&quot;+&quot;</span> <span class="op">:</span> rest) <span class="ot">=</span> <span class="fu">sum</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">read</span> <span class="op">$</span> rest</span> 116 + <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>solve (<span class="st">&quot;*&quot;</span> <span class="op">:</span> rest) <span class="ot">=</span> <span class="fu">product</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">read</span> <span class="op">$</span> rest</span></code></pre></div> 117 + </div> 118 + </div> 119 + <div class="row"> 120 + <p>Thus, to solve the first part, we can break up our input using 121 + <code>lines</code>. <code>rot</code> is a simple function that 122 + rotates a list forwards to move the last element to the first. By 123 + doing <code>rot . lines</code> upon our input, we have a list of 124 + the form <code>["+ *", "1 2 3", "4 5 6"]</code>. Next, we define 125 + an <code>align</code> function to line up the colums. This method 126 + simply breaks each item in the list by spaces, and then transposes 127 + them, so we end up with 128 + <code>[["+", "1", "2", "3"], ["*", "4", "5", "6"]]</code>:</p> 129 + <div class="code"> 130 + <div class="sourceCode" id="cb2"><pre 131 + class="sourceCode haskell haskell-top"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Char</span> (isSpace)</span> 132 + <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (transpose)</span> 133 + <span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List.Split</span> (splitWhen)</span></code></pre></div> 134 + <div class="sourceCode" id="cb3"><pre 135 + class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>rot <span class="ot">=</span> liftA2 (<span class="op">:</span>) <span class="fu">last</span> <span class="fu">init</span></span> 136 + <span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span> 137 + <span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>p1 <span class="ot">=</span> <span class="fu">sum</span> <span class="op">.</span> <span class="fu">map</span> solve <span class="op">.</span> align <span class="op">.</span> rot <span class="op">.</span> <span class="fu">lines</span></span> 138 + <span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span> 139 + <span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> align <span class="ot">=</span> transpose <span class="op">.</span> <span class="fu">map</span> <span class="fu">words</span></span></code></pre></div> 140 + </div> 141 + </div> 142 + <h3 data-number="2.4.2" id="part-2-4">Part 2</h3> 143 + <div class="row"> 144 + <p>We are now tasked with lining up the digits in a columnar 145 + fashion to for a number:</p> 146 + <div class="code"> 147 + 148 + </div> 149 + </div> 150 + <pre><code>123 ... 151 + 45 ... 152 + 6 ... 153 + * ...</code></pre> 154 + <div class="row"> 155 + <p>Here, the numbers to operate on are 356, 24 and 1. 156 + Unfortunately, we can no longer employ <code>words</code> as it 157 + breaks on all whitespace. We must now transpose our list as-is, to 158 + make sense of the digits. Ignore the last row for a second, and 159 + only consider the first 3 rows:</p> 160 + <div class="code"> 161 + 162 + </div> 163 + </div> 164 + <pre><code>123 165 + 45 166 + 6</code></pre> 167 + <div class="row"> 168 + <p>Upon transposing this, we get:</p> 169 + <div class="code"> 170 + 171 + </div> 172 + </div> 173 + <pre><code>1 174 + 24 175 + 356</code></pre> 176 + <div class="row"> 177 + <p>This is exactly what we need!</p> 178 + <div class="code"> 179 + 180 + </div> 181 + </div> 182 + <div class="row"> 183 + <p>Let us start with a similar base, using <code>lines</code> to 184 + break things up, and <code>rot</code> to move the line of 185 + operators to the start. Our <code>align</code> function can now be 186 + defined as below.</p> 187 + <div class="code"> 188 + <div class="sourceCode" id="cb7"><pre 189 + class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>p2 <span class="ot">=</span> <span class="fu">sum</span> <span class="op">.</span> <span class="fu">map</span> solve <span class="op">.</span> align <span class="op">.</span> rot <span class="op">.</span> <span class="fu">lines</span></span> 190 + <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span> 191 + <span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> align <span class="ot">=</span></span> 192 + <span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">zipWith</span> (<span class="op">:</span>)</span> 193 + <span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="op">&lt;$&gt;</span> (<span class="fu">words</span> <span class="op">.</span> <span class="fu">head</span>)</span> 194 + <span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="op">&lt;*&gt;</span> (splitWhen (<span class="fu">all</span> <span class="fu">isSpace</span>) <span class="op">.</span> transpose <span class="op">.</span> <span class="fu">tail</span>)</span></code></pre></div> 195 + </div> 196 + </div> 197 + <div class="row"> 198 + <p>We first start with <code>zipWith (:)</code> to join the 199 + operation <code>"+"</code> with the rest of the numbers to 200 + produce:</p> 201 + <div class="code"> 202 + 203 + </div> 204 + </div> 205 + <pre><code>[&quot;+&quot;, &quot;1&quot;, &quot;2&quot;, ...]</code></pre> 206 + <div class="row"> 207 + <p>Remember that this is the format <code>solve</code> 208 + accepts!.</p> 209 + <div class="code"> 210 + 211 + </div> 212 + </div> 213 + <div class="row"> 214 + <p>We are using <code>&lt;*&gt;</code> to perform “sequential 215 + application”. The first part …</p> 216 + <div class="code"> 217 + 218 + </div> 219 + </div> 220 + <pre><code>words . head</code></pre> 221 + <div class="row"> 222 + <p>… is used to split up the operator line into a list of 223 + operators.</p> 224 + <div class="code"> 225 + 226 + </div> 227 + </div> 228 + <div class="row"> 229 + <p>The second part …</p> 230 + <div class="code"> 231 + 232 + </div> 233 + </div> 234 + <pre><code>splitWhen (all isSpace) . transpose . tail</code></pre> 235 + <div class="row"> 236 + <p>…is used to transpose numbers! Note what happens when we 237 + transpose the lines containing numbers, we get:</p> 238 + <div class="code"> 239 + 240 + </div> 241 + </div> 242 + <pre><code>[&quot;1 &quot;,&quot;24 &quot;,&quot;356&quot;,&quot; &quot;,&quot;369&quot;,&quot;248&quot;,&quot;8 &quot;, ...]</code></pre> 243 + <div class="row"> 244 + <p>There is an element containing all spaces (which was present 245 + between each column!). This is what we use to separate each 246 + column.</p> 247 + <div class="code"> 248 + 249 + </div> 250 + </div> 251 + <div class="row"> 252 + <p>Finally, a main function to wrap it all up:</p> 253 + <div class="code"> 254 + <div class="sourceCode" id="cb12"><pre 255 + class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span> 256 + <span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> n <span class="ot">&lt;-</span> <span class="fu">getContents</span></span> 257 + <span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> <span class="op">$</span> p1 n</span> 258 + <span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> <span class="op">$</span> p2 n</span></code></pre></div> 259 + </div> 260 + </div> 261 + </body> 262 + </html>
+1
out/index.html
··· 56 56 <li><a href="2.1-day-2-1.html#day-2-1" id="toc-day-2-1">Day 2</a></li> 57 57 <li><a href="2.2-day-4.html#day-4" id="toc-day-4">Day 4</a></li> 58 58 <li><a href="2.3-day-5.html#day-5" id="toc-day-5">Day 5</a></li> 59 + <li><a href="2.4-day-6.html#day-6" id="toc-day-6">Day 6</a></li> 59 60 </ul></li> 60 61 </ul> 61 62 </nav>
+1 -1
out/sitemap.json
··· 1 - {"section":{"id":"","level":"0","number":null,"path":"index.html","title":""},"subsections":[{"section":{"id":"section","level":"1","number":"1","path":"1-section.html#section","title":"2016"},"subsections":[{"section":{"id":"day-1","level":"2","number":"1.1","path":"1.1-day-1.html#day-1","title":"Day 1"},"subsections":[{"section":{"id":"part-1","level":"3","number":"1.1.1","path":"1.1-day-1.html#part-1","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2","level":"3","number":"1.1.2","path":"1.1-day-1.html#part-2","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-2","level":"2","number":"1.2","path":"1.2-day-2.html#day-2","title":"Day 2"},"subsections":[{"section":{"id":"part-1-1","level":"3","number":"1.2.1","path":"1.2-day-2.html#part-1-1","title":"Part 1"},"subsections":[]}]}]},{"section":{"id":"section-1","level":"1","number":"2","path":"2-section-1.html#section-1","title":"2025"},"subsections":[{"section":{"id":"day-2-1","level":"2","number":"2.1","path":"2.1-day-2-1.html#day-2-1","title":"Day 2"},"subsections":[{"section":{"id":"part-1-2","level":"3","number":"2.1.1","path":"2.1-day-2-1.html#part-1-2","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-1","level":"3","number":"2.1.2","path":"2.1-day-2-1.html#part-2-1","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-4","level":"2","number":"2.2","path":"2.2-day-4.html#day-4","title":"Day 4"},"subsections":[{"section":{"id":"part-1-3","level":"3","number":"2.2.1","path":"2.2-day-4.html#part-1-3","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-2","level":"3","number":"2.2.2","path":"2.2-day-4.html#part-2-2","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-5","level":"2","number":"2.3","path":"2.3-day-5.html#day-5","title":"Day 5"},"subsections":[{"section":{"id":"part-1-4","level":"3","number":"2.3.1","path":"2.3-day-5.html#part-1-4","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-3","level":"3","number":"2.3.2","path":"2.3-day-5.html#part-2-3","title":"Part 2"},"subsections":[]}]}]}]} 1 + {"section":{"id":"","level":"0","number":null,"path":"index.html","title":""},"subsections":[{"section":{"id":"section","level":"1","number":"1","path":"1-section.html#section","title":"2016"},"subsections":[{"section":{"id":"day-1","level":"2","number":"1.1","path":"1.1-day-1.html#day-1","title":"Day 1"},"subsections":[{"section":{"id":"part-1","level":"3","number":"1.1.1","path":"1.1-day-1.html#part-1","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2","level":"3","number":"1.1.2","path":"1.1-day-1.html#part-2","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-2","level":"2","number":"1.2","path":"1.2-day-2.html#day-2","title":"Day 2"},"subsections":[{"section":{"id":"part-1-1","level":"3","number":"1.2.1","path":"1.2-day-2.html#part-1-1","title":"Part 1"},"subsections":[]}]}]},{"section":{"id":"section-1","level":"1","number":"2","path":"2-section-1.html#section-1","title":"2025"},"subsections":[{"section":{"id":"day-2-1","level":"2","number":"2.1","path":"2.1-day-2-1.html#day-2-1","title":"Day 2"},"subsections":[{"section":{"id":"part-1-2","level":"3","number":"2.1.1","path":"2.1-day-2-1.html#part-1-2","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-1","level":"3","number":"2.1.2","path":"2.1-day-2-1.html#part-2-1","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-4","level":"2","number":"2.2","path":"2.2-day-4.html#day-4","title":"Day 4"},"subsections":[{"section":{"id":"part-1-3","level":"3","number":"2.2.1","path":"2.2-day-4.html#part-1-3","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-2","level":"3","number":"2.2.2","path":"2.2-day-4.html#part-2-2","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-5","level":"2","number":"2.3","path":"2.3-day-5.html#day-5","title":"Day 5"},"subsections":[{"section":{"id":"part-1-4","level":"3","number":"2.3.1","path":"2.3-day-5.html#part-1-4","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-3","level":"3","number":"2.3.2","path":"2.3-day-5.html#part-2-3","title":"Part 2"},"subsections":[]}]},{"section":{"id":"day-6","level":"2","number":"2.4","path":"2.4-day-6.html#day-6","title":"Day 6"},"subsections":[{"section":{"id":"part-1-5","level":"3","number":"2.4.1","path":"2.4-day-6.html#part-1-5","title":"Part 1"},"subsections":[]},{"section":{"id":"part-2-4","level":"3","number":"2.4.2","path":"2.4-day-6.html#part-2-4","title":"Part 2"},"subsections":[]}]}]}]}
+44 -1
out/style.css
··· 1 + :root { 2 + --bg-color: #ffffff; 3 + --text-color: #1a1a1a; 4 + --border-color: #e0e0e0; 5 + --link-color: #0066cc; 6 + --link-hover: #004499; 7 + --link-visited: #551a8b; 8 + --syntax-datatype: #8f4e8b; 9 + --syntax-comment: #6a737d; 10 + --syntax-keyword: #1a1a1a; 11 + } 12 + 13 + @media (prefers-color-scheme: dark) { 14 + :root { 15 + --bg-color: #000000; 16 + --text-color: #e8e8e8; 17 + --border-color: #404040; 18 + --link-color: #6eb5ff; 19 + --link-hover: #9fcdff; 20 + --link-visited: #d4a5ff; 21 + --syntax-datatype: #c792ea; 22 + --syntax-comment: #b0b0b0; 23 + --syntax-keyword: #e8e8e8; 24 + } 25 + } 26 + 1 27 body { 2 28 max-width: 1400px; 3 29 margin-left: auto; ··· 5 31 box-sizing: border-box; 6 32 padding: 0 5vw; 7 33 font-family: "Libre Baskerville", serif; 34 + background-color: var(--bg-color); 35 + color: var(--text-color); 8 36 } 9 37 10 38 .sitenav { ··· 35 63 overflow: auto; 36 64 } 37 65 66 + a { 67 + color: var(--link-color); 68 + } 69 + 70 + a:hover { 71 + color: var(--link-hover); 72 + } 73 + 74 + a:visited { 75 + color: var(--link-visited); 76 + } 77 + 78 + code span.dt { color: var(--syntax-datatype); } 79 + code span.co { color: var(--syntax-comment); font-style: italic; } 80 + code span.kw { color: var(--syntax-keyword); font-weight: bold; } 81 + 38 82 @media (max-width: 768px) { 39 83 body { 40 84 max-width: 100%; ··· 54 98 padding: 0; 55 99 } 56 100 } 57 -
+94
src/2025/06.lhs
··· 1 + ## Day 6 2 + 3 + This day is largely string munging, which is quite boring, but also quite easy to do with Haskell! 4 + 5 + ### Part 1 6 + 7 + This part needs us to consider each operation on a column. `Data.List.transpose` fortunately makes this very simple. If we are able to massage our input into the form `["+", "1", "2", "3"]`, we can use this simple `solve` function to produce the result. The only motivation to use this format is the ease of pattern-matching over the start of the list. 8 + 9 + ```haskell 10 + solve ("+" : rest) = sum . map read $ rest 11 + solve ("*" : rest) = product . map read $ rest 12 + ``` 13 + 14 + Thus, to solve the first part, we can break up our input using `lines`. `rot` is a simple function that rotates a list forwards to move the last element to the first. By doing `rot . lines` upon our input, we have a list of the form `["+ *", "1 2 3", "4 5 6"]`. Next, we define an `align` function to line up the colums. This method simply breaks each item in the list by spaces, and then transposes them, so we end up with `[["+", "1", "2", "3"], ["*", "4", "5", "6"]]`: 15 + 16 + ```haskell-top 17 + import Data.Char (isSpace) 18 + import Data.List (transpose) 19 + import Data.List.Split (splitWhen) 20 + ``` 21 + 22 + ```haskell 23 + rot = liftA2 (:) last init 24 + 25 + p1 = sum . map solve . align . rot . lines 26 + where 27 + align = transpose . map words 28 + ``` 29 + 30 + ### Part 2 31 + 32 + We are now tasked with lining up the digits in a columnar fashion to for a number: 33 + 34 + 123 ... 35 + 45 ... 36 + 6 ... 37 + * ... 38 + 39 + Here, the numbers to operate on are 356, 24 and 1. Unfortunately, we can no longer employ `words` as it breaks on all whitespace. We must now transpose our list as-is, to make sense of the digits. Ignore the last row for a second, and only consider the first 3 rows: 40 + 41 + 123 42 + 45 43 + 6 44 + 45 + Upon transposing this, we get: 46 + 47 + 1 48 + 24 49 + 356 50 + 51 + This is exactly what we need! 52 + 53 + Let us start with a similar base, using `lines` to break things up, and `rot` to move the line of operators to the start. Our `align` function can now be defined as below. 54 + 55 + ```haskell 56 + p2 = sum . map solve . align . rot . lines 57 + where 58 + align = 59 + zipWith (:) 60 + <$> (words . head) 61 + <*> (splitWhen (all isSpace) . transpose . tail) 62 + ``` 63 + 64 + We first start with `zipWith (:)` to join the operation `"+"` with the rest of the numbers to produce: 65 + 66 + ["+", "1", "2", ...] 67 + 68 + Remember that this is the format `solve` accepts! 69 + 70 + We are using `<*>` to perform "sequential application". The first part ... 71 + 72 + words . head 73 + 74 + ... is used to split up the operator line into a list of operators. 75 + 76 + The second part ... 77 + 78 + splitWhen (all isSpace) . transpose . tail 79 + 80 + ...is used to transpose numbers! Note what happens when we transpose the lines containing numbers, we get: 81 + 82 + ["1 ","24 ","356"," ","369","248","8 ", ...] 83 + 84 + There is an element containing all spaces (which was present between each column), `Data.List.Split.splitWhen` is employed to detect and chunk our list into runs of valid numbers. 85 + 86 + 87 + Finally, a main function to wrap it all up: 88 + 89 + ```haskell 90 + main = do 91 + n <- getContents 92 + print $ p1 n 93 + print $ p2 n 94 + ```