<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>/Wakamoleguy</title>
        <link>https://www.wakamoleguy.com</link>
        <description>Home of the wakamoleguy. Sometimes I write about things.</description>
        <lastBuildDate>Sat, 11 Apr 2026 08:34:58 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Hello, MDX! Hello, Islands! Goodbye, MDX!]]></title>
            <link>https://www.wakamoleguy.com/p/hello-mdx-hello-islands-goodbye-mdx</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/hello-mdx-hello-islands-goodbye-mdx</guid>
            <pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[For quite a while, I have been wanting to have this site support interactive widgets. I thought MDX would be the key to that. It wasn't, but I learned a lot along the way.]]></description>
            <content:encoded><![CDATA[<p>For quite a while, I have been wanting to have this site support interactive widgets. Getting that to work was more involved than I thought. Here is an interactive counter. Click the button, number goes up!</p><p><em>Interactive counter — view on the website</em></p><p>The thing is, adding these &quot;islands&quot; of interactivity to an otherwise static site is still annoyingly difficult today. So I set off on a journey to explore how to add interactive content to this site while maintaining a simple authoring experience, a code base and pipelines that I can understand, and a minimal set of rock solid dependencies.</p><p class="note">Granted, frameworks like <a href="https://astro.build/">Astro</a> are built for this; I didn&#x27;t have the appetite for a full site migration off of <a href="https://www.wakamoleguy.com/p/goodbye-heroku">Next.js</a>.</p><h2 id="enter-mdx">Enter MDX?</h2><p><a href="https://mdxjs.com/">MDX</a> is billed as &quot;Markdown for the component era.&quot; It allows you to write Markdown files, sprinkle in imported components, and export metadata. This sounds great! If I have a Markdown file, I could write something like this:</p><pre><code class="language-markdown lang-markdown">---
title: &#x27;Hello, MDX!&#x27;
---

import Counter from &#x27;./components/Counter&#x27;

blah blah interesting prose

&lt;Counter /&gt;

blah blah more interesting prose</code></pre><p>With Next&#x27;s app routing and the new-ish <code>@next/mdx</code> package, this seemed like a great opportunity to use a first-party framework package to introduce some nice new features to the blog. In practice, I ran into several issues.</p><h2 id="obstacle-1-dynamic-routes-to-mdx-pages">Obstacle 1: Dynamic routes to MDX pages</h2><p>My site is configured to render each post at a dynamic URL based on its ID. If you hit <code>/p/[id]</code>, and a matching file exists, you get the page. If you enter some other unknown slug, you get a 404 error. This is important to me, as it allows me to create a new page by dropping in a single markdown file. (While <a href="https://www.wakamoleguy.com/p/you-cant-avoid-markup">you can&#x27;t avoid markup</a>, my goal is minimal overhead.)</p><p>It turns out that Turbopack can&#x27;t handle this with MDX files. While the site is primarily statically built, that build still happens in two phases:</p><ol start="1"><li>Turbopack detects and bundles all routes.</li><li>Next.js runs those bundles to create server-rendered static builds.</li></ol><p>MDX support comes in only in the second phase, so the first phase fails. The workaround is to add a build step to convert the MDX files to TSX beforehand. That&#x27;s doable, but it increases the complexity of the build process. The dev server also requires a separate file watcher to run that build step outside of <code>next dev</code>, introducing further complexity.</p><p>Instead of adding a build step, I sidestepped the issue by reading the MDX files from the filesystem and evaluating them semi-manually with <code>@mdx-js/mdx</code> and <code>@mdx-js/mdx-react</code>. (These files are trusted content written by yours truly, so evaluating them does not pose a security risk.) This ends up using React&#x27;s <code>renderToStaticMarkup</code> under the hood. A similar process is also used for the index page&#x27;s list of posts and the site&#x27;s new RSS feed.</p><h2 id="obstacle-2-excluding-islands-from-the-rss-feed">Obstacle 2: Excluding Islands from the RSS feed</h2><p>As part of my desire to Publish on my Own Site, Syndicate Elsewhere (<a href="https://indieweb.org/POSSE">POSSE</a>), I added an RSS feed to my site. RSS feeds use XML, which looks a lot like HTML but has a few different behaviors. One major limitation is that you can&#x27;t use JavaScript and CSS. That means no interactive widgets in the RSS feed. That left me with two options: include only the descriptions of posts in the feed, or find a way to replace any interactive islands with fallback content. Since including the full text is best practice, that was my preference.</p><p>For a while, I explored whether we could have components that rendered their own fallback content. However, I hit a bigger obstacle: <em>any attempt to import the island components failed</em>. Islands are inherently client-side components. Take the Counter for example:</p><pre><code class="language-tsx lang-tsx">&#x27;use client&#x27;

import { useState } from &#x27;react&#x27;
import Island from &#x27;./island&#x27;

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    &lt;p&gt;
      Count: &lt;strong&gt;{count}&lt;/strong&gt;
    &lt;/p&gt;
    &lt;button onClick={() =&gt; setCount((c) =&gt; c + 1)}&gt;Increment&lt;/button&gt;
  )
}</code></pre><p><code>&#x27;use client&#x27;</code> tells Next that this component has to be rendered on the client. It cannot be statically rendered on the server. And yet, <code>renderToStaticMarkup</code> is inherently a server-side rendering environment. <em>Any</em> attempt to import Counter will fail with a loud error message. Including <code>&lt;noscript&gt;</code> content doesn&#x27;t matter if the server will never get to render it.</p><p class="note">I still ended up using fallback content within the islands anyways, for when folks visit the live site with JavaScript disabled.</p><h2 id="obstacle-3-rendering-islands-from-the-server">Obstacle 3: Rendering Islands from the Server</h2><p>This same <code>renderToStaticMarkup</code> limitation actually affected the live pages, too. Because I was rendering MDX files manually in my dynamic route, even the live website was generating build-time errors when including client-side components. The solution to both issues: <strong>ditch the direct imports and maintain a mapping of components to use during evaluation.</strong></p><p>Here&#x27;s what the mapping code looks like today:</p><pre><code class="language-tsx lang-tsx">import { compiler } from &#x27;markdown-to-jsx&#x27;
import { ComponentType, createElement } from &#x27;react&#x27;
import Counter from &#x27;./islands/counter&#x27;

type IslandName = &#x27;Counter&#x27;
type IslandMap = Record&lt;IslandName, ComponentType&gt;

const liveIslands: IslandMap = { Counter }
const rssIslands: IslandMap = {
  Counter: () =&gt; (
    &lt;p&gt;
      &lt;em&gt;Interactive counter — view on the website&lt;/em&gt;
    &lt;/p&gt;
  ),
}

export default function NextMarkdown({
  children,
  rss = false,
}: {
  children: string
  rss?: boolean
}) {
  return (
    &lt;&gt;
      {compiler(children, {
        createElement,
        wrapper: null,
        overrides: rss ? rssIslands : liveIslands,
      })}
    &lt;/&gt;
  )
}</code></pre><p>This adds overhead when adding an island to a post. Instead of importing directly into my blog post file, I need to separately add the component to the mappings. I spent a <em>long</em> time looking for alternatives here. The only other viable approach was to use script tags to hand off islands using vanilla JS. That seemed significantly worse from a developer experience perspective, although it may come in handy for non-React islands in the future.</p><p>In the end, maintaining the maps is overhead that I can tolerate. After all, I don&#x27;t use interactive islands very often, and when I do I need to define RSS fallback content anyways. Maintaining a live map and RSS map in the same file is not so bad.</p><h2 id="what-has-mdx-ever-done-for-me">What has MDX ever done for me?</h2><p>At this point, everything was working. I could write posts in single files like I did before, and adding interactive widgets had only a small amount of overhead. The pipelines for the live posts, home page listing, and RSS feed were very similar and maintainable.</p><p>Then I realized MDX wasn&#x27;t helping with any of it.</p><p><em>Without imports in the files, all I had was plain old Markdown with a worse metadata syntax!</em></p><pre><code class="language-markdown lang-markdown">export const metadata = {
title: &#x27;Hello, MDX!&#x27;
}

blah blah interesting prose

&lt;Counter /&gt;

blah blah more interesting prose</code></pre><h2 id="rolling-back-to-roll-forward">Rolling back to roll forward</h2><p>In the end, I (asked Claude to) roll back all of the posts to their previous format. I kept the new pipelines and component maps, using <code>markdown-to-jsx</code> and <code>graymatter</code> to extract the content instead of <code>@mdx-js/mdx</code>. It&#x27;s a bit anticlimactic, but in the end it&#x27;s still fewer dependencies.</p><p>This was definitely an interesting exploration, and I learned a lot more detail about Next, Turbopack, and server-side component rendering. Having been in the Angular world at work for some time, it was a good refresher. It does leave me feeling like the ideal solution is still out there somewhere. (Or maybe, it&#x27;s just Astro after all.)</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[One Task at a Time, Even with AI]]></title>
            <link>https://www.wakamoleguy.com/p/one-task-at-a-time-even-with-ai</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/one-task-at-a-time-even-with-ai</guid>
            <pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[AI tools are able to generate code quickly, but they also introduce new wait times in the development process.
Rather than using this wait time to kick off multiple tasks in parallel, I still do my best work when I limit
myself to one in-progress task at a time.
]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://imgs.xkcd.com/comics/compiling.png"/><p>I have been thinking a lot about AI-driven software development workflows lately, what bottlenecks they address and <a href="https://www.wakamoleguy.com/p/ai-dlc-solves-wrong-bottleneck">what bottlenecks they don&#x27;t</a>. I use Claude constantly throughout my day, and it has changed how I work as an Engineering Manager. Claude helps me review product specs, brainstorm team strategy, and understand our team&#x27;s spend over time. And when I do get time to code, it looks very different in 2026 compared to 2016. Unrecognizably different! And yet, <strong>I still do my best work when I limit myself to one in-progress task at a time.</strong></p><h2 id="coding-today-has-new-wait-times">Coding Today Has New Wait Times</h2><p>When I sit down to code today, I usually have both Claude Code and VS Code open. Six months ago, I would largely be working in VS Code, identifying next steps and shooting off small tasks to Claude to implement. It was an accelerant to typing the code I could already envision. Recently, models and tooling have gotten increasingly more powerful, and I have been using Claude to drive more of the exploration and planning process, much like I would with a junior engineer. Checking in, tweaking plans, raising additional concerns, and eventually approving the plan. After approval, Claude goes off and implements it step by step. Afterwards, I walk through reviewing the changes until I understand them thoroughly. Oftentimes, I&#x27;ll be making other edits here and there (e.g. fewer mutations, more functional style) until I feel confident taking ownership over the code. Push a branch, write a PR description (still by hand today!), and we&#x27;re good to go. This process works amazingly well for me today, and I&#x27;m routinely impressed by how well Claude explores, identifies key concerns, and plans the task, especially with the latest Opus model.</p><p class="note">In this post, I primarily mention Claude and Claude Code. You can substitute these for the models and tools of your choice. I&#x27;m most familiar with Claude and don&#x27;t want to clutter this post by repeatedly saying &quot;...and other tools.&quot;</p><p>This process, though, does break up what used to be a single session of deep focus with a few wait times. Depending on the complexity of the task, the initial exploration and implementation times can each take minutes. And if either needs to be iterated significantly, that adds additional waits. These wait times are killer for productivity—UX studies have shown time and again how delays in response times can cause humans to drop off from tasks. For a deeper dive into this, check out <a href="https://blog.chromium.org/2020/05/the-science-behind-web-vitals.html#:~:text=Interruptions%20due%20to%20waiting">the science behind Core Web Vitals</a>.</p><h2 id="ok-so-we-multitask">OK, so we multitask?</h2><p>My first response to this wait time was to multitask. If Claude is doing a lot of this work autonomously, I could use the wait times to kick off more Claude Code agents, and then review them one by one as they are ready. Spin up some git worktrees so they don&#x27;t conflict, and suddenly you&#x27;re the 10x rock star you always dreamed of.</p><p>The issue is that you&#x27;re still context switching across all of these tasks. The more related the tasks are, the more likely they are to legitimately conflict. And the less related they are, the more context switching you need to do to hop between them. That&#x27;s very draining! And for me, it started leading to one of these results:</p><ol start="1"><li>Pure exhaustion and zero joy. Suddenly in addition to my regular set of interruptions throughout the day, coding was also an endless game of whack-a-mole.</li><li>Don&#x27;t try to grok all of the context for each task, and trust Claude more on the results. This undermined my feeling of ownership over the code, and resulted in more bugs escaping, higher maintenance burden, and less understanding.</li><li>Don&#x27;t try to continue each task immediately. This creates the liability of work in progress: the task sits delivering zero user value, accumulating merge conflicts, context decay, and integration risk. Claude only reduced the sunk cost in creating it.</li></ol><p>It&#x27;s possible that everybody has a different level of multitasking that feels natural to them. For me, I was learning it was one task at a time.</p><h2 id="hold-the-context-embrace-the-wait">Hold the context, embrace the wait</h2><figure class="compact"><img src="https://imgs.xkcd.com/comics/compiling.png" alt="xkcd 303: Two people sword fighting while sitting in office chairs. &#x27;Are you coming to bed?&#x27; &#x27;I can&#x27;t. This is important.&#x27; &#x27;What?&#x27; &#x27;Someone is compiling.&#x27;"/><figcaption>Seriously, this is the best approach. Source: <a href="https://xkcd.com/303/">xkcd 303</a></figcaption></figure><p>In my role, I do have much less focus time than an individual contributor—escalations of urgent questions or bug reports, questions for our team from across the org, and of course meetings. It used to be very hard to find focus time around these. AI agents do help with this, as I <em>can</em> pause and resume them as needed or let them work asynchronously while I&#x27;m on a call. In these cases, the wait time is a feature.</p><p>But when I do have focus time? What I&#x27;ve actually found gets me the best results is to...just wait. Grab a coffee, stretch, listen to music. I don&#x27;t pay the cost of context switching, and I still get more, higher quality coding done than I did before. I still feel strong ownership over the results, and the joy of having built something. And at the end of the day, I feel satisfied, not stressed.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI-DLC Solves the Wrong Bottleneck]]></title>
            <link>https://www.wakamoleguy.com/p/ai-dlc-solves-wrong-bottleneck</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/ai-dlc-solves-wrong-bottleneck</guid>
            <pubDate>Tue, 11 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[My org adopted AI tools across Engineering, Product, and Design. One our teams had each engineer ship a full service, end-to-end, in a single week. Everyone's faster. So why aren't we shipping more of the _right_ things?
]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://www.wakamoleguy.com/img/sdlc-flow.svg"/><p>My org adopted AI tools across Engineering, Product, and Design. One of our teams had each engineer ship a full service, end-to-end, in a single week. Everyone&#x27;s faster. So why aren&#x27;t we shipping more of the <em>right</em> things?</p><p>One idea to address this that has been gaining mindshare in our org is an <a href="https://aws.amazon.com/blogs/devops/ai-driven-development-life-cycle/">AI-driven Development Lifecycle (AI-DLC)</a>. It was introduced by a solutions architect at AWS and promises to rebuild the software development process from the ground up for the age of AI agents. But when reading about AI-DLC, something didn&#x27;t resonate with me. It doesn&#x27;t address the real bottlenecks that our team is facing today, despite everybody across Engineering, Product, and Design using AI tools daily.</p><h2 id="the-premise">The Premise</h2><p>The AI-DLC narrative typically follows a pattern: teams adopt AI tools, developers go dramatically faster at writing code, they find themselves idle waiting for direction, and so the process expands to let developers drive more of the lifecycle end-to-end with minimal product intent. It&#x27;s pitched as a necessary reimagining of our software development process from first principles, to unlock the full potential of AI agents. &quot;We need automobiles and not the faster horse chariots.&quot; Ditch the old methods, which have &quot;product owners, developers, and architects spending most of their time on...SDLC rituals.&quot;</p><p>Now, I am all for first principles thinking here. But every meaningful change in how we build software has been an evolution, even from waterfall to agile principles. &quot;You can&#x27;t retrofit current processes because AI changed the world&quot; is a thought-terminating cliché. It prevents meaningful inspection of the real bottlenecks in how we develop software today, and it&#x27;s a recipe for unlearning past lessons. In the end, all software goes through the basic steps of Scope -&gt; Build -&gt; Ship at <em>some</em> level. That&#x27;s a real foundation we can build on.</p><p>And I definitely need to call this out: if you as a software engineer are spending <em>most</em> of your time in SDLC rituals, something is deeply wrong! The majority of your day should include focus time for deep work. If AWS is solving for that as part of the AI-DLC, it&#x27;s possible that <em>any</em> process reset would be a beneficial excuse to wipe the meeting load and start fresh. (Hey, maybe try Kanban!)</p><h2 id="where-is-the-bottleneck">Where is the bottleneck?</h2><p>So let&#x27;s go ahead and use first principles, but also look at our processes today and find the real bottlenecks. Can we adapt our current Scope -&gt; Build -&gt; Ship cycles to fit the age of AI?</p><p>We can definitely generate code faster today. Let&#x27;s assume for now that this code is all the same high-quality, well-understood, maintainable code that we&#x27;d get using traditional methods. (The jury is out on that; topic for another post.) To move faster, we want to pull more implementation-ready ideas into developers&#x27; hands. For my team, that&#x27;s where we are currently running dry. AI-DLC responds to this by loosening the definition of implementation-ready: give developers intents rather than fully scoped specs.</p><p>But did we ask why that source is drying up? Product and Design are also using AI tools every day. Why is that not resulting in more scoped ideas for development? On our team, it&#x27;s not because Product and Design are failing to move quickly. Just like developers, Product and Design have access to a sliding scale of speed vs quality when using AI assistance. So far, we&#x27;ve seen outputs that are faster <em>and</em> higher quality. I believe the bottleneck is further upstream. Now that code is fast, that upstream constraint is suddenly visible.</p><h2 id="the-bottlenecks-are-still-human">The Bottlenecks are Still Human</h2><figure><img src="https://www.wakamoleguy.com/img/sdlc-flow.svg" alt="The software development lifecycle: User Understanding, Stakeholder Alignment, Scope, Build, Ship, Validate. Scope, Build, and Ship are fast with AI. The bottlenecks are the human-heavy stages."/><figcaption>When Build gets fast, the constraint shifts to the human-heavy stages.</figcaption></figure><p>If Engineering, Product, and Design are all using AI tools to compress our cycle time, the bottlenecks shift to the inherently asynchronous, human-heavy parts of the process: user understanding, user validation, and stakeholder alignment. Together, these processes help to ensure the team is building the right thing (for the user, for the company). And yet, these are the hardest to speed up because they depend on external feedback loops and human judgement. AI-DLC attempts to address this through Mob Elaboration, but this runs into challenges. Let&#x27;s look at each one and how we might solve it.</p><h3 id="a-pipeline-for-proactive-user-understanding">A Pipeline for Proactive User Understanding</h3><p>AI-DLC relies on Mob Elaboration to make quick decisions in real time. What happens if you need additional user discovery? Traditionally, Product would take that question, go off and do some discovery, and come back with an answer later. If this is going to happen in real time, there needs to be a ready repository of user insights. A continuous background process can support this through, e.g., regular user interviews, support ticket analysis, tools like Productboard. When it&#x27;s time to build, you pull from this pool first rather than starting research from scratch.</p><p>However, there will still be times when the answer is not readily available. At that point, you&#x27;re left with a choice between making an uninformed decision in the moment or delaying the work. Since cycle times are very low, the cost of the uninformed decision may not be so high. (That&#x27;s one reason why Scrum uses timeboxes, after all.) The specifics of that tradeoff will vary from company to company and product to product.</p><p>If user understanding and discovery is difficult, the risk is that teams will bias towards work that requires little discovery, like bug fixes or performance optimizations. Your team will feel very productive while delivering less overall value.</p><h3 id="decouple-validation-choices">Decouple Validation Choices</h3><p>After shipping something, how do you validate whether it&#x27;s delivering on its goals? AI-DLC doesn&#x27;t address this. Validated learning takes time to collect, as real users interact with the product. This doesn&#x27;t need to run at the same speed as the development cycle. A feature can ship on Monday, another on Tuesday, and validation results from last week&#x27;s feature come back on Thursday (and feed into the insight reservoir). The build cycle is daily but the learn cycle might be weekly. That&#x27;s OK, as long as it&#x27;s actually happening and feeding back in.</p><p>If we&#x27;re not routinely validating what we build with real users, we risk building the wrong things; we ship a lot of features that nobody uses.</p><h3 id="lightweight-stakeholder-alignment">Lightweight Stakeholder Alignment</h3><p>Smaller batch sizes should make stakeholder alignment faster and easier; there&#x27;s less to disagree about when each unit of work is small. However, without a regular inspection point, ten individually reasonable daily decisions can add up to strategic drift that nobody intended. AI-DLC doesn&#x27;t address where the &quot;intents&quot; are coming from either, so presumably there is still some cadence for gathering those from stakeholders. It&#x27;s almost certainly not daily (there&#x27;s too much cross-functional collaboration needed), but maybe weekly or biweekly.</p><h2 id="evolution-not-revolution">Evolution, Not Revolution</h2><p>If we take this all into account, what are we left with?</p><ul><li><strong>Daily cycle:</strong> Scope -&gt; Build -&gt; Ship, agent-heavy execution on well-understood work drawn from a prioritized backlog.</li><li><strong>Continuous discovery:</strong> User research pipeline feeding an insight reservoir. Human-driven, async, running on its own natural cadence.</li><li><strong>Weekly cadence:</strong> Direction check and validation review, feeding learnings back into the reservoir and adjusting priorities.</li></ul><p>The process overall has recognizable components of Scrum (a weekly inspect-and-adapt loop), Kanban (a focus on flow and limiting work in progress), and Lean Startup (validated learning) methodologies. This makes sense: those processes arrived at their structures by solving fundamental coordination problems under uncertainty. AI didn&#x27;t eliminate those problems.</p><p>Instead of throwing out the old, if we want to squeeze the most productivity out of our new AI colleagues, we need to drill down to the true bottlenecks. That might mean focusing on a support system for the human-oriented, naturally asynchronous parts of the system today.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 13: Distress Signal]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day13</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day13</guid>
            <pubDate>Thu, 23 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[After a bit of a break, I'm returning to finish the Advent Calendar. In [Day 13: Distress Signal](https://adventofcode.com/2022/day/13), we sort packets and learn about the InstanceSigs Haskell language extension.
]]></description>
            <content:encoded><![CDATA[<p>It&#x27;s been several months since I paused on Advent of Code 2022, and I am now attempting to return. Today&#x27;s challenge, <a href="https://adventofcode.com/2022/day/13">Day 13: Distress Signal</a>, is one that I actually solved back in December but never wrote up. Let&#x27;s hope I can decipher the code!</p><h3 id="a-custom-ordering">A Custom Ordering</h3><p>The challenge today is largely to define a custom ordering for a recursive Packet data type. Our Packet data type captures the shape:</p><pre><code class="language-haskell lang-haskell">data Packet = Leaf Int | ListOf [Packet] deriving (Show, Eq)

parsePacket :: GenParser Char u Packet
parsePacket = try parseLeaf &lt;|&gt; parseList
  where
    parseLeaf = Leaf &lt;$&gt; parseInt
    parseList = between (char &#x27;[&#x27;) (char &#x27;]&#x27;) $ do
      packets &lt;- sepBy parsePacket (char &#x27;,&#x27;)
      return $ ListOf packets</code></pre><p>To define the ordering of Packets, we instanciate an Ord class for the type. The minimal definition is a compare function which can take 2 Packets and return LT, EQ, or GT. The code follows the problem description closely:</p><pre><code class="language-haskell lang-haskell">instance Ord Packet where
  compare :: Packet -&gt; Packet -&gt; Ordering
  compare (Leaf a) (Leaf b) = compare a b
  compare (Leaf a) bs = compare (ListOf [Leaf a]) bs
  compare as (Leaf b) = compare as (ListOf [Leaf b])
  compare (ListOf []) (ListOf []) = EQ
  compare (ListOf []) (ListOf _) = LT
  compare (ListOf _) (ListOf []) = GT
  compare (ListOf (a : as)) (ListOf (b : bs)) = case compare a b of
    EQ -&gt; compare (ListOf as) (ListOf bs)
    x -&gt; x</code></pre><h3 id="instance-signature">Instance Signature?</h3><p>Now, the code for our Ord instance is actually not valid Haskell! Instance declarations are not allowed to have type signatures in them. That&#x27;s the line with <code class="language-hs">compare :: Package -&gt; Packet -&gt; Ordering</code>. The instance should be able to infer all of this information.</p><p>However, sometimes providing the type signature is useful, especially for novices like me! It&#x27;s possible to enable this via the <code class="language-hs">{-# LANGUAGE InstanceSigs #-}</code> language extension.</p><p>By putting such a <a href="https://wiki.haskell.org/Language_extensions">language extension pragma</a> at the top of the file, we ask the compiler to enable additional language features. In this case it&#x27;s a simple and safe rule, but extensions can get pretty complex!</p><h3 id="part-1---parsing-the-list-of-pairs">Part 1 - Parsing the List of Pairs</h3><p>In Part 1, we want to process each pair of Packets together, and then count whether they are in the correct order. To parse them together, I wrote a helper <code class="language-hs">classlistToPair</code>:</p><pre><code class="language-haskell lang-haskell">listToPair :: Show a =&gt; [a] -&gt; (a, a)
listToPair [a, b] = (a, b)
listToPair l = error $ &quot;listToPair: invalid input: &quot; ++ show l</code></pre><p>We first split the list into sub-lists containing two elements, then convert those sublists into tuples. Since the parsing returns an Either, we provide a default <code class="language-hs">Leaf 0</code> fallback, although this should not be hit with our real input data.</p><pre><code class="language-haskell lang-haskell">input :: IO [(Packet, Packet)]
input =
  let rawPairs = splitOn [&quot;&quot;] . lines &lt;$&gt; readDay 2022 13
   in fmap (listToPair . fmap (fromRight (Leaf 0) . parse parsePacket &quot;&quot;)) &lt;$&gt; rawPairs</code></pre><p>Now that we have our list of pairs, we can find our answer to Part 1. If we were going to count the correctly ordered pairs, we could apply our <code class="language-hs">compare</code> function, filter out any incorrectly ordered pairs, and then take the length of the remaining list:</p><pre><code class="language-haskell lang-haskell">countOrdered :: [(Packet, Packet)] -&gt; Int
countOrdered =
  length
    . filter (== LT)
    . fmap (uncurry compare)</code></pre><p>However, we need the index of the resulting pairs, so let&#x27;s attach that to our items first. Then at the end, instead of counting, we will sum the index:</p><pre><code class="language-haskell lang-haskell">part1 :: [(Packet, Packet)] -&gt; Int
part1 =
  sum
    . fmap fst
    . filter (\(_, o) -&gt; o == LT)
    . fmap (fmap (uncurry compare))
    . zip [1 ..]</code></pre><h3 id="part-2">Part 2</h3><p>For Part 2, we are asked to sort the full list of Packets, ignoring the pairings. Additionally, we will sort our two divider packets, <code class="language-hs">[[2]]</code> and <code class="language-hs">[[6]]</code>. With our Ord instance, sorting is as simple as passing the list of Packets to <code class="language-hs">sort</code>!</p><p>Rather than parse our input again, I opted to start with the list of pairs, flattening it back into a single list:</p><pre><code class="language-haskell lang-haskell">part2 :: [(Packet, Packet)] -&gt; Int
part2 pairs = undefined -- TODO
  where
    dividers = [ListOf [ListOf [Leaf 2]], ListOf [ListOf [Leaf 6]]]
    sortedPackets = sort $ dividers ++ concatMap (\(a, b) -&gt; [a, b]) pairs</code></pre><p>Once we have our sorted list, we look for the indexes of our two dividers and multiply them together to get our final answer:</p><pre><code class="language-haskell lang-haskell">part2 :: [(Packet, Packet)] -&gt; Int
part2 pairs = product $ (+ 1) &lt;$&gt; mapMaybe (`elemIndex` sortedPackets) dividers
  where
    dividers = [ListOf [ListOf [Leaf 2]], ListOf [ListOf [Leaf 6]]]
    sortedPackets = sort $ dividers ++ concatMap (\(a, b) -&gt; [a, b]) pairs</code></pre><h3 id="do-you-need-to-fully-sort">Do you need to fully sort?</h3><p>Instead of sorting the full list, we could take a more target approach to finding the indexes of our dividers. The index of an element is only dependent on how many Packets sort lower than it, not the internal ordering of those packets.</p><p>Sorting the list is O(n log n). Sometimes Haskell&#x27;s laziness will allow us to skip some sorting in these cases. However, it must fully sort each item up until our dividers, so our Big O time is unchanged.</p><p>Counting how many Packets are less than a given divider is O(n), as it can be done in a single pass through the list. We have 2 dividers, adding a constant factor.</p><p>I didn&#x27;t end up implementing this approach, but it should have faster runtime characteristics on large lists (which frankly, is not our input).</p><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">{-# LANGUAGE InstanceSigs #-}

module AOC2022.Day13 (spec) where

import Data.Either
import Data.List (elemIndex, sort)
import Data.List.Split (splitOn)
import Data.Maybe (mapMaybe)
import Input
import Test.Hspec
import Text.ParserCombinators.Parsec

listToPair :: Show a =&gt; [a] -&gt; (a, a)
listToPair [a, b] = (a, b)
listToPair l = error $ &quot;listToPair: invalid input: &quot; ++ show l

input :: IO [(Packet, Packet)]
input =
  let rawPairs = splitOn [&quot;&quot;] . lines &lt;$&gt; readDay 2022 13
   in fmap (listToPair . fmap (fromRight (Leaf 0) . parse parsePacket &quot;&quot;)) &lt;$&gt; rawPairs

data Packet = Leaf Int | ListOf [Packet] deriving (Show, Eq)

parsePacket :: GenParser Char u Packet
parsePacket = try parseLeaf &lt;|&gt; parseList
  where
    parseLeaf = Leaf &lt;$&gt; parseInt
    parseList = between (char &#x27;[&#x27;) (char &#x27;]&#x27;) $ do
      packets &lt;- sepBy parsePacket (char &#x27;,&#x27;)
      return $ ListOf packets

instance Ord Packet where
  compare :: Packet -&gt; Packet -&gt; Ordering
  compare (Leaf a) (Leaf b) = compare a b
  compare (Leaf a) bs = compare (ListOf [Leaf a]) bs
  compare as (Leaf b) = compare as (ListOf [Leaf b])
  compare (ListOf []) (ListOf []) = EQ
  compare (ListOf []) (ListOf _) = LT
  compare (ListOf _) (ListOf []) = GT
  compare (ListOf (a : as)) (ListOf (b : bs)) = case compare a b of
    EQ -&gt; compare (ListOf as) (ListOf bs)
    x -&gt; x

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 13&quot; $ do
    describe &quot;Part 1&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part1 myInput `shouldBe` 0 -- redacted
    describe &quot;Part 2&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part2 myInput `shouldBe` 0 -- redacted

part1 :: [(Packet, Packet)] -&gt; Int
part1 =
  sum
    . fmap fst
    . filter (\(_, o) -&gt; o == LT)
    . fmap (fmap (uncurry compare))
    . zip [1 ..]

part2 :: [(Packet, Packet)] -&gt; Int
part2 pairs = product $ (+ 1) &lt;$&gt; mapMaybe (`elemIndex` sortedPackets) dividers
  where
    dividers = [ListOf [ListOf [Leaf 2]], ListOf [ListOf [Leaf 6]]]
    sortedPackets = sort $ dividers ++ concatMap (\(a, b) -&gt; [a, b]) pairs</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day12">Day 12: Hill Climbing Algorithm</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 12: Hill Climbing Algorithm]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day12</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day12</guid>
            <pubDate>Tue, 13 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 12: Hill Climbing Algorithm](https://adventofcode.com/2022/day/12), we write Dijkstra's algorithm from scratch!
]]></description>
            <content:encoded><![CDATA[<p>It&#x27;s <a href="https://adventofcode.com/2022/day/12">Day 12</a>, and it&#x27;s finally Dijkstra time! We need to find the shortest path on the graph, so let&#x27;s get right to it. In past years, I&#x27;ve used a library for Dijkstra&#x27;s, but this year I tried to roll it myself. Let&#x27;s see how that worked out!</p><h3 id="dijkstras-in-haskell">Dijkstra&#x27;s in Haskell</h3><p><a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra&#x27;s Algorithm</a> is an algorithm for finding the shortest distance between any two points on a graph. I&#x27;m not going to explain it much here, as there are many better resources for that.</p><p>In implementing Dijkstra&#x27;s, there are two pieces of state we care about: our queue of upcoming nodes to visit, and our set of nodes already visited (which we do not want to waste time revisting). With today&#x27;s simple problem, I used a Sequence and a Set (Haskell&#x27;s Set is tree-based). There are better data types for this! But these were simple and efficient enough.</p><p>Dijkstra&#x27;s is a recursive function, so we can keep track of our state by passing it from one recursive call to the next. Here is the meat of the algorithm:</p><pre><code class="language-haskell lang-haskell">go :: Array (Int, Int) Char -&gt; Set (Int, Int) -&gt; Seq ((Int, Int), Int) -&gt; Int
go g v q = case Seq.viewl q of
  (i, d) :&lt; q&#x27; -&gt;
    if i `elem` v
      then go g v q&#x27;
      else
        if i == goal g
          then d
          else go g (i `Set.insert` v) $ q&#x27; &gt;&lt; fromList (map (,d + 1) (filter (`notElem` v) (neighbors g i)))
  Seq.EmptyL -&gt; error &quot;empty queue&quot;</code></pre><p>We have our grid, our visited set, and our upcoming queue. Each iteration, we look at the first item in our queue. If it&#x27;s already visited, we ditch it and continue with the rest of the queue. If it&#x27;s the goal, we return its distance. If it&#x27;s any other node, we add it to our visited set, add its neighbors (with +1 distance) to our queue, and recurse.</p><h3 id="is-that-really-dijkstras">Is that really Dijkstra&#x27;s?</h3><p>Now wait a minute, we aren&#x27;t even using a priority queue here! Is this Dijkstra&#x27;s, or is it just a breadth-first search? To that I have two things to say:</p><ol start="1"><li>Every &#x27;edge&#x27; in our grid has a weight of 1, so this is equivalent to using a priority queue <em>in this particular scenario</em>.</li><li>We could use a priority queue if we want to, I was just being lazy.</li></ol><h3 id="the-nitty-gritty-of-goals-and-neighbors">The Nitty Gritty of Goals and Neighbors</h3><p>In the above code, <code>goal</code> is a helper function that finds the location of the &#x27;E&#x27; in our grid. I wrote a similar helper for &#x27;S&#x27;:</p><pre><code class="language-haskell lang-haskell">findCoord :: Ix a =&gt; Char -&gt; Array a Char -&gt; a
findCoord c = fst . head . filter (\(_, c&#x27;) -&gt; c == c&#x27;) . assocs

start :: Ix a =&gt; Array a Char -&gt; a
start = findCoord &#x27;S&#x27;

goal :: Ix a =&gt; Array a Char -&gt; a
goal = findCoord &#x27;E&#x27;</code></pre><p>Neighbors finds the indices to the north, south, east, and west, making sure that they remain in the grid and at an accessible elevation:</p><pre><code class="language-haskell lang-haskell">elev :: Char -&gt; Int
elev &#x27;S&#x27; = elev &#x27;a&#x27;
elev &#x27;E&#x27; = elev &#x27;z&#x27;
elev c = fromEnum c - fromEnum &#x27;a&#x27;

neighbors :: Array (Int, Int) Char -&gt; (Int, Int) -&gt; [(Int, Int)]
neighbors g i@(x, y) = do
  i&#x27; &lt;- [(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]
  guard $ inRange (bounds g) i&#x27;
  guard $ elev (g ! i&#x27;) &lt;= elev (g ! i) + 1
  return i&#x27;</code></pre><p>Part 1 then kicks off <code>go</code> with an empty visited set and our start node.</p><pre><code class="language-haskell lang-haskell">part1 :: Array (Int, Int) Char -&gt; Int
part1 g = go g Set.empty $ fromList [(start g, 0)]</code></pre><h3 id="part-2">Part 2</h3><p>In Part 2, we are looking for the shortest path from any &#x27;a&#x27; to &#x27;E&#x27;. There are two ways we could do this. First, we could store all of our &#x27;a&#x27; locations as our initial set and run the code again. Perhaps more cleanly, though, we can reverse our search. We&#x27;ll start at &#x27;E&#x27; and look backwards until land on any &#x27;a&#x27;. We&#x27;ll need a new function for downhill neighbors:</p><pre><code class="language-haskell lang-haskell">downhill :: Array (Int, Int) Char -&gt; (Int, Int) -&gt; [(Int, Int)]
downhill g i@(x, y) = do
  i&#x27; &lt;- [(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]
  guard $ inRange (bounds g) i&#x27;
  guard $ elev (g ! i&#x27;) &gt;= elev (g ! i) - 1
  return i&#x27;</code></pre><p>We can abstract out our neighbors and goal functions, to reuse the logic from Part 1:</p><pre><code class="language-haskell lang-haskell">go :: ((Int, Int) -&gt; Bool) -&gt; ((Int, Int) -&gt; [(Int, Int)]) -&gt; Array (Int, Int) Char -&gt; Set (Int, Int) -&gt; Seq ((Int, Int), Int) -&gt; Int
go isGoal n g v q = case Seq.viewl q of
  (i, d) :&lt; q&#x27; -&gt;
    if i `elem` v
      then go isGoal n g v q&#x27;
      else
        if isGoal i
          then d
          else go isGoal n g (i `Set.insert` v) $ q&#x27; &gt;&lt; fromList (map (,d + 1) (filter (`notElem` v) (n i)))
  Seq.EmptyL -&gt; error &quot;empty queue&quot;

part1 :: Array (Int, Int) Char -&gt; Int
part1 g = go (== goal g) (neighbors g) g Set.empty $ fromList [(start g, 0)]

part2 :: Array (Int, Int) Char -&gt; Int
part2 g = go ((== 0) . elev . (g !)) (downhill g) g Set.empty $ fromList [(goal g, 0)]</code></pre><h3 id="full-code">Full Code</h3><p class="note">There are aspects of this implementation that are not very efficient. Typically, I believe &#x27;go isGoal neighbors&#x27; is bound once, so that the function isn&#x27;t evaluated fresh every single iteration. Check out the <a href="https://hackage.haskell.org/package/astar">aStar package</a> for more professional examples. I&#x27;ll likely use that on future days as needed.</p><pre><code class="language-haskell lang-haskell">{-# LANGUAGE TupleSections #-}

module AOC2022.Day12 (spec) where

import Control.Monad (guard)
import Data.Array
  ( Array,
    Ix (inRange),
    assocs,
    bounds,
    listArray,
    (!),
  )
import Data.Sequence (Seq, ViewL ((:&lt;)), fromList, (&gt;&lt;))
import qualified Data.Sequence as Seq
import Data.Set (Set)
import qualified Data.Set as Set
import Input (readDay)
import Test.Hspec (describe, hspec, it, shouldBe)

input :: IO (Array (Int, Int) Char)
input = listArray ((-20, 0), (20, 160)) . filter (/= &#x27;\n&#x27;) &lt;$&gt; readDay 2022 12

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 12&quot; $ do
    describe &quot;Part 1&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part1 myInput `shouldBe` 0 -- redacted
    describe &quot;Part 2&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part2 myInput `shouldBe` 0 -- redacted

findCoord :: Ix a =&gt; Char -&gt; Array a Char -&gt; a
findCoord c = fst . head . filter (\(_, c&#x27;) -&gt; c == c&#x27;) . assocs

start :: Ix a =&gt; Array a Char -&gt; a
start = findCoord &#x27;S&#x27;

goal :: Ix a =&gt; Array a Char -&gt; a
goal = findCoord &#x27;E&#x27;

elev :: Char -&gt; Int
elev &#x27;S&#x27; = elev &#x27;a&#x27;
elev &#x27;E&#x27; = elev &#x27;z&#x27;
elev c = fromEnum c - fromEnum &#x27;a&#x27;

neighbors :: Array (Int, Int) Char -&gt; (Int, Int) -&gt; [(Int, Int)]
neighbors g i@(x, y) = do
  i&#x27; &lt;- [(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]
  guard $ inRange (bounds g) i&#x27;
  guard $ elev (g ! i&#x27;) &lt;= elev (g ! i) + 1
  return i&#x27;

go :: ((Int, Int) -&gt; Bool) -&gt; ((Int, Int) -&gt; [(Int, Int)]) -&gt; Array (Int, Int) Char -&gt; Set (Int, Int) -&gt; Seq ((Int, Int), Int) -&gt; Int
go isGoal n g v q = case Seq.viewl q of
  (i, d) :&lt; q&#x27; -&gt;
    if i `elem` v
      then go isGoal n g v q&#x27;
      else
        if isGoal i
          then d
          else go isGoal n g (i `Set.insert` v) $ q&#x27; &gt;&lt; fromList (map (,d + 1) (filter (`notElem` v) (n i)))
  Seq.EmptyL -&gt; error &quot;empty queue&quot;

part1 :: Array (Int, Int) Char -&gt; Int
part1 g = go (== goal g) (neighbors g) g Set.empty $ fromList [(start g, 0)]

downhill :: Array (Int, Int) Char -&gt; (Int, Int) -&gt; [(Int, Int)]
downhill g i@(x, y) = do
  i&#x27; &lt;- [(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]
  guard $ inRange (bounds g) i&#x27;
  guard $ elev (g ! i&#x27;) &gt;= elev (g ! i) - 1
  return i&#x27;

part2 :: Array (Int, Int) Char -&gt; Int
part2 g = go ((== 0) . elev . (g !)) (downhill g) g Set.empty $ fromList [(goal g, 0)]</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day13">Day 13: Distress Signal</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day11">Day 11: Monkey in the Middle</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 11: Monkey in the Middle]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day11</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day11</guid>
            <pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 11: Monkey in the Middle](https://adventofcode.com/2022/day/11), we carefully watch the items thrown from monkey to monkey. But did *you* see the moonwalking bear?
]]></description>
            <content:encoded><![CDATA[<p>With this <a href="https://adventofcode.com/2022/day/11">Day 11: Monkey in the Middle</a> challenge, I had hoped to use something clever to keep track of the throws. Perhaps the Writer monad could be tacked on to my simulation to sum the throws as we went? But alas, I wasn&#x27;t able to get that working, since each monkey needs their own throw counter.</p><p>In the end, the code is pretty straight forward. We define a data type for our monkeys. We need indexed access to them, so we store them in an Array. Since we&#x27;re appending a lot of items to the end of lists, I used Data.Sequence instead of a plain list.</p><p>Parsing this input seemed like a waste of time, so you&#x27;ll see the hard-coded list of monkeys in the code below.</p><h3 id="wait-but-part-2">Wait But Part 2?</h3><p>The key insight in Part 2 is to use modular arithmetic to keep the numbers small. Each of the inspect operations checks whether a result is divisible by a small prime number, and addition and squaring preserve that test when taken modulo that same number.</p><p>Since all of our test functions use different numbers, we take the least common multiple as our worst case. This is somewhere around 10 million (or 223 million if you want the example to work!)</p><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">module AOC2022.Day11 (spec) where

import Data.Array
  ( Array,
    accum,
    elems,
    indices,
    listArray,
    (!),
    (//),
  )
import Data.Foldable (toList)
import Data.List (foldl&#x27;, sortOn)
import Data.Ord (Down (Down))
import Data.Sequence (Seq, empty, fromList, length, (|&gt;))
import Test.Hspec (describe, hspec, it, shouldBe)
import Prelude hiding (length)

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 11&quot; $ do
    describe &quot;Part 1&quot; $ do
      it &quot;runs on custom input&quot; $ do
        part1 exampleMonkeys `shouldBe` 10605
        part1 myMonkeys `shouldBe` 0 -- redacted
    describe &quot;Part 2&quot; $ do
      it &quot;runs on custom input&quot; $ do
        part2 exampleMonkeys `shouldBe` 2713310158
        part2 myMonkeys `shouldBe` 0 -- redacted

data Monkey = Monkey
  { items :: Seq Int,
    operation :: Int -&gt; Int,
    test :: Int -&gt; Int,
    throwCount :: Int
  }

exampleMonkeys :: Array Int Monkey
exampleMonkeys =
  listArray
    (0, 3)
    [ Monkey (fromList [79, 98]) (* 19) (\x -&gt; if x `mod` 23 == 0 then 2 else 3) 0,
      Monkey (fromList [54, 65, 75, 74]) (+ 6) (\x -&gt; if x `mod` 19 == 0 then 2 else 0) 0,
      Monkey (fromList [79, 60, 97]) (\x -&gt; x * x) (\x -&gt; if x `mod` 13 == 0 then 1 else 3) 0,
      Monkey (fromList [74]) (+ 3) (\x -&gt; if x `mod` 17 == 0 then 0 else 1) 0
    ]

maxmod :: Int
maxmod = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23

myMonkeys :: Array Int Monkey
myMonkeys =
  listArray
    (0, 7)
    [ Monkey (fromList [63, 84, 80, 83, 84, 53, 88, 72]) (* 11) (\x -&gt; if x `mod` 13 == 0 then 4 else 7) 0,
      Monkey (fromList [67, 56, 92, 88, 84]) (+ 4) (\x -&gt; if x `mod` 11 == 0 then 5 else 3) 0,
      Monkey (fromList [52]) (\x -&gt; x * x) (\x -&gt; if even x then 3 else 1) 0,
      Monkey (fromList [59, 53, 60, 92, 69, 72]) (+ 2) (\x -&gt; if x `mod` 5 == 0 then 5 else 6) 0,
      Monkey (fromList [61, 52, 55, 61]) (+ 3) (\x -&gt; if x `mod` 7 == 0 then 7 else 2) 0,
      Monkey (fromList [79, 53]) (+ 1) (\x -&gt; if x `mod` 3 == 0 then 0 else 6) 0,
      Monkey (fromList [59, 86, 67, 95, 92, 77, 91]) (+ 5) (\x -&gt; if x `mod` 19 == 0 then 4 else 0) 0,
      Monkey (fromList [58, 83, 89]) (* 19) (\x -&gt; if x `mod` 17 == 0 then 2 else 1) 0
    ]

catchItem :: Monkey -&gt; Int -&gt; Monkey
catchItem monkey item = monkey {items = items monkey |&gt; item}

step :: (Int -&gt; Int) -&gt; Array Int Monkey -&gt; Int -&gt; Array Int Monkey
step worryReducer monkeys i = monkeys&#x27;
  where
    m = monkeys ! i
    itemThrows = (\item -&gt; (test m item, item)) . worryReducer . operation m &lt;$&gt; items m
    m&#x27; = m {items = empty, throwCount = throwCount m + length itemThrows}
    monkeys&#x27; = accum catchItem monkeys (toList itemThrows) // [(i, m&#x27;)]

oneRound :: (Int -&gt; Int) -&gt; Array Int Monkey -&gt; Array Int Monkey
oneRound worryReducer monkeys = foldl&#x27; (step worryReducer) monkeys $ indices monkeys

monkeyBusiness :: Array Int Monkey -&gt; Int
monkeyBusiness = product . take 2 . sortOn Down . elems . fmap throwCount

part1 :: Array Int Monkey -&gt; Int
part1 monkeys = monkeyBusiness $ foldl&#x27; (const . oneRound (`div` 3)) monkeys [1 .. 20]

part2 :: Array Int Monkey -&gt; Int
part2 monkeys = monkeyBusiness $ foldl&#x27; (const . oneRound (`mod` maxmod)) monkeys [1 .. 10000]</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day12">Day 12: Hill Climbing Algorithm</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day10">Day 10: Cathode-Ray Tube</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 10: Cathode-Ray Tube]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day10</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day10</guid>
            <pubDate>Sun, 11 Dec 2022 17:30:00 GMT</pubDate>
            <description><![CDATA[In [Day 10: Cathod-Ray Tube](https://adventofcode.com/2022/day/10), we simulate the processer of a small device using the State monad. Plus, we use some fancy characters for printing.
]]></description>
            <content:encoded><![CDATA[<p>In today&#x27;s double feature, we&#x27;re tackling <a href="https://adventofcode.com/2022/day/10">Day 10: Cathod-Ray Tube</a>. The challenge is to use a list of assembly-code-like instructions to simulate the state of a small device.</p><p><em>Catching strong 2019 vibes...</em></p><h3 id="parsing-the-instructions">Parsing the instructions</h3><p>Parsing this input line by line is typical of most days. We split it into lines, and then create a small Parsec parser that can convert those lines to a data type. The data type then allows us to do pattern matching in our other &quot;business logic&quot; functions.</p><p>There are two small notes today:</p><ol start="1"><li>I unwrapped the result with <code class="language-hs">fromRight []</code> so that my tests don&#x27;t need to operate on Eithers. This did, however, cause me to miss a parsing error for some time, as it was silently replaced with a valid-but-empty list of instructions.</li><li>Our <code class="language-hs">parseInt</code> function needed to be expanded to handle negative numbers. Whoops! <code class="language-hs">parseInt = read &lt;$&gt; many1 (char &#x27;-&#x27; &lt;|&gt; digit)</code></li></ol><p>Here&#x27;s the rest of the parsing code:</p><pre><code class="language-haskell lang-haskell">import Data.Either
import Input
import Text.ParserCombinators.Parsec

data Instruction = Noop | Addx Int
  deriving (Show, Eq)

parseInstruction :: GenParser Char u Instruction
parseInstruction = parseNoop &lt;|&gt; parseAddx
  where
    parseNoop = try $ string &quot;noop&quot; &gt;&gt; return Noop
    parseAddx = try $ string &quot;addx &quot; &gt;&gt; Addx &lt;$&gt; parseInt

input :: IO [Instruction]
input = fromRight [] . traverse (parse parseInstruction &quot;&quot;) . lines &lt;$&gt; readDay 2022 10</code></pre><h3 id="running-instructions-with-state">Running Instructions With State</h3><p>We have a list of instructions and a register, and our goal is to simulate &quot;cycles.&quot; We need a way to keep track of the result of each cycle <em>and</em> the state of the register for the next cycle. We can do that with the State monad!</p><p>With the <a href="http://learnyouahaskell.com/for-a-few-monads-more#state">State monad</a>, we define each computation as a function from some previous state, to both a value and an updated state. We can chain these computations together, and each will receive the state from the previous computation.</p><p>Since we need to know the value of the register at any arbitrary cycle, let&#x27;s have each instruction return a list of those values. The noop instruction takes one cycle to complete, so it will return a list with just one of the register value in it. The addx instruction takes two cycles, so it will return a list of length 2.</p><pre><code class="language-haskell lang-haskell">noop :: State Int [Int]
noop = do
  x &lt;- get
  return [x]

addx :: Int -&gt; State Int [Int]
addx v = do
  x &lt;- get
  put (x + v) -- Update the register for the next instruction
  return [x, x] -- Takes 2 cycles to complete

step :: Instruction -&gt; State Int [Int]
step Noop = noop
step (Addx v) = addx v</code></pre><h3 id="part-1---compute-and-inspect">Part 1 - Compute and inspect</h3><p>For part 1, we want to run our computation and inspect the value at particular cycles. We&#x27;ll use a function <code class="language-hs">compute</code> to calculate a list of Int pairs. Let&#x27;s look at the code first:</p><pre><code class="language-haskell lang-haskell">compute :: [Instruction] -&gt; [(Int, Int)]
compute = zip [1 ..] . flip evalState 1 . fmap concat . traverse step</code></pre><p>What is this doing?</p><ol start="1"><li><p><code class="language-hs">traverse step</code>: Look at the type of traverse:</p><pre><code class="language-haskell lang-haskell">traverse :: (Traversable t, Applicative f) =&gt; (a -&gt; f b) -&gt; t a -&gt; f (t b)</code></pre><p>Step is our function from Instruction to State Int [Int]. Our second argument comes from <code>compute</code> and is a list of Instructions. Our return type is then a State Int [[Int]]. In other words, a computation that can be given an initial state and result in a list of lists of register values.</p></li><li><p><code class="language-hs">fmap concat</code>: Flatten our list-of-lists into a single list of register values. We use <code>fmap</code> to concatenate the value inside the State monad (which is also a Functor).</p></li><li><p><code class="language-hs">flip evalState 1</code>: Run our stateful computation with the initial register value of 1.</p></li><li><p><code class="language-hs">zip [1 ..]</code>: Attach the cycle count to each register value. This will make it easier to find the 20th, 60th, etc.</p></li></ol><h3 id="part-1---signal-strength">Part 1 - Signal Strength</h3><p>With all that in place, the only remaining piece of Part 1 is to compute the signal strength:</p><pre><code class="language-haskell lang-haskell">part1 :: [Instruction] -&gt; Int
part1 = sum . fmap signalStrength . compute
  where
    signalStrength (i, x)
      | i `mod` 40 == 20 &amp;&amp; i &lt;= 220 = i * x
      | otherwise = 0</code></pre><h3 id="part-2---rendering-sprites">Part 2 - Rendering Sprites</h3><p>Part 2 sounds much more complicated than it turns out to be. We have our computation all ready to go, so we just need to see if the cycle instruction and register value correspond to painting a pixel or not. The cycle instruction is 1-indexed, so we need to subtract 1 and modulo the length of the line (40). If that&#x27;s within 1 of the register value, we paint a pixel.</p><p>Advent of Code examples use <code>.</code> and <code>#</code> to represent dark and light squares. I&#x27;ve learned my lesson over the years, and will use the much clearer &#x27;⬛&#x27; and &#x27;🟩&#x27;.</p><pre><code class="language-haskell lang-haskell">part2 :: [Instruction] -&gt; String
part2 = unlines . chunksOf 40 . fmap render . compute
  where
    render (i, x) = if abs (x - ((i - 1) `mod` 40)) &lt;= 1 then &#x27;🟩&#x27; else &#x27;⬛&#x27;</code></pre><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">module AOC2022.Day10 (spec) where

import Control.Monad.State.Lazy
import Data.Either
import Data.List.Split
import Input
import Test.Hspec
import Text.ParserCombinators.Parsec hiding (State)

input :: IO [Instruction]
input = fromRight [] . traverse (parse parseInstruction &quot;&quot;) . lines &lt;$&gt; readDay 2022 10

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 10&quot; $ do
    describe &quot;Part 1&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part1 myInput `shouldBe` 0 -- redacted
    describe &quot;Part 2&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part2 myInput `shouldBe` &quot;&quot; --redacted

data Instruction = Noop | Addx Int
  deriving (Show, Eq)

parseInstruction :: GenParser Char u Instruction
parseInstruction = parseNoop &lt;|&gt; parseAddx
  where
    parseNoop = try $ string &quot;noop&quot; &gt;&gt; return Noop
    parseAddx = try $ string &quot;addx &quot; &gt;&gt; Addx &lt;$&gt; parseInt

noop :: State Int [Int]
noop = do
  x &lt;- get
  return [x]

addx :: Int -&gt; State Int [Int]
addx v = do
  x &lt;- get
  put (x + v) -- Update the register
  return [x, x] -- Takes 2 cycles to complete

step :: Instruction -&gt; State Int [Int]
step Noop = noop
step (Addx v) = addx v

compute :: [Instruction] -&gt; [(Int, Int)]
compute = zip [1 ..] . flip evalState 1 . fmap concat . traverse step

part1 :: [Instruction] -&gt; Int
part1 = sum . fmap signalStrength . compute
  where
    signalStrength (i, x)
      | i `mod` 40 == 20 &amp;&amp; i &lt;= 220 = i * x
      | otherwise = 0

part2 :: [Instruction] -&gt; String
part2 = unlines . chunksOf 40 . fmap render . compute
  where
    render (i, x) = if abs (x - ((i - 1) `mod` 40)) &lt;= 1 then &#x27;🟩&#x27; else &#x27;⬛&#x27;</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day11">Day 11: Monkey in the Middle</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day09">Day 9: Rope Bridge</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 9: Rope Bridge]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day09</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day09</guid>
            <pubDate>Sun, 11 Dec 2022 12:30:00 GMT</pubDate>
            <description><![CDATA[In [Day 9: Rope Bridge](https://adventofcode.com/2022/day/9), we simulate a swinging rope with recursive rules.
]]></description>
            <content:encoded><![CDATA[<p>I&#x27;m still running a couple days behind, and so this grey Sunday I am tackling <a href="https://adventofcode.com/2022/day/9">Day 9: Rope Bridge</a>. We&#x27;re asked to simulate the movement of a rope, where the tail of the rope follows along with the movements of the head.</p><h3 id="the-ways-ropes-move">The Ways Ropes Move</h3><p>Unusually, today I didn&#x27;t start with parsing! Instead, I jumped right into modeling the rules of motion. There are two that we care about: the head following steps directly from our input file, and the tail being lazily tugged along behind it.</p><pre><code class="language-haskell lang-haskell">-- Tugs the first argument towards the second argument
tug :: (Int, Int) -&gt; (Int, Int) -&gt; (Int, Int)
tug (x, y) (a, b)
  | isTouching = (x, y)
  | x &lt; a &amp;&amp; y &lt; b = (x + 1, y + 1)
  | x &gt; a &amp;&amp; y &gt; b = (x - 1, y - 1)
  | x &lt; a &amp;&amp; y &gt; b = (x + 1, y - 1)
  | x &gt; a &amp;&amp; y &lt; b = (x - 1, y + 1)
  | x &lt; a = (x + 1, y)
  | x &gt; a = (x - 1, y)
  | y &lt; b = (x, y + 1)
  | y &gt; b = (x, y - 1)
  | otherwise = (x, y)
  where
    isTouching = abs (x - a) &lt;= 1 &amp;&amp; abs (y - b) &lt;= 1

data Direction = North | South | East | West deriving (Show, Eq)

step :: (Int, Int) -&gt; Direction -&gt; (Int, Int)
step (x, y) North = (x, y + 1)
step (x, y) South = (x, y - 1)
step (x, y) East = (x + 1, y)
step (x, y) West = (x - 1, y)</code></pre><p>The tug function isn&#x27;t pretty, but it works!</p><h3 id="parsing-the-input">Parsing The Input</h3><p>We have a list of commands in our input. Each line can represent several individual motions, but we really want to simulate them one by one. Let&#x27;s expand them out.</p><pre><code class="language-haskell lang-haskell">strToDir :: Char -&gt; Direction
strToDir &#x27;U&#x27; = North
strToDir &#x27;D&#x27; = South
strToDir &#x27;R&#x27; = East
strToDir &#x27;L&#x27; = West
strToDir c = error $ &quot;Invalid direction: &quot; ++ show c

input :: IO [Direction]
input = concatMap parseMotions . lines &lt;$&gt; readDay 2022 9
  where
    parseMotions (d : &#x27; &#x27; : n) = replicate (read n) (strToDir d)
    parseMotions _ = error &quot;Invalid motion&quot;</code></pre><h3 id="simulating-the-rope">Simulating the Rope</h3><p>How do we simulate the rope? Well, the head of the rope moves according to the direction, and the tail of the rope follows. I had a hunch (read: saw on Reddit) that Part 2 may involve a longer rope, so I structured it as a recursive function:</p><pre><code class="language-haskell lang-haskell">stepRope :: [(Int, Int)] -&gt; Direction -&gt; [(Int, Int)]
stepRope (h : t) dir = step h dir : follow (step h dir) t
  where
    follow prev (next : rest) = tug next prev : follow (tug next prev) rest
    follow _ [] = []</code></pre><p>This pretty closely matches how we&#x27;d describe it in English, which is one thing I love about the expressiveness of Haskell.</p><p>Now we want to fold our list of steps over our rope to simulate its motion. But wait! We care about each state along the way, so instead of <code>fold</code> we use <code>scan</code>. Tracking the tail locations is as simple as getting the last item from each scan result, filtering to only unique coordinates, and counting them up.</p><pre><code class="language-haskell lang-haskell">part1 :: [Direction] -&gt; Int
part1 = length . nub . fmap last . scanl stepRope [(0, 0), (0, 0)]</code></pre><p>Part 2 is a longer rope, with 10 knots, but looks precisely the same:</p><pre><code class="language-haskell lang-haskell">part2 :: [Direction] -&gt; Int
part2 = length . nub . fmap last . scanl stepRope (replicate 10 (0, 0))</code></pre><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">module AOC2022.Day09 (spec) where

import Data.List
import Input
import Test.Hspec

data Direction = North | South | East | West deriving (Show, Eq)

strToDir :: Char -&gt; Direction
strToDir &#x27;U&#x27; = North
strToDir &#x27;D&#x27; = South
strToDir &#x27;R&#x27; = East
strToDir &#x27;L&#x27; = West
strToDir c = error $ &quot;Invalid direction: &quot; ++ show c

input :: IO [Direction]
input = concatMap parseMotions . lines &lt;$&gt; readDay 2022 9
  where
    parseMotions (d : &#x27; &#x27; : n) = replicate (read n) (strToDir d)
    parseMotions _ = error &quot;Invalid motion&quot;

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 9&quot; $ do
    describe &quot;Part 1&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        stepRope [(1, 1), (0, 0)] North `shouldBe` [(1, 2), (1, 1)]
        part1 myInput `shouldBe` 0 -- redacted
    describe &quot;Part 2&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part2 myInput `shouldBe` 0 -- redacted

-- Tugs the first argument towards the second argument
tug :: (Int, Int) -&gt; (Int, Int) -&gt; (Int, Int)
tug (x, y) (a, b)
  | isTouching = (x, y)
  | x &lt; a &amp;&amp; y &lt; b = (x + 1, y + 1)
  | x &gt; a &amp;&amp; y &gt; b = (x - 1, y - 1)
  | x &lt; a &amp;&amp; y &gt; b = (x + 1, y - 1)
  | x &gt; a &amp;&amp; y &lt; b = (x - 1, y + 1)
  | x &lt; a = (x + 1, y)
  | x &gt; a = (x - 1, y)
  | y &lt; b = (x, y + 1)
  | y &gt; b = (x, y - 1)
  | otherwise = (x, y)
  where
    isTouching = abs (x - a) &lt;= 1 &amp;&amp; abs (y - b) &lt;= 1

step :: (Int, Int) -&gt; Direction -&gt; (Int, Int)
step (x, y) North = (x, y + 1)
step (x, y) South = (x, y - 1)
step (x, y) East = (x + 1, y)
step (x, y) West = (x - 1, y)

stepRope :: [(Int, Int)] -&gt; Direction -&gt; [(Int, Int)]
stepRope (h : t) dir = step h dir : follow (step h dir) t
  where
    follow prev (next : rest) = tug next prev : follow (tug next prev) rest
    follow _ [] = []
stepRope [] _ = []

part1 :: [Direction] -&gt; Int
part1 = length . nub . fmap last . scanl stepRope [(0, 0), (0, 0)]

part2 :: [Direction] -&gt; Int
part2 = length . nub . fmap last . scanl stepRope (replicate 10 (0, 0))
</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day10">Day 10: Cathode-Ray Tube</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day08">Day 8: Treetop Tree House</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 8: Treetop Tree House]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day08</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day08</guid>
            <pubDate>Sat, 10 Dec 2022 16:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 8: Treetop Tree House](https://adventofcode.com/2022/day/8), we use the list monad to simulatenously step in any of four cardinal directions.
]]></description>
            <content:encoded><![CDATA[<p>It&#x27;s <a href="https://adventofcode.com/2022/day/8">Day 8: Treetop Tree House</a>, or at least it was a couple days ago... I&#x27;m still catching up. Today, we&#x27;re faced with a grid of trees, and asked to do some visibility checks.</p><p>First thought: Oy vey, another Array problem?</p><h3 id="at-least-the-parsing-is-easy">At Least the Parsing is Easy</h3><p>Let&#x27;s read in our grid as a list of numbers, and then drop them in an array. Our grid size is conveniently square, so we can get away with an easy <code>length</code> check.</p><pre><code class="language-haskell lang-haskell">input :: IO (Array (Int, Int) Int)
input = do
  s &lt;- lines &lt;$&gt; readDay 2022 8
  return $ listArray ((1, 1), (length s, length s)) $ digitToInt &lt;$&gt; concat s</code></pre><h3 id="part-1-visibility-from-the-edge">Part 1: Visibility from the Edge</h3><p>For Part 1, we want to know how many trees are visible from the outside. To do this, we&#x27;ll iterate over each tree, and check if it&#x27;s visible. This will do some extra work, but it&#x27;s very simple.</p><p class="note">There are two main ways to reduce the work here. One is to check each of the rows and columns directly from the outside. Imagine shooting a ray into the grid and seeing how many trees are passed before it hits something. However, we&#x27;d have to store the exact trees in a Set, to avoid double-counting trees that are visible from other directions.</p><p class="note">The second way to reduce the double work is to calculate each tree&#x27;s visiblity based on the trees next to it. A tree is visible from the west only if it&#x27;s western neighbor is visible and smaller.</p><p>How do we iterate over each tree? Well, a tree is really just an index in the array! Let&#x27;s make some helper functions that can start with a tree, and return all of the other trees in a particular direction, ending at the edge of the grid:</p><pre><code class="language-haskell lang-haskell">type Tree = (Int, Int)

-- From a given index, step in a cardinal direction until we hit a boundary
northFrom, southFrom, eastFrom, westFrom :: Tree -&gt; (Tree, Tree) -&gt; [Tree]
northFrom (x, y) b = takeWhile (inRange b) [(x, y - d) | d &lt;- [1 ..]]
southFrom (x, y) b = takeWhile (inRange b) [(x, y + d) | d &lt;- [1 ..]]
eastFrom (x, y) b = takeWhile (inRange b) [(x + d, y) | d &lt;- [1 ..]]
westFrom (x, y) b = takeWhile (inRange b) [(x - d, y) | d &lt;- [1 ..]]</code></pre><p>A tree is visible if it&#x27;s visible from any of these four directions. Let&#x27;s use the List monad to represent this choice. We&#x27;ll create a list of our 4 directions, and then define a computation that can run on any of them.</p><pre><code class="language-haskell lang-haskell">treeIsVisible :: Array Tree Int -&gt; Tree -&gt; Bool
treeIsVisible a t = or $ do
  stepFrom &lt;- [northFrom, southFrom, eastFrom, westFrom]
  let trees = stepFrom t $ bounds a
  return $ all (&lt; (a ! t)) $ fmap (a !) trees

part1 :: Array Tree Int -&gt; Int
part1 a = length . filter (treeIsVisible a) $ indices a</code></pre><h3 id="part-2---maximal-visibility">Part 2 - Maximal visibility</h3><p>Part 2 ends up being very similar:</p><ol start="1"><li>We will still iterate over each tree with <code class="language-hs">indices a</code></li><li>We will still use the List monad to choose one of our four directions</li><li>This will result in a list of values. Instead of a boolean whether or not the given tree is visible <em>from that direction</em>, it will be the number of trees visible <em>in that direction</em>.</li><li>We will combine the values together. Instead of <code class="language-hs">or</code>, we will use <code class="language-hs">product</code></li><li>Instead of filtering our trees and counting the length, we&#x27;ll find the maximum resulting value.</li></ol><pre><code class="language-haskell lang-haskell">takeUntil :: (a -&gt; Bool) -&gt; [a] -&gt; [a]
takeUntil p = foldr (\x ys -&gt; x : if p x then [] else ys) []

scenicScore :: Array Tree Int -&gt; Tree -&gt; Int
scenicScore a t = product $ do
  stepFrom &lt;- [northFrom, southFrom, eastFrom, westFrom]
  return $ length $ takeUntil (\x -&gt; a ! x &gt;= a ! t) $ stepFrom t $ bounds a

part2 :: Array Tree Int -&gt; Int
part2 a = maximum . fmap (scenicScore a) $ indices a</code></pre><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">module AOC2022.Day08 (spec) where

import Data.Array
import Data.Char (digitToInt)
import Input
import Test.Hspec

input :: IO (Array (Int, Int) Int)
input = do
  s &lt;- lines &lt;$&gt; readDay 2022 8
  return $ listArray ((1, 1), (length s, length s)) $ digitToInt &lt;$&gt; concat s

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 8&quot; $ do
    describe &quot;Part 1&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part1 myInput `shouldBe` 0 -- redacted
    describe &quot;Part 2&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part2 myInput `shouldBe` 0 -- redacted

type Tree = (Int, Int)

-- From a given index, step in a cardinal direction until we hit a boundary
northFrom, southFrom, eastFrom, westFrom :: Tree -&gt; (Tree, Tree) -&gt; [Tree]
northFrom (x, y) b = takeWhile (inRange b) [(x, y - d) | d &lt;- [1 ..]]
southFrom (x, y) b = takeWhile (inRange b) [(x, y + d) | d &lt;- [1 ..]]
eastFrom (x, y) b = takeWhile (inRange b) [(x + d, y) | d &lt;- [1 ..]]
westFrom (x, y) b = takeWhile (inRange b) [(x - d, y) | d &lt;- [1 ..]]

treeIsVisible :: Array Tree Int -&gt; Tree -&gt; Bool
treeIsVisible a t = or $ do
  stepFrom &lt;- [northFrom, southFrom, eastFrom, westFrom]
  let trees = stepFrom t $ bounds a
  return $ all (&lt; (a ! t)) $ fmap (a !) trees

part1 :: Array Tree Int -&gt; Int
part1 a = length . filter (treeIsVisible a) $ indices a

takeUntil :: (a -&gt; Bool) -&gt; [a] -&gt; [a]
takeUntil p = foldr (\x ys -&gt; x : if p x then [] else ys) []

scenicScore :: Array Tree Int -&gt; Tree -&gt; Int
scenicScore a t = product $ do
  stepFrom &lt;- [northFrom, southFrom, eastFrom, westFrom]
  return $ length $ takeUntil (\x -&gt; a ! x &gt;= a ! t) $ stepFrom t $ bounds a

part2 :: Array Tree Int -&gt; Int
part2 a = maximum . fmap (scenicScore a) $ indices a</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day09">Day 9: Rope Bridge</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day07">Day 7: No Space Left On Device</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 7: No Space Left On Device]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day07</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day07</guid>
            <pubDate>Sat, 10 Dec 2022 10:00:00 GMT</pubDate>
            <description><![CDATA[After taking a break for a few days, we return for [Day 7: No Space Left On Device](https://adventofcode.com/2022/day/7), where we parse and parse again.
]]></description>
            <content:encoded><![CDATA[<p>I took a break for a few days before tackling <a href="https://adventofcode.com/2022/day/7">Day 7: No Space Left On Device</a>. In this challenge, we are tasked with reconstructing a file system structure from a list of terminal output. I decided I wanted to solve this with two rounds of parsing:</p><ol start="1"><li>Parse the raw lines into structured TerminalOutput commands.</li><li>Parse the list of TerminalOutput commands into a FileSystem tree.</li></ol><h3 id="first-parse---string-to-terminal-output">First Parse - String to Terminal Output</h3><p>First things first, we needed to convert the strings into something more useful:</p><pre><code class="language-haskell lang-haskell">data TerminalOutput
  = LS
  | Cd String
  | CdUp
  | LSDir String
  | LSFile Int String
  deriving (Eq, Show)

parseLine :: ParsecT [Char] u Identity TerminalOutput
parseLine = parseCdUp &lt;|&gt; parseCd &lt;|&gt; parseDir &lt;|&gt; parseFile &lt;|&gt; parseLS
  where
    parseCdUp = try $ string &quot;$ cd ..&quot; $&gt; CdUp
    parseCd = try $ fmap Cd (string &quot;$ cd &quot; &gt;&gt; many1 (noneOf &quot;\n&quot;))
    parseDir = try $ fmap LSDir (string &quot;dir &quot; &gt;&gt; many1 (noneOf &quot;\n&quot;))
    parseFile = try $ liftA2 LSFile (parseInt &lt;* string &quot; &quot;) (many1 (noneOf &quot;\n&quot;))
    parseLS = try $ string &quot;$ ls&quot; $&gt; LS</code></pre><p>The mishmash of punctuation and parentheses isn&#x27;t the easiest to read, but it generally parses the line left-to-right, discarding any cruft.</p><h3 id="parsing-the-terminal-output-again">Parsing the Terminal Output Again?</h3><p>With a list of TerminalOutput commands, I now wanted to parse a FileSystem tree. Sure, I <em>could</em> have just used recursion, but I didn&#x27;t want to pass around the state of what directory I was in. Plus, the point of this is to learn, right?</p><p>To write a custom Parsec parser, I looked to the <code class="language-hs">Text.Parsec.Prim</code> module, specifically <code class="language-hs">tokenPrim</code>. We can define a combinator for each of our tokens like so:</p><pre><code class="language-haskell lang-haskell">ls :: ParsecT [TerminalOutput] u Identity ()
ls = tokenPrim show nextPos test
  where
    test LS = Just ()
    test _ = Nothing

cdup :: ParsecT [TerminalOutput] u Identity ()
cdup = tokenPrim show nextPos test
  where
    test CdUp = Just ()
    test _ = Nothing

cd :: ParsecT [TerminalOutput] u Identity TerminalOutput
cd = tokenPrim show nextPos test
  where
    test (Cd s) = Just (Cd s)
    test _ = Nothing

lsdir :: ParsecT [TerminalOutput] u Identity TerminalOutput
lsdir = tokenPrim show nextPos test
  where
    test (LSDir s) = Just (LSDir s)
    test _ = Nothing

lsfile :: ParsecT [TerminalOutput] u Identity TerminalOutput
lsfile = tokenPrim show nextPos test
  where
    test (LSFile i s) = Just (LSFile i s)
    test _ = Nothing</code></pre><p>Note that <code class="language-hs">ls, cdup</code> parse a unit <code class="language-hs">()</code> type. They <em>could</em> return the TerminalOutput, but we want to ignore them in our final FileSystem anyways.</p><p><code class="language-hs">nextPos</code> is a function that updates our &quot;source position&quot;, stepping through our list of TerminalOutput commands as we parse. Since all of our tokens are a single command, they can share the same implementation:</p><pre><code class="language-haskell lang-haskell">nextPos :: SourcePos -&gt; b1 -&gt; b2 -&gt; SourcePos
nextPos p = const $ const $ newPos (sourceName p) (sourceLine p) (sourceColumn p + 1)</code></pre><h3 id="using-our-parsers-to-make-a-filesystem">Using Our Parsers to Make a FileSystem</h3><p>Now that we have our primitives, we can define a parser for a FileSystem. A FileSystem is either a single File (with a name and size) or a Directory (with a name and a list of files or sub-directories).</p><pre><code class="language-haskell lang-haskell">data FileSystem = Directory String [FileSystem] | File String Int deriving (Eq, Show)</code></pre><p>We can parse it like so:</p><pre><code class="language-haskell lang-haskell">parseFiles :: ParsecT [TerminalOutput] u Identity [FileSystem]
parseFiles = mapMaybe parseListing &lt;$&gt; many (try lsdir &lt;|&gt; try lsfile)
  where
    parseListing (LSFile i s) = Just $ File s i
    parseListing _ = Nothing

parseFileSystem :: ParsecT [TerminalOutput] u Identity FileSystem
parseFileSystem = do
  Cd name &lt;- cd
  ls
  files &lt;- parseFiles
  subdirs &lt;- many parseFileSystem
  cdup &lt;|&gt; eof
  return $ Directory name (files ++ subdirs)</code></pre><p>Note that we terminate our parse with an option of <code class="language-hs">cdup &lt;|&gt; eof</code>. This sidesteps the issue where you may not return to the root directory at the end of the input.</p><h3 id="wait-what-was-the-question">Wait, What Was The Question?</h3><p>After this really-way-too-involved setup, we can now go about solving Part 1 and Part 2. These are both pretty simple functions now that we have our FileSystem object.</p><pre><code class="language-haskell lang-haskell">size :: FileSystem -&gt; Int
size (File _ i) = i
size (Directory _ fs) = sum $ map size fs

listAll :: FileSystem -&gt; [FileSystem]
listAll f@(File _ _) = [f]
listAll d@(Directory _ fs) = d : concatMap listAll fs

isDir :: FileSystem -&gt; Bool
isDir (Directory _ _) = True
isDir _ = False

part1 :: FileSystem -&gt; Int
part1 = sum . filter (&lt;= 100000) . fmap size . filter isDir . listAll

diskSize, spaceNeeded :: Int
diskSize = 70000000
spaceNeeded = 30000000

part2 :: FileSystem -&gt; Int
part2 root = minimum $ filter (&gt;= spaceToFree) $ fmap size $ filter isDir $ listAll root
  where
    spaceToFree = spaceNeeded + size root - diskSize</code></pre><p class="note">This is doing a lot of extra work in calculating the size for each of the directories and sub-directories. A more efficient approach would precalculate the size of each directory when parsing it, so that it can be retrieved in constant time and avoid recomputing the size of subtrees.</p><h3 id="full-code">Full Code</h3><p>Here&#x27;s the full code! The imports are more verbose than usual, to disambiguate which module the Parsec and Applicative functions came from.</p><pre><code class="language-haskell lang-haskell">module AOC2022.Day07 (spec) where

import Control.Applicative (liftA2)
import Data.Functor (($&gt;))
import Data.Functor.Identity (Identity)
import Data.Maybe (mapMaybe)
import Input (parseInt, readDay)
import Test.Hspec (describe, hspec, it, shouldBe)
import Text.Parsec.Pos
  ( SourcePos,
    newPos,
    sourceColumn,
    sourceLine,
    sourceName,
  )
import Text.Parsec.Prim
  ( ParsecT,
    many,
    parse,
    tokenPrim,
    try,
    (&lt;|&gt;),
  )
import Text.ParserCombinators.Parsec
  ( ParseError,
    eof,
    many1,
    noneOf,
    string,
  )

input :: IO (Either ParseError FileSystem)
input = do
  raw &lt;- lines &lt;$&gt; readDay 2022 7
  return $ do
    output &lt;- traverse (parse parseLine &quot;&quot;) raw
    parse parseFileSystem [] output

spec :: IO ()
spec = hspec $ do
  describe &quot;Part 1&quot; $ do
    it &quot;runs a test&quot; $ do
      myInput &lt;- input
      fmap part1 myInput `shouldBe` Right 0 -- redacted
  describe &quot;Part 2&quot; $ do
    it &quot;runs a test&quot; $ do
      myInput &lt;- input
      fmap part2 myInput `shouldBe` Right 0 -- redacted

data TerminalOutput
  = LS
  | Cd String
  | CdUp
  | LSDir String
  | LSFile Int String
  deriving (Eq, Show)

parseLine :: ParsecT [Char] u Identity TerminalOutput
parseLine = parseCdUp &lt;|&gt; parseCd &lt;|&gt; parseDir &lt;|&gt; parseFile &lt;|&gt; parseLS
  where
    parseCdUp = try $ string &quot;$ cd ..&quot; $&gt; CdUp
    parseCd = try $ fmap Cd (string &quot;$ cd &quot; &gt;&gt; many1 (noneOf &quot;\n&quot;))
    parseDir = try $ fmap LSDir (string &quot;dir &quot; &gt;&gt; many1 (noneOf &quot;\n&quot;))
    parseFile = try $ liftA2 LSFile (parseInt &lt;* string &quot; &quot;) (many1 (noneOf &quot;\n&quot;))
    parseLS = try $ string &quot;$ ls&quot; $&gt; LS

data FileSystem = Directory String [FileSystem] | File String Int deriving (Eq, Show)

nextPos :: SourcePos -&gt; b1 -&gt; b2 -&gt; SourcePos
nextPos p = const $ const $ newPos (sourceName p) (sourceLine p) (sourceColumn p + 1)

ls :: ParsecT [TerminalOutput] u Identity ()
ls = tokenPrim show nextPos test
  where
    test LS = Just ()
    test _ = Nothing

cdup :: ParsecT [TerminalOutput] u Identity ()
cdup = tokenPrim show nextPos test
  where
    test CdUp = Just ()
    test _ = Nothing

cd :: ParsecT [TerminalOutput] u Identity TerminalOutput
cd = tokenPrim show nextPos test
  where
    test (Cd s) = Just (Cd s)
    test _ = Nothing

lsdir :: ParsecT [TerminalOutput] u Identity TerminalOutput
lsdir = tokenPrim show nextPos test
  where
    test (LSDir s) = Just (LSDir s)
    test _ = Nothing

lsfile :: ParsecT [TerminalOutput] u Identity TerminalOutput
lsfile = tokenPrim show nextPos test
  where
    test (LSFile i s) = Just (LSFile i s)
    test _ = Nothing

parseFiles :: ParsecT [TerminalOutput] u Identity [FileSystem]
parseFiles = mapMaybe parseListing &lt;$&gt; many (try lsdir &lt;|&gt; try lsfile)
  where
    parseListing (LSFile i s) = Just $ File s i
    parseListing _ = Nothing

parseFileSystem :: ParsecT [TerminalOutput] u Identity FileSystem
parseFileSystem = do
  Cd name &lt;- cd
  ls
  files &lt;- parseFiles
  subdirs &lt;- many parseFileSystem
  cdup &lt;|&gt; eof
  return $ Directory name (files ++ subdirs)

size :: FileSystem -&gt; Int
size (File _ i) = i
size (Directory _ fs) = sum $ map size fs

listAll :: FileSystem -&gt; [FileSystem]
listAll f@(File _ _) = [f]
listAll d@(Directory _ fs) = d : concatMap listAll fs

isDir :: FileSystem -&gt; Bool
isDir (Directory _ _) = True
isDir _ = False

part1 :: FileSystem -&gt; Int
part1 = sum . filter (&lt;= 100000) . fmap size . filter isDir . listAll

diskSize, spaceNeeded :: Int
diskSize = 70000000
spaceNeeded = 30000000

part2 :: FileSystem -&gt; Int
part2 root = minimum $ filter (&gt;= spaceToFree) $ fmap size $ filter isDir $ listAll root
  where
    spaceToFree = spaceNeeded + size root - diskSize</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day08">Day 8: Treetop Tree House</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day06">Day 6: Tuning Trouble</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 6: Tuning Trouble]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day06</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day06</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 6: Tuning Trouble](https://adventofcode.com/2022/day/6), we scan through a string looking for subsets of unique characters.
]]></description>
            <content:encoded><![CDATA[<p>For a refreshing change, <a href="https://adventofcode.com/2022/day/6">Day 6: Tuning Trouble</a> does not require us to parse our input at all. We&#x27;re given a single line of characters, and we need to process it looking for sets of unique characters.</p><p>This problem seems like a natural fit for recursion. Our core functionality will be a function that peeks the first few characters of the string. If they are unique, it returns the count. Otherwise, we discard a letter and try again with the rest of the string. Here&#x27;s my first iteration at this, for Part 1:</p><pre><code class="language-haskell lang-haskell">charsUntilPacket :: String -&gt; Int
charsUntilPacket (a : b : c : d : rest)
  | Set.size (Set.fromList [a, b, c, d]) == 4 = 4
  | otherwise = 1 + charsUntilPacket (b : c : d : rest)</code></pre><h3 id="part-2---windows-of-size-14">Part 2 - Windows of size 14</h3><p>Looking at 14 characters in a row is much the same. Pattern matching on 14 characters seemed a little excessive, though. I restructured <code class="language-hs">charsUntilPacket</code> to take a window size parameter, and renamed it <code class="language-hs">charsUntilNUnique</code>.</p><p>Lastly, I changed how we are checking for uniqueness. The Set approach works fine, but it forces the entire Set to be constructed to check its size. The alternative approach of <code class="language-hs">nub s == s</code> is, perhaps surprisingly, more efficient: it compares the elements one by one and can skip the remaining computation of <code class="language-hs">nub s</code> as soon as it discovers a mismatch. Laziness for the win!</p><p class="note">Hoogle <a href="https://hoogle.haskell.org/?hoogle=isNub">does find</a> a function <code class="language-hs">isNub</code> that is equivalent. However, it&#x27;s not in a package I&#x27;m familiar with.</p><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">module AOC2022.Day06 (spec) where

import Data.List (nub)
import Input (readDay)
import Test.Hspec (describe, hspec, it, shouldBe)

input :: IO String
input = readDay 2022 6

spec :: IO ()
spec = hspec $ do
  describe &quot;Part 1&quot; $ do
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part1 myInput `shouldBe` 0 -- redacted
  describe &quot;Part 2&quot; $ do
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part2 myInput `shouldBe` 0 -- redacted

charsUntilNUnique :: Int -&gt; String -&gt; Int
charsUntilNUnique i s =
  if nub (take i s) == take i s
    then i
    else 1 + charsUntilNUnique i (tail s)

part1 :: String -&gt; Int
part1 = charsUntilNUnique 4

part2 :: String -&gt; Int
part2 = charsUntilNUnique 14</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day07">Day 7: No Space Left On Device</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day05">Day 5: Supply Stacks</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 5: Supply Stacks]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day05</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day05</guid>
            <pubDate>Mon, 05 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 5: Supply Stacks](https://adventofcode.com/2022/day/5), we watch a crane push and pop items from several stacks.
]]></description>
            <content:encoded><![CDATA[<p>It&#x27;s <a href="https://adventofcode.com/2022/day/5">Day 5</a>, and it&#x27;s time to move some crates. We&#x27;re given 9 initial stacks of crates, and instructions for how a crane moves crates from one stack to another. Here is our sample input:</p><pre><code class="language-plaintext lang-plaintext">    [D]
[N] [C]
[Z] [M] [P]
 1   2   3

move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2</code></pre><p>Initial thought: There&#x27;s no way I&#x27;m parsing that stack diagram!</p><h3 id="parsing-moves">Parsing Moves</h3><p>Based on <a href="https://www.wakamoleguy.com/p/aoc2022-day04-bonus">parsing tricks I&#x27;ve learned recently</a>, parsing the move instructions is straightforward:</p><pre><code class="language-haskell lang-haskell">data Move = Move Int Int Int

parseMove :: GenParser Char u Move
parseMove =
  liftA3
    Move
    (string &quot;move &quot; &gt;&gt; parseInt)
    (string &quot; from &quot; &gt;&gt; parseInt)
    (string &quot; to &quot; &gt;&gt; parseInt)

-- parseInt now lives in my reusable Input module:
parseInt :: GenParser Char u Int
parseInt = read &lt;$&gt; many1 digit</code></pre><h3 id="modeling-the-stacks">Modeling the Stacks</h3><p>Lists are a great way to represent stacks in just about any functional language like Haskell, since you can push and pop the top of the list while the tail remains unmodified. But how will we represent our set of 9 stacks? For that, I opted for an <a href="https://hackage.haskell.org/package/array-0.5.4.0/docs/Data-Array.html">array</a>. Compared to Lists, Arrays in Haskell are fixed size and provide faster access and updates to indexed elements. We will be looking up individual stacks and modifying them for each move instruction, so this is perfect for our needs.</p><p>Like I said, I wasn&#x27;t going to parse that initial structure. Here is my input, hardcoded as an array. The start of each string is the top of each stack.</p><pre><code class="language-haskell lang-haskell">stacks :: Array Int String
stacks =
  listArray
    (1, 9)
    [ &quot;BVWTQNHD&quot;,
      &quot;BWD&quot;,
      &quot;CJWQST&quot;,
      &quot;PTZNRJF&quot;,
      &quot;TSMJVPG&quot;,
      &quot;NTFWB&quot;,
      &quot;NVHFQDLB&quot;,
      &quot;RFPH&quot;,
      &quot;HPNLBMSZ&quot;
    ]</code></pre><p class="note">Haskell sidesteps the debate about 0-based and 1-based indexing, as you need to specify the index range explicitly! Here, our stacks start at 1, so we use 1-9 instead of 0-8.</p><h3 id="applying-moves-to-our-stack">Applying Moves to Our Stack</h3><p>Now all we have to do is fold our list of Moves onto our Array. Part 1 is actually a little trickier than Part 2 here, as we can only move one item at a time. If we&#x27;re moving more than one item, let&#x27;s just move one and then recurse.</p><pre><code class="language-haskell lang-haskell">move :: Array Int String -&gt; Move -&gt; Array Int String
move a (Move 0 _ _) = a
move a (Move n x y) =
  let (h, rest) = splitAt 1 (a ! x)
   in move (a // [(x, rest), (y, h ++ (a ! y))]) (Move (n - 1) x y)</code></pre><p><code class="language-hs">(a ! x)</code> accesses the array element at index <code>x</code>. This code splits that element into the top item and the rest. It uses <code class="language-hs">(a // assocs)</code> to update the elements at the old and new index. Then it continues on, moving the next crate until the move is complete.</p><p>Part 2 is simpler, as we can move them all in one go:</p><pre><code class="language-haskell lang-haskell">moveAll :: Array Int String -&gt; Move -&gt; Array Int String
moveAll a (Move n x y) =
  let (pickedUp, rest) = splitAt n (a ! x)
   in a // [(x, rest), (y, pickedUp ++ (a ! y))]</code></pre><p>Finally, we need to take the top item from each stack and concatenate them into a string:</p><pre><code class="language-haskell lang-haskell">peekStacks :: Array Int String -&gt; String
peekStacks = fmap head . elems

part1 :: [Move] -&gt; String
part1 = peekStacks . foldl move stacks

part2 :: [Move] -&gt; String
part2 = peekStacks . foldl moveAll stacks</code></pre><h3 id="is-parsing-really-so-bad">Is Parsing Really So Bad?</h3><p>I solved this last night. When I woke up, I was refreshed and really didn&#x27;t want to let this input get the best of me. How might we parse these stacks? Here&#x27;s the plan:</p><ul><li>Parse each row one by one.</li><li>Rows are either <code class="language-hs">&quot;[A]&quot;</code> or <code class="language-hs" style="whitespace:pre">&quot;\s\s\s&quot;</code>, separated by spaces. In either case, grab the middle character.</li><li>After we parse all rows, <a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-List.html#v:transpose">transpose</a> them to get our stacks, filtering out any blank spaces.</li></ul><p>Here is how that ended up looking:</p><pre><code class="language-haskell lang-haskell">parseStacks :: GenParser Char u [String]
parseStacks = fmap catMaybes . transpose &lt;$&gt; parseLines
  where
    parseCrate = find isLetter . Just &lt;$&gt; (oneOf &quot;[ &quot; *&gt; anyChar &lt;* oneOf &quot; ]&quot;)
    parseLine = parseCrate `sepBy1` char &#x27; &#x27;
    parseLines = parseLine `endBy1` newline</code></pre><p>I stopped here. It should be trivial to parse this from the input file, and then parse the rest of the moves afterwards. We&#x27;ll also need to convert our list of Strings into an Array by examining the length.</p><h3 id="full-code">Full Code</h3><pre><code class="language-haskell lang-haskell">module AOC2022.Day05 (spec) where

import Control.Applicative
import Data.Array
import Data.Char
import Data.List
import Data.Maybe
import Input
import Test.Hspec
import Text.ParserCombinators.Parsec

stacks :: Array Int String
stacks =
  listArray
    (1, 9)
    [ &quot;BVWTQNHD&quot;,
      &quot;BWD&quot;,
      &quot;CJWQST&quot;,
      &quot;PTZNRJF&quot;,
      &quot;TSMJVPG&quot;,
      &quot;NTFWB&quot;,
      &quot;NVHFQDLB&quot;,
      &quot;RFPH&quot;,
      &quot;HPNLBMSZ&quot;
    ]

data Move = Move Int Int Int

parseMove :: GenParser Char u Move
parseMove =
  liftA3
    Move
    (string &quot;move &quot; &gt;&gt; parseInt)
    (string &quot; from &quot; &gt;&gt; parseInt)
    (string &quot; to &quot; &gt;&gt; parseInt)

input :: IO (Either ParseError [Move])
input = traverse (parse parseMove &quot;&quot;) . lines &lt;$&gt; readDay 2022 5

spec :: IO ()
spec = hspec $ do
  describe &quot;Part 1&quot; $ do
    it &quot;parses the stacks&quot; $ do
      part1 [] `shouldBe` &quot;BBCPTNNRH&quot;
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part1 &lt;$&gt; myInput `shouldBe` Right &quot;_________&quot; -- redacted

  describe &quot;Part 2&quot; $ do
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part2 &lt;$&gt; myInput `shouldBe` Right &quot;_________&quot; -- redacted
  describe &quot;Parsing&quot; $ do
    it &quot;parses the raw stack string&quot; $ do
      parse parseStacks &quot;&quot; rawStacks
        `shouldBe` Right
          [ &quot;BVWTQNHD&quot;,
            &quot;BWD&quot;,
            &quot;CJWQST&quot;,
            &quot;PTZNRJF&quot;,
            &quot;TSMJVPG&quot;,
            &quot;NTFWB&quot;,
            &quot;NVHFQDLB&quot;,
            &quot;RFPH&quot;,
            &quot;HPNLBMSZ&quot;
          ]

move :: Array Int String -&gt; Move -&gt; Array Int String
move a (Move 0 _ _) = a
move a (Move n x y) =
  let (h, rest) = splitAt 1 (a ! x)
   in move (a // [(x, rest), (y, h ++ (a ! y))]) (Move (n - 1) x y)

peekStacks :: Array Int String -&gt; String
peekStacks = fmap head . elems

part1 :: [Move] -&gt; String
part1 = peekStacks . foldl move stacks

moveAll :: Array Int String -&gt; Move -&gt; Array Int String
moveAll a (Move n x y) =
  let (pickedUp, rest) = splitAt n (a ! x)
   in a // [(x, rest), (y, pickedUp ++ (a ! y))]

part2 :: [Move] -&gt; String
part2 = peekStacks . foldl moveAll stacks

-- Parsing
rawStacks :: String
rawStacks =
  unlines
    [ &quot;[B]                     [N]     [H]&quot;,
      &quot;[V]         [P] [T]     [V]     [P]&quot;,
      &quot;[W]     [C] [T] [S]     [H]     [N]&quot;,
      &quot;[T]     [J] [Z] [M] [N] [F]     [L]&quot;,
      &quot;[Q]     [W] [N] [J] [T] [Q] [R] [B]&quot;,
      &quot;[N] [B] [Q] [R] [V] [F] [D] [F] [M]&quot;,
      &quot;[H] [W] [S] [J] [P] [W] [L] [P] [S]&quot;,
      &quot;[D] [D] [T] [F] [G] [B] [B] [H] [Z]&quot;,
      &quot; 1   2   3   4   5   6   7   8   9 &quot;
    ]

parseStacks :: GenParser Char u [String]
parseStacks = fmap catMaybes . transpose &lt;$&gt; parseLines
  where
    parseCrate = find isLetter . Just &lt;$&gt; (oneOf &quot;[ &quot; *&gt; anyChar &lt;* oneOf &quot; ]&quot;)
    parseLine = parseCrate `sepBy1` char &#x27; &#x27;
    parseLines = parseLine `endBy1` newline</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day06">Day 6: Tuning Trouble</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day04">Day 4: Camp Cleanup</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 4: Camp Cleanup]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day04</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day04</guid>
            <pubDate>Sun, 04 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 4: Camp Cleanup](https://adventofcode.com/2022/day/4), we write a bunch of code to avoid doing extra work. Wait a minute…
]]></description>
            <content:encoded><![CDATA[<p>In <a href="https://adventofcode.com/2022/day/4">Day 4: Camp Cleanup</a>, each elf has been assigned a range of segments to clean. We&#x27;re given a list of these pairs, and we&#x27;re tasked with comparing whether the ranges overlap completely (Part 1) or at all (Part 2).</p><p>The numbers in our input are all relatively small, to the point where we could brute-force check the elements of each range. But, let&#x27;s try to avoid that by only examing the endpoints of the range.</p><p class="note">This type of representation is bound to be more efficient. It also lends itself well to <a href="https://en.wikipedia.org/wiki/Sweep_line_algorithm">sweep line algorithms</a>, which I bet we will see later this season.</p><h3 id="the-range-type">The Range type</h3><p>Our Range type is a data type that stores only its endpoints:</p><pre><code class="language-haskell lang-haskell">data Range = Range Int Int</code></pre><p>In solving this challenge, I wanted to make the interface for this Range as reusable as possible. Most of the helper functions are analogs to similar functions on <code>Data.Set</code> or <code>Data.List</code>. For Part 1, we need to detect if one Range is a subset of another.</p><pre><code class="language-haskell lang-haskell">-- So reusable!
elem :: Int -&gt; Range -&gt; Bool
i `elem` Range a b = a &lt;= i &amp;&amp; i &lt;= b

-- Much consistency!
isSubsetOf :: Range -&gt; Range -&gt; Bool
Range a b `isSubsetOf` target = a `elem` target &amp;&amp; b `elem` target

-- Specific to Part 1:
isOverlap :: Range -&gt; Range -&gt; Bool
isOverlap a b = a `isSubsetOf` b || b `isSubsetOf` a

part1 :: [(Range, Range)] -&gt; Int
part1 = length . filter (uncurry isOverlap)</code></pre><p>For Part 2, we are looking for any overlap. We can also define some more commonly found functions:</p><pre><code class="language-haskell lang-haskell">-- Just like Sets!
intersection :: Range -&gt; Range -&gt; Range
intersection (Range a b) (Range x y) = Range (max a x) (min b y)

-- Just like Foldables, and Sets, and Maps...
null :: Range -&gt; Bool
null (Range a b) = b &lt; a

part2 :: [(Range, Range)] -&gt; Int
part2 = length . filter (not . null . uncurry intersection)</code></pre><h3 id="parsing">Parsing</h3><p>The final piece is to parse the input into a list of <code class="language-hs">(Range, Range)</code> pairs. To do this, I used <a href="https://hackage.haskell.org/package/parsec-3.1.15.1/docs/Text-Parsec-Combinator.html">Parsec</a>.</p><pre><code class="language-haskell lang-haskell">parseRangePair :: GenParser Char u (Range, Range)
parseRangePair = do
  r1 &lt;- parseRange
  _ &lt;- char &#x27;,&#x27;
  r2 &lt;- parseRange
  return (r1, r2)
  where
    parseRange = do
      a &lt;- read &lt;$&gt; many1 digit
      _ &lt;- char &#x27;-&#x27;
      b &lt;- read &lt;$&gt; many1 digit
      return $ Range a b

input :: IO (Either ParseError [(Range, Range)])
input = traverse (parse parseRangePair &quot;&quot;) . lines &lt;$&gt; readDay 2022 4</code></pre><p>This is pretty verbose, and I&#x27;m sure it can be optimized.</p><h3 id="full-code">Full Code</h3><p>Here it is all together:</p><pre><code class="language-haskell lang-haskell">module AOC2022.Day04 (spec) where

import Input
import Test.Hspec
import Text.ParserCombinators.Parsec
import Prelude hiding (elem, null)

input :: IO (Either ParseError [(Range, Range)])
input = traverse (parse parseRangePair &quot;&quot;) . lines &lt;$&gt; readDay 2022 4

spec :: IO ()
spec = hspec $ do
  describe &quot;Part 1&quot; $ do
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part1 &lt;$&gt; myInput `shouldBe` Right 0 -- redacted

  describe &quot;Part 2&quot; $ do
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part2 &lt;$&gt; myInput `shouldBe` Right 0 -- redacted

data Range = Range Int Int

parseRangePair :: GenParser Char u (Range, Range)
parseRangePair = do
  r1 &lt;- parseRange
  _ &lt;- char &#x27;,&#x27;
  r2 &lt;- parseRange
  return (r1, r2)
  where
    parseRange = do
      a &lt;- read &lt;$&gt; many1 digit
      _ &lt;- char &#x27;-&#x27;
      b &lt;- read &lt;$&gt; many1 digit
      return $ Range a b

elem :: Int -&gt; Range -&gt; Bool
i `elem` Range a b = a &lt;= i &amp;&amp; i &lt;= b

isSubsetOf :: Range -&gt; Range -&gt; Bool
Range a b `isSubsetOf` target = a `elem` target &amp;&amp; b `elem` target

isOverlap :: Range -&gt; Range -&gt; Bool
isOverlap a b = a `isSubsetOf` b || b `isSubsetOf` a

part1 :: [(Range, Range)] -&gt; Int
part1 = length . filter (uncurry isOverlap)

intersection :: Range -&gt; Range -&gt; Range
intersection (Range a b) (Range x y) = Range (max a x) (min b y)

null :: Range -&gt; Bool
null (Range a b) = b &lt; a

part2 :: [(Range, Range)] -&gt; Int
part2 = length . filter (not . null . uncurry intersection)</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>See Also: <a href="https://www.wakamoleguy.com/p/aoc2022-day04-bonus">Day 4 Bonus: Parsing</a></p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day05">Day 5: Supply Stacks</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day03">Day 3: Rucksack Reorganization</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 4 Bonus: Parsing]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day04-bonus</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day04-bonus</guid>
            <pubDate>Sun, 04 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Following up on [Day 4](/p/aoc2022-day04), I refactor my parsing function
to reduce repetition.
]]></description>
            <content:encoded><![CDATA[<p>In <a href="https://www.wakamoleguy.com/p/aoc2022-day04">Day 4</a>, I had a strong hunch that the <code class="language-hs">parseRange</code> function could be improved. For me, parsing tends to be one of the slowest parts of the Advent of Code challenges, and so I&#x27;m always looking for ways to build a better intuition for parsing in Haskell.</p><p>Here&#x27;s the original:</p><pre><code class="language-haskell lang-haskell">parseRangePair :: GenParser Char u (Range, Range)
parseRangePair = do
  r1 &lt;- parseRange
  _ &lt;- char &#x27;,&#x27;
  r2 &lt;- parseRange
  return (r1, r2)
  where
    parseRange = do
      a &lt;- read &lt;$&gt; many1 digit
      _ &lt;- char &#x27;-&#x27;
      b &lt;- read &lt;$&gt; many1 digit
      return $ Range a b</code></pre><p><a href="https://hackage.haskell.org/package/parsec">Parsec</a> defines parser combinators that can be used to compose powerful grammars. My original code does <em>not</em> use much composition, so maybe I&#x27;m doing something wrong!</p><h3 id="use-your-words-human">Use Your Words, Human</h3><p>One trick that helps in these situations is to try describing what we want in plain language. (This apparently works with <a href="https://github.com/max-sixty/aoc-gpt">computers</a>, too.)</p><p>We want:</p><ul><li>Two Ranges, separated by a comma</li><li>Each Range is two Ints, separated by a hyphen</li></ul><p>Following this, we actually come across the <a href="https://hackage.haskell.org/package/parsec-3.1.15.1/docs/Text-Parsec-Combinator.html"><code>sepBy</code> and <code>sepBy1</code> combinators</a>:</p><pre><code class="language-haskell lang-haskell">parseRanges :: GenParser Char u [Range]
parseRanges = parseRange `sepBy1` (char &#x27;,&#x27;)
  where parseRange = ...</code></pre><p>While this looks promising, it doesn&#x27;t compile. <code>sepBy1</code> parses a list. Our <code class="language-hs">Range</code> constructor expects exactly 2 Ints, and our <code class="language-hs">part1, part2</code> functions expect exactly 2 ranges. Let&#x27;s go a different way, but I&#x27;ll remember <code>sepBy</code> in later challenges.</p><h3 id="do-or-do-not">Do or Do Not</h3><p>Using <code>do</code> notation is resulting in verbose code. We have to bind the separator characters just to discard them, and we need a separate line just to return the final result.</p><p>Monads, Applicatives, and Functors are often described as being values wrapped in some abstract &#x27;box&#x27;. In our last <a href="https://www.wakamoleguy.com/p/aoc2022-day03-bonus">Day 3 bonus post</a>, our box was functions; we wanted to compose values that still needed a String passed to them. Now we want to compose values that haven&#x27;t yet been parsed. They are still in the Parser box, if you will.</p><p>We can &quot;lift&quot; our combining functions to work on boxed values. To discard the separator in between, we can use the operator (&gt;&gt;). This operator is like bind (&gt;&gt;=) except that it discards the first first result value.</p><p>Putting it all together, we have:</p><pre><code class="language-haskell lang-haskell">parseRangePair :: GenParser Char u (Range, Range)
parseRangePair =
  let parseInt = read &lt;$&gt; many1 digit
      parseRange = liftA2 Range parseInt (char &#x27;-&#x27; &gt;&gt; parseInt)
   in liftA2 (,) parseRange (char &#x27;,&#x27; &gt;&gt; parseRange)</code></pre><h3 id="further-refactoring">Further refactoring?</h3><p>Not right now, thank you. <code class="language-hs">parseInt</code> definitely belongs in my Input module, and the internal structure of <code class="language-hs">parseRange</code> and <code class="language-hs">parseRangePair</code> could also be useful to reuse. But that&#x27;s a problem for a future day. Maybe even tomorrow!</p><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Main Post: <a href="https://www.wakamoleguy.com/p/aoc2022-day04">Day 4: Camp Cleanup</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 3: Rucksack Reorganization]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day03</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day03</guid>
            <pubDate>Sat, 03 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 3: Rucksack Reorganization](https://adventofcode.com/2022/day/3), we help our elfen friends identify shared features across sets.
]]></description>
            <content:encoded><![CDATA[<p>For <a href="https://adventofcode.com/2022/day/3">Day 3: Rucksack Reorganization</a>, we are given an ominous premise: each string in our input represents a rucksack with compartments and all the items inside. The items, however, are stored improperly. Today is the first weekend puzzle, which tend to be more time intensive than those during the week. It&#x27;s only Day 3, but could we be tasked with some variation of the <a href="https://en.wikipedia.org/wiki/Knapsack_problem">Knapsack Problem</a>, needing to reorganize the items to optimally fit?</p><p>Alas, nothing so complicated. (Phew!) Instead, our goal in both parts is to find common elements shared by various strings (or parts of strings).</p><h3 id="part-1">Part 1</h3><p>In Part 1, we need to find the only character that appears in both the first and second halves of each input string. Then we need to run that through a <code class="language-hs">priority</code> function to transform it into an integer.</p><p>Splitting the list is straightforward. Let&#x27;s take the length of the list and use that to determine how many characters belong in each piece:</p><pre><code class="language-haskell lang-haskell">let size = length s `div` 2
in (take size s, drop size s)

-- Update:  I just learned about `splitAt` in Prelude:
-- splitAt :: Int -&gt; [a] -&gt; ([a], [a])
(s1, s2) = splitAt (length s `div` 2) s</code></pre><p>I didn&#x27;t care to get fancy with my priority function today:</p><pre><code class="language-haskell lang-haskell">charPriority :: Char -&gt; Int
charPriority c
  | &#x27;a&#x27; &lt;= c &amp;&amp; c &lt;= &#x27;z&#x27; = fromEnum c - fromEnum &#x27;a&#x27; + 1
  | &#x27;A&#x27; &lt;= c &amp;&amp; c &lt;= &#x27;Z&#x27; = fromEnum c - fromEnum &#x27;A&#x27; + 27
  | otherwise = 0</code></pre><h4 id="using-sets">Using Sets</h4><p>Now, how should we compare the items in the first string with the items in the second? One option is to manually iterate over the characters in the first, checking if they are in the second. In the worst case, the common character will be at the end of each string, requiring <code>O(n^2)</code> comparisons. Instead, I chose to first transform the strings into a more efficient data structure, then compare those instead.</p><ol start="1"><li>Construct a <a href="https://hackage.haskell.org/package/containers-0.6.6/docs/Data-Set.html">Set</a> from each String. <code>O(log n)</code></li><li>Combine the Sets by intersection. <code>~O(n)</code> assuming similarly sized sets.</li><li>The only item in the remaining Set is our answer. <code>O(1)</code></li><li>Total Runtime: <code>O(n)</code></li></ol><p class="note">In practice, using asymptotic analysis here is questionable. Our input is very limited in size. This approach seems comparable to sorting the strings and then comparing them element-by-element, which is O(n log n) total. It doesn&#x27;t seem possible to break the O(n) barrier, since you will always have the possibility of needing to look at every item in the list.</p><p>Here&#x27;s the full code:</p><pre><code class="language-haskell lang-haskell">module AOC2022.Day03 (spec) where

import qualified Data.Set as Set
import Input
import Test.Hspec

input :: IO String
input = readDay 2022 3

spec :: IO ()
spec = hspec $ do
  describe &quot;Part 1&quot; $ do
    it &quot;vJrwpWtwJgWrhcsFMMfFFhFp&quot; $ do
      part1 &quot;vJrwpWtwJgWrhcsFMMfFFhFp&quot; `shouldBe` 16
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      sum (fmap part1 (lines myInput)) `shouldBe` 0 -- redacted

standout :: [Char] -&gt; Char
standout s =
  let size = length s `div` 2
      (c1, c2) = (Set.fromList $ take size s, Set.fromList $ drop size s)
   in Set.findMin $ c1 `Set.intersection` c2

charPriority :: Char -&gt; Int
charPriority c
  | &#x27;a&#x27; &lt;= c &amp;&amp; c &lt;= &#x27;z&#x27; = fromEnum c - fromEnum &#x27;a&#x27; + 1
  | &#x27;A&#x27; &lt;= c &amp;&amp; c &lt;= &#x27;Z&#x27; = fromEnum c - fromEnum &#x27;A&#x27; + 27
  | otherwise = 0

part1 :: String -&gt; Int
part1 = charPriority . standout</code></pre><h2 id="part-2---where-sets-pay-off">Part 2 - Where Sets Pay Off</h2><p>In Part 2, we no longer need to split the individual lines. Instead, we&#x27;re looking for the common character in each group of 3 input lines. This is... basically the same thing! Let&#x27;s factor out our <code>commonItem</code> logic, and generalize it to work on any number of Strings:</p><pre><code class="language-haskell lang-haskell">commonItem :: [String] -&gt; Char
commonItem = Set.findMin . foldr1 Set.intersection . fmap Set.fromList</code></pre><p>With this factored out, the only difference between Part 1 and Part 2 is how we generate our groups of strings. While Part 1 splits each line into two strings, Part 2 process the input in chunks of 3. Full code:</p><pre><code class="language-haskell lang-haskell">module AOC2022.Day03 (spec) where

import Data.List.Split
import qualified Data.Set as Set
import Input
import Test.Hspec

input :: IO String
input = readDay 2022 3

spec :: IO ()
spec = hspec $ do
  describe &quot;Part 1&quot; $ do
    it &quot;vJrwpWtwJgWrhcsFMMfFFhFp&quot; $ do
      part1 [&quot;vJrwpWtwJgWrhcsFMMfFFhFp&quot;] `shouldBe` 16
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part1 (lines myInput) `shouldBe` 0 -- redacted
  describe &quot;Part 2&quot; $ do
    it &quot;runs on custom input&quot; $ do
      myInput &lt;- input
      part2 (lines myInput) `shouldBe` 0 -- redacted

commonItem :: [String] -&gt; Char
commonItem = Set.findMin . foldr1 Set.intersection . fmap Set.fromList

splitInHalf :: String -&gt; [String]
splitInHalf s = [take size s, drop size s]
  where
    size = length s `div` 2

charPriority :: Char -&gt; Int
charPriority c
  | &#x27;a&#x27; &lt;= c &amp;&amp; c &lt;= &#x27;z&#x27; = fromEnum c - fromEnum &#x27;a&#x27; + 1
  | &#x27;A&#x27; &lt;= c &amp;&amp; c &lt;= &#x27;Z&#x27; = fromEnum c - fromEnum &#x27;A&#x27; + 27
  | otherwise = 0

part1 :: [String] -&gt; Int
part1 = sum . fmap (charPriority . commonItem . splitInHalf)

part2 :: [String] -&gt; Int
part2 = sum . fmap (charPriority . commonItem) . chunksOf 3</code></pre><h4 id="runtime-analysis">Runtime analysis</h4><p>The runtime of <code class="language-hs">Set.intersection</code> is <code>O(m log((n+1)/(m+1)))</code>. For similarly sized Sets, the <code>log</code> factor approaches a constant, which is why the runtime for Part 1 is O(n). In Part 2, our best case is that the first intersection results in a single item, after which the remaining intersections run with <code>m=1</code>, or <code>O(log n)</code>. In the worse case, however, all but the final intersection share every character, taking the same O(n) time.</p><p>The Set from <code>Data.Set</code> is built with balanced binary trees. Another option is <a href="https://hackage.haskell.org/package/unordered-containers-0.2.19.1/docs/Data-HashSet.html"><code>Data.HashSet</code></a>, which would have closer to O(n) runtime for all operations. However, Data.HashSet is missing the <code>findMin</code> function that is so convenient here. While we know our result will contain a single item, HashSets in general are <em>unordered</em> containers with fewer options for lookups.</p><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>See Also: <a href="https://www.wakamoleguy.com/p/aoc2022-day03-bonus">Day 3 Bonus: Split in Half</a></p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day04">Day 4: Camp Cleanup</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day02">Day 2: Rock Paper Scissors</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 3 Bonus: Split in Half]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day03-bonus</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day03-bonus</guid>
            <pubDate>Sat, 03 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Following up on [Day 3](/p/aoc2022-day03), I explore some functions to split strings in half.
]]></description>
            <content:encoded><![CDATA[<p>While writing up the post for <strong>Advent of Code</strong> <a href="https://www.wakamoleguy.com/p/aoc2022-day03">Day 3</a>, I came across a small improvement to my <code class="language-hs">splitInHalf</code> function. This function takes a string and returns both parts of it. Here&#x27;s the original:</p><pre><code class="language-haskell lang-haskell">splitInHalf :: String -&gt; [String]
splitInHalf s = [take size s, drop size s]
  where
    size = length s `div` 2</code></pre><p>Prelude (essentially Haskell&#x27;s standard library) has a function <code class="language-hs">splitAt</code>, which we can use:</p><pre><code class="language-haskell lang-haskell">splitInHalf :: String -&gt; [String]
splitInHalf s = [s1, s2]
  where
    (s1, s2) = splitAt (length s `div` 2)</code></pre><p>Converting from the tuple to the list should be unnecessary. Let&#x27;s try <code class="language-hs">chunksOf</code>?</p><pre><code class="language-haskell lang-haskell">splitInHalf :: String -&gt; [String]
splitInHalf s = chunksOf (length s `div` 2) s</code></pre><h3 id="point-free">Point Free?</h3><p>We can convert the above function into a <a href="https://en.wikipedia.org/wiki/Tacit_programming">point-free</a> style. Look at the form of our functions:</p><pre><code class="language-haskell lang-haskell">splitInHalf :: String -&gt; [String]
halfLength :: String -&gt; Int -- (`div` 2) . length
chunksOf :: Int -&gt; String -&gt; [String]</code></pre><p><code class="language-hs">(r -&gt;)</code> is an instance of a monad, so let&#x27;s factor <code class="language-hs">(String -&gt;)</code> out from our types and see what&#x27;s left. We replace each function <code class="language-hs">(String -&gt; a)</code> with <code class="language-hs">m a</code>:</p><pre><code class="language-haskell lang-haskell">splitInHalf :: m [String]
halfLength :: m Int
chunksOf :: Int -&gt; m [String]</code></pre><p>So is there a function that can take our <code class="language-hs">halfLength</code> and <code class="language-hs">chunksOf</code> and returns our function <code class="language-hs">splitInHalf</code>? It would have the type of <code class="language-hs">m a -&gt; (a -&gt; m b) -&gt; m b</code>. It does exist, it&#x27;s called &quot;bind&quot; (<code>&gt;&gt;=</code>), and it&#x27;s kinda the core functionaly of monads!</p><pre><code class="language-haskell lang-haskell">splitInHalf :: String -&gt; [String]
splitInHalf = (`div` 2) . length &gt;&gt;= chunksOf</code></pre><p>Using the flipped version of bind brings another new perspective:</p><pre><code class="language-haskell lang-haskell">splitInHalf :: String -&gt; [String]
splitInHalf = chunksOf =&lt;&lt; (`div` 2) . length</code></pre><p>This looks similar to our original, but composed of functions instead of values.</p><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Main Post: <a href="https://www.wakamoleguy.com/p/aoc2022-day03">Day 3: Rucksack Reorganization</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 2: Rock Paper Scissors]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day02</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day02</guid>
            <pubDate>Fri, 02 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 2: Rock Paper Scissors](https://adventofcode.com/2022/day/2), we evaluate the merits of using an encrypted strategy guide to cheat our new friends.
]]></description>
            <content:encoded><![CDATA[<p>It&#x27;s <a href="https://adventofcode.com/2022/day/2">Day 2</a> of <strong>Advent of Code</strong>, and we&#x27;re apparently going to play in a tournament of Rock Paper Scissors. One elf has &quot;helpfully&quot; given us a strategy guide to guarantee a win. Now, I am adamantly opposed to cheating in any form, so this puzzle posed a predicament. Luckily our task sidesteps this; rather than using the strategy, we only care to check to see how effective it <em>would</em> be.</p><p class="note">OpenAI recently released <a href="https://openai.com/blog/chatgpt/">ChatGPT</a>, an interactive language model for dialogues. It is built with some functionality to refuse inappropriate requests. Trending on HackerNews today is a post describing all of the way people have found to <a href="https://news.ycombinator.com/item?id=33832358">circumvent that filter</a>. One of the most popular is to phrase the prompt as make believe. So that&#x27;s what we&#x27;re doing today. We&#x27;re not cheating at Rock Paper Scissors; we&#x27;re simply playing a character that would cheat at Rock Paper Scissors.</p><h3 id="a-naive-but-solid-approach">A Naive, But Solid Approach</h3><p>The scoring for a single round of Rock Paper Scissors is based on two simple rules. One of them is dependent on the shape you throw (3 options), and the other is dependent on the outcome of the game (shapes you and your opponent throw, <code class="language-hs">3 * 3 == 9</code> options). That&#x27;s not that many cases! Let&#x27;s just hardcode them.</p><pre><code class="language-haskell lang-haskell">module AOC2022.Day02 (spec) where

import Control.Applicative
import Input
import Test.Hspec

input :: IO String
input = readDay 2022 2

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 2&quot; $ do
    it &quot;solves part 1&quot; $ do
      myInput &lt;- input
      part1 myInput `shouldBe` 0 -- redacted
    it &quot;solves part 2&quot; $ do
      myInput &lt;- input
      part2 myInput `shouldBe` 0 -- redacted

part1 :: String -&gt; Int
part1 = sum . fmap score . lines

score :: String -&gt; Int
score = liftA2 (+) scoreShape scoreOutcome

scoreShape :: String -&gt; Int
scoreShape [_, _, &#x27;X&#x27;] = 1
scoreShape [_, _, &#x27;Y&#x27;] = 2
scoreShape [_, _, &#x27;Z&#x27;] = 3
scoreShape _ = 0

scoreOutcome :: String -&gt; Int
scoreOutcome &quot;A X&quot; = 3
scoreOutcome &quot;A Y&quot; = 6
scoreOutcome &quot;A Z&quot; = 0
scoreOutcome &quot;B X&quot; = 0
scoreOutcome &quot;B Y&quot; = 3
scoreOutcome &quot;B Z&quot; = 6
scoreOutcome &quot;C X&quot; = 6
scoreOutcome &quot;C Y&quot; = 0
scoreOutcome &quot;C Z&quot; = 3
scoreOutcome _ = 0

part2 :: String -&gt; Int
part2 = sum . fmap score2 . lines

score2 :: String -&gt; Int
score2 = liftA2 (+) scoreShape2 scoreOutcome2

scoreShape2 :: String -&gt; Int
scoreShape2 &quot;A X&quot; = 3
scoreShape2 &quot;A Y&quot; = 1
scoreShape2 &quot;A Z&quot; = 2
scoreShape2 &quot;B X&quot; = 1
scoreShape2 &quot;B Y&quot; = 2
scoreShape2 &quot;B Z&quot; = 3
scoreShape2 &quot;C X&quot; = 2
scoreShape2 &quot;C Y&quot; = 3
scoreShape2 &quot;C Z&quot; = 1
scoreShape2 _ = 0

scoreOutcome2 :: String -&gt; Int
scoreOutcome2 [_, _, &#x27;X&#x27;] = 0
scoreOutcome2 [_, _, &#x27;Y&#x27;] = 3
scoreOutcome2 [_, _, &#x27;Z&#x27;] = 6
scoreOutcome2 _ = 0</code></pre><p>OK, so it&#x27;s a little long, but I doubt there is a simpler, more understandable approach. The only real trick is the use of <code class="language-hs">liftA2</code> to convert <code class="language-hs">+</code> from an operator on numbers to an operator on functions. For further reading, check out <a href="http://learnyouahaskell.com/functors-applicative-functors-and-monoids">Learn You A Haskell&#x27;s chapter on Applicative Functors</a>, especially regarding <code class="language-hs">instance Functor ((-&gt;) r)</code>.</p><h3 id="who-needs-simple">Who Needs Simple?</h3><p>While the code is working just fine, there is something deeply unsatisfying about such repetitive statements. My goal isn&#x27;t to strictly minimize the amount of code, though, so to justify further exploration let&#x27;s introduce a self-imposed &quot;Part 3&quot;: make it work with <a href="https://bigbangtheory.fandom.com/wiki/Rock,_Paper,_Scissors,_Lizard,_Spock">Rock Paper Scissors Lizard Spock</a>, an extension of Rock Paper Scissors with 5 options.</p><p>The key insight is that all games like Rock Paper Scissors Lizard Spock can be represented as a <a href="https://en.wikipedia.org/wiki/Cyclic_order">cyclic order</a>. For any game with <code class="language-hs">2k+1</code> shapes, each shape has <code class="language-hs">k</code> other shapes that beat it and <code class="language-hs">k</code> other shapes that lose to it. For code golfers, this opens up a plethora of <a href="https://github.com/ephemient/aoc2022/blob/main/hs/src/Day2.hs">modular arithmetic tricks</a> to aid in solving. We&#x27;ll focus more on the algebraic side of things.</p><p>So let&#x27;s start with a data type that implements Ord:</p><pre><code class="language-haskell lang-haskell">data Shape = Rock | Paper | Scissors deriving (Eq, Show)
instance Ord Shape where
  compare x y =
    let minmax = [Rock, Scissors]
     in if x `elem` minmax &amp;&amp; y `elem` minmax then compare y x else compare x y```</code></pre><p>This compare function is no good! While it may work for our needs, it is <em>not</em> a valid instance of the Ord typeclass, <a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Ord.html#t:Ord">since it is <em>not transitive</em></a>. (Rock is less than Paper, and Paper is less than Scissors, but Rock is not less than Scissors.)</p><p>So we throw that away and create our own typeclass CyclicEnum, using the same code to implement a cycle compare, or <code class="language-hs">ccompare</code>. Given a Shape, we also want to be able to find the Shape that is some number of steps down the cycle, so we introduce another function <code class="language-hs">toCyclicEnumFrom</code>.</p><pre><code class="language-haskell lang-haskell">class (Bounded a, Ord a, Enum a) =&gt; CyclicEnum a where
  ccompare :: a -&gt; a -&gt; Ordering
  toCyclicEnumFrom :: a -&gt; Int -&gt; a
  ccompare x y =
    let minmax = [minBound, maxBound]
     in if x `elem` minmax &amp;&amp; y `elem` minmax then compare y x else compare x y
  toCyclicEnumFrom a i = toEnum $ (i + fromEnum a + sizeof a) `mod` sizeof a


sizeof :: CyclicEnum a =&gt; a -&gt; Int
sizeof a = 1 + val maxBound - val minBound
  where
    val = fromEnum . (`asTypeOf` a)</code></pre><p>With this new algebraic representation, we unfortunately have to parse the strings. Let&#x27;s assume that in our Rock Paper Scissors Lizard Spock, example, we would use A, B, C, D, and E as well as V, W, X, Y, and Z. We can do some modular arithmetic on the character codes to generalize this:</p><pre><code class="language-haskell lang-haskell">parseCode :: CyclicEnum a =&gt; Char -&gt; a
parseCode = toCyclicEnumFrom minBound . clampAlphabet . fromEnum
  where
    -- A, B, C -&gt; 0, 1, 2 and X, Y, Z -&gt; -3, -2, -1
    clampAlphabet = (`subtract` 13) . (`mod` 26) . (+ 13) . (`subtract` fromEnum &#x27;A&#x27;)</code></pre><p>With our new representation, we can rephrase our scoring function in terms of the underlying enum values. We can also implement the requested behavior from Part 2, to decode the <em>outcome</em> of the game into its actual shapes, using our handy <code class="language-hs">toCyclicEnumFrom</code> function:</p><pre><code class="language-haskell lang-haskell">decodeGame :: CyclicEnum a =&gt; (a, a) -&gt; (a, a)
decodeGame (a, o) = (a, toCyclicEnumFrom a (fromEnum o - sizeof a `div` 2))</code></pre><h3 id="putting-it-all-together">Putting It All Together</h3><p>Here&#x27;s the full code. Implementing Rock Paper Scissors Lizard Spock is now as simple as adding two new items to the Shape enum!</p><p class="note">The proper order of the cycle according to the usual rules would be Rock-Spock-Paper-Lizard-Scissors. Each shape defeats the two preceding items and loses to the two following shapes.</p><pre><code class="language-haskell lang-haskell">class (Bounded a, Ord a, Enum a) =&gt; CyclicEnum a where
  ccompare :: a -&gt; a -&gt; Ordering
  toCyclicEnumFrom :: a -&gt; Int -&gt; a
  ccompare x y =
    let minmax = [minBound, maxBound]
     in if x `elem` minmax &amp;&amp; y `elem` minmax then compare y x else compare x y
  toCyclicEnumFrom a i = toEnum $ (i + fromEnum a + sizeof a) `mod` sizeof a

sizeof :: CyclicEnum a =&gt; a -&gt; Int
sizeof a = 1 + val maxBound - val minBound
  where
    val = fromEnum . (`asTypeOf` a)

data Shape = Rock | Paper | Scissors deriving (Eq, Show, Ord, Bounded, Enum)

instance CyclicEnum Shape

parseCode :: CyclicEnum a =&gt; Char -&gt; a
parseCode = toCyclicEnumFrom minBound . clampAlphabet . fromEnum
  where
    -- A, B, C -&gt; 0, 1, 2 and X, Y, Z -&gt; -3, -2, -1
    clampAlphabet = (`subtract` 13) . (`mod` 26) . (+ 13) . (`subtract` fromEnum &#x27;A&#x27;)

parseGame :: String -&gt; (Shape, Shape)
parseGame [a, &#x27; &#x27;, x] = (parseCode a, parseCode x)

scoreShape :: CyclicEnum a =&gt; a -&gt; a -&gt; Int
scoreShape = const $ (1 +) . fromEnum

scoreOutcome :: CyclicEnum a =&gt; a -&gt; a -&gt; Int
scoreOutcome they you = (3 *) $ fromEnum $ ccompare you they

score :: CyclicEnum a =&gt; (a, a) -&gt; Int
score = liftA2 (+) (uncurry scoreShape) (uncurry scoreOutcome)

decodeGame :: CyclicEnum a =&gt; (a, a) -&gt; (a, a)
decodeGame (a, o) = (a, toCyclicEnumFrom a (fromEnum o - sizeof a `div` 2))

part1 :: String -&gt; Int
part1 = sum . fmap (score . parseGame) . lines

part2 :: String -&gt; Int
part2 = sum . fmap (score . decodeGame . parseGame) . lines</code></pre><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day03">Day 3: Rock Paper Scissors</a> Previous: <a href="https://www.wakamoleguy.com/p/aoc2022-day01">Day 1: Calorie Counting</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advent of Code 2022 - Day 1: Calorie Counting]]></title>
            <link>https://www.wakamoleguy.com/p/aoc2022-day01</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/aoc2022-day01</guid>
            <pubDate>Thu, 01 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In [Day 1: Calorie Counting](https://adventofcode.com/2022/day/1), we start
our expedition into the jungle. I describe and annotate my solution.

I'm solving Advent of Code's 2022 puzzles using Haskell.
]]></description>
            <content:encoded><![CDATA[<p>It&#x27;s that time of year again! We have 25 days to collect 50 stars and save Christmas. That&#x27;s right: it&#x27;s <a href="https://adventofcode.com/">Advent of Code</a>. This year I am solving the puzzles using Haskell, and I plan to write about each day&#x27;s solution here.</p><p><a href="https://adventofcode.com/2022/day/1">Day 1: Calorie Counting</a> is a bit of a warm-up, as usual for the first day&#x27;s challenge. This year, we have input like this:</p><pre><code class="language-plaintext lang-plaintext">1000
2000
3000

4000

5000
6000

7000
8000
9000

10000</code></pre><p>Each grouping represents the snacks carried by a single elf, and each line is the calorie count for an individual snack. In Part 1, we need to sum up each group and find the greatest. In Part 2, we need to find the three (3) greatest.</p><h3 id="first-solution">First Solution</h3><p>Here&#x27;s my first attempt at solving the problem.</p><pre><code class="language-haskell lang-haskell">import Data.List
import Data.List.Split
import Input
import Test.Hspec

input :: IO String
input = readDay 2022 1

spec :: IO ()
spec = hspec $ do
  describe &quot;Day 01&quot; $ do
    describe &quot;Part 01&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part1 myInput `shouldBe` 0 -- redacted
    describe &quot;Part 02&quot; $ do
      it &quot;runs on custom input&quot; $ do
        myInput &lt;- input
        part2 myInput `shouldBe` 0 -- redacted

part1 :: String -&gt; Int
part1 = maximum . calorieCounter

part2 :: String -&gt; Int
part2 = sum . take 3 . reverse . sort . calorieCounter

calorieCounter :: String -&gt; [Int]
calorieCounter = fmap (sum . fmap read . lines) . splitOn &quot;\n\n&quot;</code></pre><p>I use <a href="https://hspec.github.io/">Hspec</a> to run my code as a test suite. Once I find the correct answer, I add it as an expectation. This allows me to refactor my code more easily, either in solving Part 2 or in cleanup afterwards. <code class="language-hs">Input.readDay</code> is a simple helper method that reads my input file from a local directory.</p><h3 id="polishing">Polishing</h3><p>There were a few things I wanted to improve with this solution:</p><ol start="1"><li>Part 1 and Part 2 can both be viewed as &quot;Take the N greatest elves and sum them&quot;. But the code for Part 1 and Part 2 were pretty different. I wanted to move the sorting into the <code class="language-hs">calorieCounter</code>, so that it could be used in both parts.</li><li><code class="language-hs">reverse</code> <a href="https://www.smlnj.org/doc/SMLofNJ/pages/susp.html"><em>forces</em></a> the full list to be evaluated, so <code class="language-hs">reverse . sort</code> sorts the whole list even when we only need a few top items. The <a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Ord.html">Data.Ord</a> module provides a <code class="language-hs">Down</code> type which can sort in descending order. Combined with <code class="language-hs">sortOn</code>, this allows us to lazily sort only as much of the list as we need to take.</li><li>Is there any way to simplify the <code class="language-hs">fmap</code>? <code class="language-hs">splitOn</code> can operate on any list, not just Strings (aka, <code class="language-hs">[Char]</code>). We should be able to use <code class="language-hs">lines</code> first, and then split the result into groups, rather than split into groups first, and then <code class="language-hs">fmap lines</code>.</li></ol><p>Instead of <code class="language-hs">splitOn &quot;\n\n&quot;</code>, we would use <code class="language-hs">splitOn [&quot;&quot;]</code>. Since each item in the list is a line, our delimiter is now one item long. We can replace <code class="language-hs">splitOn [&quot;&quot;]</code> with <code class="language-hs">splitWhen null</code>.</p><p>The final code looks like this:</p><pre><code class="language-haskell lang-haskell">import Data.List
import Data.List.Split

part1 :: String -&gt; Int
part1 = head . calorieCounter

part2 :: String -&gt; Int
part2 = sum . take 3 . calorieCounter

calorieCounter :: String -&gt; [Int]
calorieCounter = sortOn Down . fmap (sum . fmap read) . splitWhen null . lines</code></pre><h4 id="polish-i-didnt-do">Polish I didn&#x27;t do:</h4><p>I&#x27;m still using <code class="language-hs">head</code> in <code class="language-hs">part1</code> instead of <code class="language-hs">sum . take 1</code>. It&#x27;s not quite equivalent! While <code class="language-hs">head</code> is more concise, it could bottom on an empty input.</p><p><code class="language-hs">sum . take 1</code> will always return an Int, defaulting to 0 for an empty list. With this option, we could add the number of items to take as an argument to <code class="language-hs">calorieCounter</code>: <code class="language-hs">part1 = calorieCounter 1</code> and <code class="language-hs">part2 = calorieCounter 3</code></p><p>A third option is <code class="language-hs">listToMaybe</code>, which would return <code class="language-hs">Just 69836</code> for my input and <code class="language-hs">None</code> for an empty input.</p><h3 id="advent-of-code-2022-series">Advent of Code 2022 Series</h3><p>This post is part of a series describing my <strong>Haskell</strong> solutions to <strong>Advent of Code 2022</strong>.</p><p>Next: <a href="https://www.wakamoleguy.com/p/aoc2022-day02">Day 2: Rock Paper Scissors</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Goodbye Heroku]]></title>
            <link>https://www.wakamoleguy.com/p/goodbye-heroku</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/goodbye-heroku</guid>
            <pubDate>Sat, 07 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[For many years, I left this website largely unmaintained, and it continued working just fine. After all, it's primarily a set of static files which should not demand any attention. So, I consider that a win.

Today, however, I underwent a larger maintenance task, and moved this site from Heroku (with a custom Node.js server with Express) to Vercel (with a Next.js backend). Here's looking forward to many more years of zero maintenance.
]]></description>
            <content:encoded><![CDATA[<p>For many years, I left this website largely unmaintained, and it continued working just fine. After all, it&#x27;s primarily a set of static files which should not demand any attention. So, I consider that a win.</p><p>Today, however, I underwent a larger maintenance task, and moved this site from Heroku (with a custom Node.js server with Express) to Vercel (with a Next.js backend). Here&#x27;s looking forward to many more years of zero maintenance.</p><h3 id="why-the-move">Why The Move?</h3><p>My primariy motivation for moving <em>now</em> is that <a href="https://blog.heroku.com/we-heard-your-feedback">Heroku suffered a security breach</a>, and I am worried that Salesforce isn&#x27;t going to maintain Heroku very well going forward.</p><p>While I was migrating providers, there were several other pain points I wanted to address:</p><ul><li>Support Typescript and React to build more quickly.</li><li>Reduce the overhead of adding a new blog post. (Less <a href="https://www.wakamoleguy.com/p/you-cant-avoid-markup">markup</a>?)</li><li>Refresh HTTPS certificates automatically via LetsEncrypt</li><li>Deploy quickly and easily</li></ul><p>Next.js covers the former two points, and deploying with Vercel covers the latter two. Were there other options? Definitely. I could have used any static site generator and a number of deployment hosts (even including Heroku). This isn&#x27;t an ad. Next and Vercel seem like they will work with minimal effort and comfortable technologies, though, so I&#x27;m going for it.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[You Can't Avoid Markup]]></title>
            <link>https://www.wakamoleguy.com/p/you-cant-avoid-markup</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/you-cant-avoid-markup</guid>
            <pubDate>Sun, 06 Nov 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[I like writing blog posts. You may not realize that, considering I write about two posts per year. Whoops. The thing is, a lot of work goes into writing a single post; there is thinking of an idea, sketching an outline, composing the post itself, and finally marking it up and publishing it.

Most of that seems inevitable, but that last piece, the markup, feels like wasted effort. More effort makes writing less enjoyable and widens the gaps between posts, simply because I don't want to be bothered with that hassle again. In an ideal world, I would like to just write the words and post them. Everything else (the paragraph tags, links to external sites, emphasis markers, etc) would be automatically added or inferred based on context. So, what is stopping me from living in that utopia?
]]></description>
            <content:encoded><![CDATA[<p>I like writing blog posts.  You may not realize that, considering I write about two posts per year.  Whoops.  The thing is, a lot of work goes into writing a single post; there is thinking of an idea, sketching an outline, composing the post itself, and finally marking it up and publishing it.</p><p>Most of that seems inevitable, but that last piece, the markup, feels like wasted effort.  More effort makes writing less enjoyable and widens the gaps between posts, simply because I don&#x27;t want to be bothered with that hassle again.  In an ideal world, I would like to just write the words and post them.  Everything else (the paragraph tags, links to external sites, emphasis markers, etc) would be automatically added or inferred based on context.  So, what is stopping me from living in that utopia?</p><h3>A Trend Towards Simplicity</h3><p>There are a lot of different ways out there to edit content.  I will admit that I do bring a lot of the pain of markup onto myself.  I use Emacs to author my posts in vanilla HTML.  Emacs is not the prettiest editor, and HTML is quite verbose.  When I add structure to an HTML document, I am wrapping parts of a content tree in tags.  Even the smallest tags, like <code>&lt;p&gt;Paragraph&lt;/p&gt;</code> take seven characters to represent. Emphasizing a phrase takes <em>&lt;em&gt;nine whole characters!&lt;/em&gt;</em></p><p>There are lighter weight ways to mark up the same structure.  In contrast to HTML, Markdown only requires <em>*two characters*</em> to emphasize text. To make a new paragraph, you simply hit enter just like you would in Google Docs or Word.  This ease of basic use has made Markdown the defacto standard for marking up rich text across the web.  It seems <a href="https://github.com/jgm/CommonMark/wiki/Markdown-Flavors">every site has its own flavor</a>.</p><p>Does Markdown represent the end up markup in web content?  The name itself is a pretty big hint that the answer is no.  Markdown <em>is</em> markup. And while it may be easier to write, in fact it still maps 1:1 to HTML. So while Markdown might make my authoring life easier, it is a far cry from a world with no markup.</p><h3>Markup In Everyday English</h3><p>What would happen if I dropped markup entirely?  This post would just be a stream of sentences with no paragraph tags, emphasis, hyperlinks, or any other information about how different text is supposed to be presented.  Even with all of the “excess” stripped away, there is still a structure behind the words:  grammar.</p><p>I could strip away the grammar, too.  For a lot of people, grammar is looked at with the same hatred towards wasted effort that I have toward HTML tags.</p><blockquote>lol u da best mate i luv u</blockquote><p>The more I strip out, the simpler the result, until what I am left with is so minimal that it seems more of a puzzle than an English sentence.  Spaces between words, commas separating clauses, and punctuation marking questions or exclamations — these all add structure and meaning.  At some point, if I cut too much out then I lose the meaning entirely.  <em><strong>Without markup, there is no meaning.</strong></em></p><p>That, I think, is the key insight.  I can strip away all of the markup, grammar, and other structure until all meaning is lost, and then consider the minimal markup to be what needs to be added back in order to reliably convey the message.  And what that minimal need will depend on what idea is being conveyed and to whom.</p><h3>Take Only What You Need</h3><p>Markup is tedious, but without structure in language, there is no meaning.  The trick then, is to use only the markup is needed to convey the message in the way you want.  Grammar, sentences, and paragraph structures can help people understand the whole of what I am presenting. Likewise, even things like attractive and accurately styled links can help your message be consumed.</p><p>And you may not care only about humans.  Search engine indexers and web crawlers may need markup to help parse your post.  If it is important to you that they understand your idea as well as human readers do, then it makes sense to spend as much time crafting your message for those consumers as well.</p><p>In the end, if you only add markup you need to convey your message, it is inherently semantic.  With that perspective, it is not hard to reach that ideal world of going straight from writing your idea down to posting it.  In fact, we may already be there.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Many Pixels Are In An Infinite Resolution Screen?]]></title>
            <link>https://www.wakamoleguy.com/p/pixels-in-an-infinite-resolution-screen</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/pixels-in-an-infinite-resolution-screen</guid>
            <pubDate>Thu, 07 May 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[Earlier this week, I came across an article on <a href="http://practicaltypography.com/the-infinite-pixel-screen.html">Butterick's Practical Typography</a> that was about <a href="https://en.wikipedia.org/wiki/4K_resolution">4K monitors</a>.  Or, so I thought when I started reading it.  I had glossed over the title, so about halfway down I was hit by some sudden <a href="https://en.wikipedia.org/wiki/Georg_Cantor">Cantor</a>.  Discrete Math!

A lot of people would have a lot of different reactions to that, but I was pleasantly surprised.  The question posed was this:  If you keep doubling the resolution of a computor monitor, how many pixels will the <em>infinitely</em> divided screen have?
]]></description>
            <content:encoded><![CDATA[<p>Earlier this week, I came across an article on <a href="http://practicaltypography.com/the-infinite-pixel-screen.html">Butterick&#x27;s Practical Typography</a> that was about <a href="https://en.wikipedia.org/wiki/4K_resolution">4K monitors</a>.  Or, so I thought when I started reading it.  I had glossed over the title, so about halfway down I was hit by some sudden <a href="https://en.wikipedia.org/wiki/Georg_Cantor">Cantor</a>.  Discrete Math!</p><p>A lot of people would have a lot of different reactions to that, but I was pleasantly surprised.  The question posed was this:  If you keep doubling the resolution of a computor monitor, how many pixels will the <em>infinitely</em> divided screen have?</p><p>Butterick comes to the conclusion that it is <em>uncountably infinite</em>.  In an update, readers had written to him that it is actually <em>countably infinite</em>.  He admits that this is so, and explains the error of his ways.  There&#x27;s just one problem...</p><p>Butterick was right all along!</p><h3>The Flaw, or Lack Thereof</h3><p>In his original argument, Butterick attempts to draw a bijection between the pixels on an infinite resolution screen and the set of infinite binary strings.  In the correction, he says that this bijection failed to actually map any pixels.  I think the bijection is sound, though.  Let me see if I can get the actual mapping down.</p><h4>Mapping Pixels to Binary Strings</h4><p>Each pixel is somewhere on the screen.  Let&#x27;s assume it&#x27;s a square screen, and assign coordinates to the corners.  Top left is (0,0) and bottom right is (1,1).  Anywhere in between can clearly be addressed by a coordinate pair.</p><p class="note">Note that we only care that each pixel can be a coordinate pair, not that all coordinate pairs will necessarily be used.  That&#x27;s the next section.</p><p>Given a pixel, we map it to a binary string by dividing the space like Butterick did.  For each digit, we divide the space in half, alternating horizontal and vertical.  If the digit is on the left or top, we set the digit to 0.  Bottom or right gets a 1.  If it is precisely on the line, we&#x27;ll give it a 0 and keep going.  We continue this process indefinitely, thus constructing the string that perfectly matches the pixel.</p><p>Every pixel is somewhere in the space, and so every pixel will map to a binary string.  Further, the pixels are infinitely small, and so the binary string will be of infinite length.</p><h4>Mapping Binary Strings to Pixels</h4><p>Can each infinite binary string map to a pixel? I believe so.  When we split the resolution of the monitor, we cut each pixel into four parts.  When taken in pairs, we can use binary strings to map which of the resulting pixels we are talking about.  00 means top-left, 01 means top-right, 10 means bottom-left, and 11 means bottom-right.</p><p>Because of the manner of splitting, after an infinite process of these pairs, we will have followed the splits to the exact pixel.  Further, each binary string represents a unique sequence, and so each string will map to a unique pixel.</p><p>So, not only does every pixel map to an infinite binary string, but every infinite binary string maps to one of our infinitely-small pixels. Bijection accomplished; there are <strong>uncountably many pixels</strong>.<p></p></p><h3>More Intuition</h3><p>There&#x27;s another way of thinking about this which might help you believe that the mapping works.  Suppose that we had split the screen in ten pieces in each dimension instead of two.  We&#x27;d be left with 100 times the pixel each time.  From there, consider the coordinate location of each pixel.</p><p>After one split, you&#x27;d have pixels at locations like (0.1,0.3) or (0.7,0.8).  You&#x27;d never have anything smaller than the tenths digit showing up in your pairs.</p><p>After another split, you&#x27;d have pairs like (0.17,0.34) or (0.79,0.81).  Again, nothing smaller than the hundredths digit.  But do you see the pattern?</p><p>After N splits, you can represent any pair with up to N decimal digits.  After an <em>infinite</em> series of splits, you&#x27;d have infinite digits to work with.  And with infinite digits, you can represent any real number between 0 and 1.</p><p>There are uncountably infinite real numbers between 0 and 1, and so there must be an uncountably infinite number of pixels.</p><h3>The Not-So-Flawed Correction</h3><p>I&#x27;m not entirely sure the reasoning of the people who wrote in to correct Butterick, but I can at least comment on the logic of the correction he posted. It wasn&#x27;t so much flawed as just counting something different.</p><p>In the correction, he counts pixels by assigning them to positive integers.  By doing so, he claims that since you can map all of the pixels to integers, there must be countably many of them.  That&#x27;s true, and this is all well and good, but it doesn&#x27;t say anything about the ininite resolution screen.</p><p>You see, the set of all of the pixels of all finitely-sized screens in all the world, no matter what their resolution, is countably infinite.  But these are finite resolutions, not our “infinity screen.”  It&#x27;s a subtle disctinction, but an important distinction.</p><h3>That&#x27;s All I&#x27;ve Got...For Now</h3><p>I hope this does something to clear up the issue (and I hope Internet Folks will tweet me if I&#x27;m wrong). Problems like this are really fun to think about.  I&#x27;m done for now, but I think there is another followup post coming soon.  Infinity is a weird thing.  Be wary of it.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Revealing Module Pattern and `This`]]></title>
            <link>https://www.wakamoleguy.com/p/revealing-module-pattern-and-this</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/revealing-module-pattern-and-this</guid>
            <pubDate>Thu, 30 Apr 2015 00:00:00 GMT</pubDate>
            <description><![CDATA[I read an interesting post the other day by Ben Nadel (<a href="https://twitter.com/BenNadel">@BenNadel</a>). It used a relatively simple cache module to illustrate <a href="http://www.bennadel.com/blog/2798-using-method-chaining-with-the-revealing-module-pattern-in-javascript.htm"><code>this</code> behavior in the revealing module pattern</a>. It's a good read, and it got me thinking further about public and private methods and <code>this</code>.  The most thought provoking aspect for me, though, was the almost-footnote at the end: this doesn't work for private methods.

Can we fix that? Maybe.
]]></description>
            <content:encoded><![CDATA[<p>I read an interesting post the other day by Ben Nadel (<a href="https://twitter.com/BenNadel">@BenNadel</a>). It used a relatively simple cache module to illustrate <a href="http://www.bennadel.com/blog/2798-using-method-chaining-with-the-revealing-module-pattern-in-javascript.htm"><code>this</code> behavior in the revealing module pattern</a>. It&#x27;s a good read, and it got me thinking further about public and private methods and <code>this</code>.</p><p>In summary, the post showed the interesting way that method works using the revealing module pattern. Since you are defining function statements and exposing them through an object literal, <code>this</code> may not always refer to what you&#x27;d expect. Specifically, <code>this</code> will refer to the returned object literal, allowing you to chain methods within that publically exposed API.</p><p>I&#x27;ve written a decent amount of JavaScript using the revealing module pattern, so this wasn&#x27;t exactly news to me.  I wasn&#x27;t shocked that you can write methods that chain using that pattern.  Instead, the most thought provoking aspect of the article was the almost-footnote at the end: this doesn&#x27;t work for private methods.  Because <code>this</code> refers to the object literal, you cannot use it to chain any private or protected methods that you may have defined within the same constructor closure.</p><p>Can we fix that?  Maybe.</p><h3>A New SimpleCache Module</h3><p>To do this, we first need a new SimpleCache module with a private method.  I added one public method, <code>init</code>, which can be called to insert dummy values. For the sake of this example, <code>init</code> in turn calls two private methods using chaining: <code>initSome</code> and <code>initMore</code>.  Here&#x27;s the code:</p><div data-height="2700" data-theme-id="1062" data-slug-hash="oXXxWz" data-default-tab="js" data-user="wakamoleguy" class="codepen"><pre><code class="language-javascript lang-javascript">// Create an instance of our cache and set some keys. Notice that the [new] operator
// is optional since the SimpleCache (and revealing module pattern) doesn&#x27;t use
// prototypical inheritance. And, we can use method-chaining to set the cache keys.
var cache = SimpleCache().init();

output = document.getElementById(&#x27;output&#x27;)
output.innerHTML = cache.get(&#x27;a&#x27;) || false;


// ---------------------------------------------------------- //
// ---------------------------------------------------------- //


// I provide a super simple cache container.
function SimpleCache() {

    // Create an object without a prototype so that we don&#x27;t run into any cache-key
    // conflicts with native Object.prototype properties.
    var cache = Object.create( null );

    var priv = {
        get: get,
        has: has,
        remove: remove,
        set: set,
        init: init,
        initSome: initSome,
        initMore: initMore
    };

    var publ = {
        get: get.bind(priv),
        has: has.bind(priv),
        remove: remove.bind(priv),
        set: set.bind(priv),
        init: init.bind(priv)
    };

    // Reveal the public API.
    return(publ);


    // ---
    // PUBLIC METHODS.
    // ---


    // I get the value cached at the given key; or, undefined.
    function get( key ) {
        return( cache[ key ] );
    }


    // I check to see if the given key has a cached value.
    function has( key ) {
        return( key in cache );
    }


    // I remove the given key (and associated value) from the cache.
    // --
    // NOTE: Returns [this] for method chaining.
    function remove( key ) {
        delete( cache[ key ] );
        return( publ );

    }


    // I cache the given value at the given key.
    // --
    // NOTE: Returns [this] for method chaining.
    function set( key, value ) {
        cache[ key ] = value;
        return( publ );

    }

    // I initialize the cache with some dummy values
    // --
    // NOTE: Returns [this] for method chaining.
    function init() {
        this
          .initSome()
          .initMore();
        return ( publ );
    }

    // ---
    // PRIVATE METHODS
    // ---

    // I initialize the cache with some dummy values
    // --
    // NOTE: Returns [this] for method chaining.
    // NOTE: Private
    function initSome() {
        this
          .set(&#x27;a&#x27;, &#x27;Alice&#x27;)
          .set(&#x27;b&#x27;, &#x27;Bob&#x27;)
          .set(&#x27;c&#x27;, &#x27;Carol&#x27;);
        return ( this );
    }

    // I initialize the cache with some more dummy values
    // --
    // NOTE: Returns [this] for method chaining.
    // NOTE: Private
    function initMore() {
        return this
          .set(&#x27;x&#x27;, &#x27;foo&#x27;)
          .set(&#x27;y&#x27;, &#x27;bar&#x27;)
          .set(&#x27;z&#x27;, &#x27;baz&#x27;);
        return ( this );
    }

}</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/oXXxWz/">oXXxWz</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><h3>A Separate Object, with Bound Public Methods</h3><p>Notice that all of our methods, both public and private, are defined in the same way as before. Additionally, we create explicit <code>publ</code> and <code>priv</code> objects. When we expose our methods on the public object, we bind them to the <code>priv</code> object.  This ensures that internal functions can call each other with chaining, as they will all be bound to the same object.</p><p>Lastly, in our public chained methods, we return <code>publ</code> instead of <code>this</code>. That way, public users of our SimpleCache are never given a reference to the private object, and instead are always passed the publicly exposed API. Note that public methods can still chain to other public methods.</p><h3>Is This Actually Useful?</h3><p>In his original post, Ben questioned the usefulness of chaining private methods. The example above is admittedly contrived just for this purpose. I don&#x27;t know that I&#x27;ve seen any real case for this in the wild, and the dual-object approach is awfully complex for what it accomplishes. Not to mention the issues this could cause with prototypal inheritance and method lifting.  When you bind the public methods, the consumer of the module loses the ability to redirect <code>this</code> to something else. Is throwing a wrench at your module&#x27;s users worth it for slightly easier to use private methods?</p><p>Defining extra objects and binding functions also increases the memory footprint of your module. Each time you create one of these new SimpleCaches, you are eating up just a little more of your user&#x27;s browser resources.</p><p>So, in the end, while this was an interesting thought experiment, I really cannot see anybody doing this in an actual project.  What do you think?  Agree or disagree?  Have a better way of doing it? Let me know on Twitter.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Playing a FLAC file over WebRTC with SIP.js and Flac.js]]></title>
            <link>https://www.wakamoleguy.com/p/flac-over-webrtc-with-sipjs</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/flac-over-webrtc-with-sipjs</guid>
            <pubDate>Sun, 09 Nov 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[After [getting my Raspberry Pi up and running](/p/raspberry-pi-adventure-begins/) last week, I was really pumped to continue on, find a project, and put it to good use. I spent this weekend exploring the world of **[Web Audio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)**. Even working with browsers and **WebRTC** all day at work, I am constantly surprised by the ease with which HTML5 lets you wield a lot of power to do cool things. Here is how to do one thing I learned this weekend: Playing a FLAC file from one computer to another using WebRTC.
]]></description>
            <content:encoded><![CDATA[<p>After <a href="https://www.wakamoleguy.com/p/raspberry-pi-adventure-begins/">getting my Raspberry Pi up and running</a> last week, I was really pumped to continue on, find a project, and put it to good use.  I spent this weekend exploring the world of <strong><a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API">Web Audio</a></strong>. Even working with browsers and <strong>WebRTC</strong> all day at work, I am constantly surprised by the ease with which HTML5 lets you wield a lot of power to do cool things.  Here is how to do one thing I learned this weekend:  Playing a FLAC file from one computer to another using WebRTC.</p><h3>What I used:</h3><p class="note">Update:  OnSIP has since removed their developer offering.</p><ul><li><strong><a href="http://sipjs.com/">SIP.js</a></strong> and an <strong><a href="http://www.onsip.com/webrtc-sip-network">OnSIP Developer account</a></strong> - This would work using the vanilla WebRTC API as well. I used OnSIP since it&#x27;s what I&#x27;m familiar with (I&#x27;m not trying to do a sales pitch here).</li><li><strong><a href="https://github.com/audiocogs/flac.js">Flac.js</a></strong> and <strong><a href="https://github.com/audiocogs/aurora.js">Aurora.js</a></strong> - Put out by <a href="http://audiocogs.org/">Audiocogs</a>, these libraries let you load and play FLAC files in your browser using the Web Audio API.  They have several other codecs available as well.</li><li>A FLAC file to play. I used Coldplay&#x27;s <em>Sky Full of Stars</em>.  The actual song chosen <em>probably</em> doesn&#x27;t matter.</li><li>Chrome, for the browser transmitting the FLAC file. Firefox gets finicky about sending certain MediaStreams over WebRTC.</li></ul><h3>Putting it together</h3><p>Wiring these pieces up really could not have been much easier.  Flac.js and Aurora.js together provide a simple way to preload and decode the FLAC file, and they also spit out events implementing the same interface as SIP.js!  Since Aurora.js plays the file using a source context, all we have to do is grab that and connect it to a new <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamAudioDestinationNode">MediaStream destination</a>.  From there, SIP.js can take the stream and offer it in place of your regularly captured microphone audio.</p><p>In the end, the explanation is probably longer than the code itself.</p><div data-height="155" data-theme-id="1062" data-slug-hash="bNbLOx" data-default-tab="html" data-user="wakamoleguy" class="codepen"><pre><code class="language-html lang-html">&lt;script src=&quot;aurora.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;flac.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;sip-0.6.3.js&quot;&gt;&lt;/script&gt;</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/bNbLOx/">bNbLOx</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><div data-height="535" data-theme-id="1062" data-slug-hash="bNbLOx" data-default-tab="js" data-user="wakamoleguy" class="codepen"><pre><code class="language-javascript lang-javascript">// Load the FLAC file
window.player = AV.Player.fromURL(&#x27;http://localhost/path/to/file.flac&#x27;)
player.preload()

player.on(&#x27;ready&#x27;, function () {
  console.log(&#x27;ready&#x27;)

  // Aurora doesn&#x27;t create the audio context until you start playing it.
  player.play()
  player.pause()

  // Wire the WebAudio source and destination together.
  var dest = player.device.device.context.createMediaStreamDestination()
  player.device.device.node.connect(dest)

  // Send the stream to a destination using SIP and WebRTC.
  new SIP.UA()
    .invite(&#x27;listener@example.onsip.com&#x27;, { media: { stream: dest.stream } })
    .on(&#x27;accepted&#x27;, function () {
      player.play()
    })
})</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/bNbLOx/">bNbLOx</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><p>When you load the page, it will fetch the specified FLAC file and start preloading it, before calling the specified SIP address.  I pointed it to my OnSIP address and was able to receive the call in <a href="https://insta.onsip.com/phone">InstaPhone</a>.  The call showed up like any normal call, and when I answered it, the music began playing!</p><h3>What&#x27;s next?</h3><p>Playing a FLAC file over WebRTC using <em>under 20 lines of JavaScript!</em>  I know I have plans of building some cool things with this.  Streaming music from my Pi to my phone?  Sure!  Preloading my playlist so it can stream even while I am on the subway?  You bet!  What about you?  If you have some crazy ideas, <a href="https://twitter.com/share?url=https://www.wakamoleguy.com/p/flac-over-webrtc-with-sipjs/&amp;amp;text=Playing%20a%20FLAC%20file%20over%20WebRTC%20with%20SIP.js%20and%20Flac.js&amp;amp;via=wakamoleguy" target="_blank">head over to Twitter</a> and share them!</p><p>Just remember, if you are playing music over WebRTC, mind the licenses. I plan on sending music only to myself, and only music that I have purchased. I would advise a similar level of copyright caution to any other experimenters.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Waka's Raspberry Pi - An Adventure Begins]]></title>
            <link>https://www.wakamoleguy.com/p/raspberry-pi-adventure-begins</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/raspberry-pi-adventure-begins</guid>
            <pubDate>Wed, 05 Nov 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[It has been over a year since curiosity got the best of me and I purchased a <a href="http://www.raspberrypi.org/">Raspberry Pi</a>. Due to a bad SD card, it was originally shelved, one operating system short. The past couple days, though, the Pi came off the shelf and back into the workshop (read: corner of my desk).  I'm still not sure entirely what I am going to build with the Pi (perhaps something music related), but I am happy to say that I managed to get it primed and ready for development.  Here's the rundown of the setup process.
]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://www.wakamoleguy.com/img/rasp-pi-setup.jpg"/><link rel="preload" as="image" href="https://www.wakamoleguy.com/img/rasp-pi-nodejs.jpg"/><p>It has been over a year since curiosity got the best of me and I purchased a <a href="http://www.raspberrypi.org/">Raspberry Pi</a>. And how could I not? At less than $50, you get a little computer, complete with an ethernet jack, HDMI out, and a couple of USB ports to boot, all running off of a 5V 1A micro USB charger.  I had about a dozen of those chargers lying around unused, since day-to-day charging of my phone, Kindle, etc really only required one or two in circulation.</p><p>So, I ordered a Raspberry Pi. And boy was I excited!  I dreamed of connecting the ethernet ports already wired through my apartment&#x27;s walls and turning them into my own version of <a href="https://www.youtube.com/watch?v=Wx7RCJvoCMc">Stark&#x27;s JARVIS</a>.  When the Pi arrived, though, there were difficulties.  It turned out the SD card was DOA, and so my Pi was shelved, one operating system short.</p><p>I&#x27;ve since moved out of that wired up apartment (and in with my SO, which I would consider a very worthwhile trade), but I still get that tingly sensation when I think of smartening my living quarters with some custom tech.  The new apartment tends to hold pockets of uncomfortable heat as well, so the low power usage of the Pi is incredibly appealing.</p><p>And so, the Pi came off the shelf and back into the workshop (read: corner of my desk).  I&#x27;m still not sure entirely what I am going to build with the Pi (perhaps something music related), but I am happy to say that I managed to get it primed and ready for development.  Here&#x27;s the rundown of the setup process.</p><h3>The SD Card and Operating System</h3><p>As I dove back into this, I was optimistic that I could get things working, but I really didn&#x27;t know exactly what had gone wrong the first time around. Possible scapegoats were the SD card, fluctuating power from a weak charger, or maybe even a hardware issue on the Pi itself. The first step was to debug the SD card.</p><p>I don&#x27;t use SD cards for anything, really, so I wasn&#x27;t sure how to debug it.  Neither my work laptop or home PC could read them, and I didn&#x27;t have any customized reader on hand.  But, on a stroke of luck, my SO&#x27;s laptop (an older Macbook) actually had a slot to read it! Strange that the ports change so much between generations on those.  Anyways, the laptop didn&#x27;t recognize the card, but it was reading others fine.  I guess the original SD card was dead all along.</p><p>This is where I opened up my Amazon cart and starting dropping things in.  I decided not to bother getting a blank card and writing the OS image manually, so the first item in my card was the <a href="http://www.amazon.com/Raspberry-8GB-Preloaded-NOOBS-Card/dp/B00ENPQ1GK">NOOBS SD card</a>.  I also added a <a href="http://www.amazon.com/AmazonBasics-Port-2-5A-power-adapter/dp/B00DQFGH80/ref=sr_1_2?s=electronics&amp;ie=UTF8&amp;qid=1415250487&amp;sr=1-2&amp;keywords=amazon+basics+hub">four port powered USB hub</a> and a <a href="http://www.amazon.com/Raspberry-Pi-Case-Blackberry/dp/B00ASJRMT0/ref=sr_1_1?s=electronics&amp;ie=UTF8&amp;qid=1415250517&amp;sr=1-1&amp;keywords=raspberry+pi+case">case for the Pi</a>.</p><p>The NOOBS card was really great. Disk images and bootable media have always been a real source of pain for me.  This card removes all of the worry by packing several Linux distros right there for you to pick from.  No messing around with disk partitions or boot flags.  Just plug in a keyboard, scroll down to your choice OS, and go.  I went with Arch Linux, to match my PC.</p><p>Lesson: Don&#x27;t give yourself unnecessary hardship before you even start.</p><h3>With Little Power Comes Great Responsibility</h3><p>At this point, I could boot up the Pi and log in as root.  Awesome! Next stop, Wifi.  I wasn&#x27;t planning on keeping this within close proximity to the router, so getting a USB Wifi dongle configured was my top priority.  I started reading up on <code>netctl</code> and interfaces and...</p><p>Keyboard is dead.</p><p>Unplug it, plug it back in.  Nothing.  Reboot the Pi.  Nothing.  <em>sigh</em> Nothing. (Okay, I didn&#x27;t really expect that to work.)  Switching USB ports worked, for a while.  Then the second would go down and the first would work again.  Something weird was going on.</p><p>It turns out that both USB and the Pi itself have mechanisms in place to limit the current flowing through them.  This can make things like USB keyboards and Wifi dongles stop working, but on the bright side, the device doesn&#x27;t catch fire and burn down the surrounding domecile.  It&#x27;s a trade-off.  The trick is, these mechanisms (called <a href="http://elinux.org/Polyfuses_explained">polyfuses</a>) don&#x27;t clear right away.  You have to set them down, walk away, and come back hours or days later.</p><p>It took me a lot of trial and error to get a reliable power situation running, where devices had enough consistent electricity without driving the current up to the point of killing the Pi.  It looks something like this:</p><img src="https://www.wakamoleguy.com/img/rasp-pi-setup.jpg" alt="Raspberry Pi Setup. Power in to Pi, USB A to keyboard, USB B to hub.  Hub is 2.5 Amp with Wifi dongle attached."/><p>The power cable coming into the Pi is slightly better than your average phone charger, supplying 1.2 Amps at 5V.  This gives a little flexibility for powering the Pi itself and any device connected directly to it.  In this case, that&#x27;s the keyboard (the HDMI monitor has its own power, and the other USB goes to the powered hub).</p><p>The USB hub from Amazon manages the power for the USB dongle, as well as other USB devices I plan to connect (like an external hard drive).  It supplies 2.5 Amps, which is more than enough for the Wifi dongle.  I haven&#x27;t tried the external drive yet, so this may take more tweaking.</p><p>As an aside, don&#x27;t try to power the Pi from the hub.  I did this, thinking it could draw from the hub&#x27;s excess power while still looking at the other devices on the hub.  Instead, it dropped into a hard reboot cycle that I&#x27;m surprised didn&#x27;t cause significant corruption to the SD card.</p><p>Lesson:  Power is finicky when there isn&#x27;t much of it.</p><h3>To the Internet!</h3><p>Okay, Wifi for real this time.  Once I had the power set up properly, Wifi was a lot easier to get going.  It turns out that most of my problems were caused by the dongle not having power and becoming unreachable.  Those went away, and the packets flowed.</p><p>Along the way, though, I had a fair share of <code>netctl</code> errors.  Tracking them down was tricky, as the system time would reset to 1969 each time the Pi booted.  Logs were buried and debug information was hard to come by. I found myself manually setting the time to January 2014, and stepping forward a day each time the system booted.</p><p>Once the time was temporarily fixed, I managed to get to the Internet.  That let me use NTP to get the <em>real</em> time.  The last step was setting them both to happen on startup with <code>systemctl</code>.  Everything went pretty smoothly from there.</p><p>One system update and a few pacman installs later, I have a working system.  It even runs Node:</p><img src="https://www.wakamoleguy.com/img/rasp-pi-nodejs.jpg" alt="Lowsy screen pic of Node.JS http server code."/><h3>Next Stop, Adventure!</h3><p>Now that the basic system is set up, I&#x27;m stoked to get something real up and running.  The sky is the limit, and <a href="https://www.wakamoleguy.com/p/clouds-and-butts">there&#x27;s not a butt in sight.</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Clouds and Butts]]></title>
            <link>https://www.wakamoleguy.com/p/clouds-and-butts</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/clouds-and-butts</guid>
            <pubDate>Thu, 01 May 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[Browsers nowadays provide lots of ways to personalize your experience. Firefox has its [Add Ons](https://addons.mozilla.org/en-US/firefox/) and Chrome has [Extensions](https://chrome.google.com/webstore/category/extensions?utm_campaign=en&utm_source=en-ha-na-us-sk-ext&utm_medium=ha). These can be great for enhancing your browser, from increasing productivity, personalizing themes, or even adding just a little humor to your day to day surfing, but they can also be dangerous.
]]></description>
            <content:encoded><![CDATA[<link rel="preload" as="image" href="https://www.wakamoleguy.com/img/JiveButt.png"/><p>Browsers nowadays provide lots of ways to personalize your experience. Firefox has its <a href="https://addons.mozilla.org/en-US/firefox/">Add Ons</a> and Chrome has <a href="https://chrome.google.com/webstore/category/extensions?utm_campaign=en&amp;utm_source=en-ha-na-us-sk-ext&amp;utm_medium=ha">Extensions</a>. These can be great for enhancing your browser, from increasing productivity, personalizing themes, or even adding just a little humor to your day to day surfing.</p><p>Extensions can be dangerous, though. From extensions with poor security to <a href="http://arstechnica.com/security/2014/01/malware-vendors-buy-chrome-extensions-to-send-adware-filled-updates/">AdWare vendors taking advantage of auto-updates to install malware in previously trusted extensions</a>, you have to keep as watchful eye on extensions as any software you would install and run on your computer. But there&#x27;s one danger that I doubt any security or news outlet will warn you about:</p><p>Butts.</p><p><img alt="Out with the old, in with my Butt." src="https://www.wakamoleguy.com/img/JiveButt.png"/></p><p>That&#x27;s right. Last week, I tried out a very popular (and I admit, hilarious) Chrome extension <a href="https://chrome.google.com/webstore/detail/cloud-to-butt-plus/apmlngnhgbnjpajelfkmabhkfapgnoai?hl=en">Cloud to Butt Plus</a>. Install this little extension and it will do one thing: replace every instance it finds of the &#x27;cloud&#x27; (or &#x27;the cloud&#x27;) online with &#x27;butt&#x27; (or &#x27;my butt&#x27;). I guarantee if you install this extension, you will forget about it until it strikes hours or days later. Hilarity ensues. But it&#x27;s not all fun and games...</p><p>Cloud to Butt replaces every cloud it finds, regardless of where in the page it is. This includes unexpected places, such as input fields. Just last week, while working on the website at work (by the way, have you seen the <a href="http://www.onsip.com/webrtc-sip-network">new section for developers?</a>), I signed into Drupal to edit a couple pages. As the page content loaded to be edited, Cloud to Butt happily traversed the text areas, explaining everything you would want to know about butt-based architectures and undersubscribed butt networks.</p><p>So beware, anybody who works with butt storage or who would like to harness the power of my butt. You never know when a humorous extension may really surprise you.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Here Be Dragons]]></title>
            <link>https://www.wakamoleguy.com/p/here-be-dragons</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/here-be-dragons</guid>
            <pubDate>Sat, 15 Mar 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[For a few years now, the <a href="http://js1k.com/">JS1K</a> contest has been asking folks, "What can you do with just 1,024 bytes of JavaScript?"  As it turns out, people can do some really amazing things.  Just check out <a href="http://js1k.com/2010-xmas/demo/856">the winner from back in 2010</a> (Firefox seems to work best) which animates a decorated Christmas tree, or <a href="http://js1k.com/2013-spring/demo/1555">Strange Crystals II</a>, which won in the spring of 2013.  For the current contest, title 'Here Be Dragons', I decided to try my hand at it.  What can I do with just 1K of JavaScript?  Not much.
]]></description>
            <content:encoded><![CDATA[<p>For a few years now, the <a href="http://js1k.com/">JS1K</a> contest has been asking folks, &quot;What can you do with just 1,024 bytes of JavaScript?&quot;  As it turns out, people can do some really amazing things.  Just check out <a href="http://js1k.com/2010-xmas/demo/856">the winner from back in 2010</a> (Firefox seems to work best) which animates a decorated Christmas tree, or <a href="http://js1k.com/2013-spring/demo/1555">Strange Crystals II</a>, which won in the spring of 2013.  For the current contest, title &#x27;Here Be Dragons&#x27;, I decided to try my hand at it.  What can I do with just 1K of JavaScript?  Not much.</p><h3>It&#x27;s Cooler in my Mind</h3><p>When I first set out, I had this grand vision of sailing a pirate ship through unknown waters, shooting cannonball at firebreathing dragons.  I knew it would be a challenge to fit all of the features I wanted into 1K, but I opted for overshooting rather than trying to come up with an idea that sounded suitably bite-sized.  Maybe I would surprise myself, or 1024 bytes would turn out to be more than it sounds.</p><p>It didn&#x27;t.  1K is tiny.  I wasn&#x27;t familiar with the Canvas API, so I decided to go the DOM route.  First of all, that was a huge mistake.  DOM is not only harder to draw things with than a canvas, but also incredibly expensive to style.  Who has room to type out &#x27;background-color&#x27; or &#x27;-webkit-transition&#x27; when those precious bytes could be going to add clouds or random spawn points?  But at this point, I was committed to making it work as best I could.  There&#x27;s always next time to try something new.</p><h3>Let&#x27;s Break It Down</h3><p>Before I go further, you may want to check out <a href="http://js1k.com/2014-dragons/demo/1788">the demo on JS1K</a> to see what I&#x27;m talking about.  It&#x27;s not pretty.  You should really look at <a href="http://js1k.com/2014-dragons/demos">some of the awesome things other people made</a> as well.  But anyways, if you&#x27;ve decided to stick around, below I&#x27;ll walk through the entire source code.  Don&#x27;t worry, it&#x27;s not too long.</p><p>The first part just removes the canvas using the provided function.  I also included a block comment at the top of the file, to help myself keep track of different variables.  The final portion of this chunk defines a few of those variables.</p> ```javascript // Remove canvas d();<p>/*
a
b - body
c - ship
d - dragon
e
f
g
h
i - mouse X
j - mouse Y
k
l
m
M - Math
n - setTimeout
o - setInterval
p - &#x27;px&#x27;
q
r
s - &#x27;style&#x27;
t - 1000
u - 400
v - 50
w
x
y
z
*/</p><p>n = setTimeout;
o = setInterval;
t = 1000;
u = 400;
v = 50;
M = Math;
p = &#x27;px&#x27;;
s = &#x27;style&#x27;;</p><pre><code>
&lt;p&gt;As it turns out, CSS was a huge cost.  I factored out all of the styling for the dragon, the pirate ship, and even the background into this one function &lt;code&gt;setStyles&lt;/code&gt;.  It uses a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with&quot;&gt;&lt;code&gt;with&lt;/code&gt;&lt;/a&gt; statement to save precious bytes on property access.  I was running the code through the &lt;a href=&quot;https://developers.google.com/closure/compiler/&quot;&gt;Google Closure Compiler&lt;/a&gt;, so I wasn&#x27;t worried about the long function name; it would get changed to a single character later.&lt;/p&gt;

```javascript
function setStyles(q, l_background, l_height, l_width, l_top, l_left, l_transition, l_visibility) {
  with(q[s]) {
    position = &#x27;absolute&#x27;;
    background = l_background;
    height = l_height + p;
    width = l_width + p;
    top = (q.T = l_top) + p;
    left = (q.L = l_left) + p;
    transition = l_transition;
    visibility = l_visibility;
  }
}</code></pre><p>Next, I create the pirate and the dragon.  They live as <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div">DIV</a> elements, styled appropriately.  Note the expensive (read: long) names of the DOM methods. <code>createElement</code>, <code>appendChild</code>, and <code>innerHTML</code> are almost as painful as the CSS properties above.  The colors are wasting bytes as well, but that was just laziness.</p><pre><code class="language-javascript lang-javascript">// Create pirate and dragon
function createBlock(isDragon) {
  var q = document.createElement(&#x27;div&#x27;);
  isDragon ?
    setStyles(q,&#x27;green&#x27;,v,v,v,v) :
    setStyles(q,&#x27;brown&#x27;,20,v,u,u);
  isDragon ? (d=q) : (c=q);
  b.appendChild(q);
  q.h = q.innerHTML = 5;
}
setStyles(b,&#x27;skyblue&#x27;,t,t);
createBlock(0);
createBlock(1);
d.U = d.L;
c.U = c.L;</code></pre><p>The bullet code was interesting.  I had originally planned to fire the bullet to the mouse, or perhaps at a set distance from the boat.  After I saw how little room I had to work, collision detection and aiming went out the window.  Instead, the bullets animate from the ship to the dragon, or vise versa, using a CSS transition.  When they are done, they are hidden.  This code also includes the health tracking. Starting healths are cached on the objects, and if the target drops to 0, it is reset to its original health, as well as its position.</p><pre><code class="language-javascript lang-javascript">// Create or update a bullet (cannonball or fireball)
function bulletStyle(fromShip, start, u) {
  u || (u = document.createElement(&#x27;div&#x27;));
  var t = (fromShip ^ start) ? d : c;

  setStyles(u,fromShip?&#x27;#000&#x27;:&#x27;orange&#x27;,5,5,t.T+25,t.L+25,
           &#x27;top 1s,left 1s,visibility 1s&#x27;,start || &#x27;hidden&#x27;);
  return u;
}

// Fire a bullet
function bullet(fromShip,target) {
  var u = bulletStyle(fromShip,1);
  b.appendChild(u);
  n(bulletStyle.bind(0,fromShip,0,u),0);

  n(function () {
    if (!--target.h) {
      target.h = 5;
      target.T = target.U;
      target.L = target.U;
    }
    target.innerHTML = target.h;
  }, t);
}

// Fire cannon on click
this.onclick = bullet.bind(0,1,d);</code></pre><p>This code rotates the ship with the mouse, moving the dragon in the opposite direction.  I hoped this would give the impression of sailing across the open seas, although some imagination is definitely required.  Updating the DOM on every mouse move proved too expensive, so I simply update the mouse position and update the DOM on an interval about 40 times per second. (Remember that <code>o</code> is <code>setInterval</code>.)</p><pre><code class="language-javascript lang-javascript">// Pirate follows mouse
b.parentNode.onmousemove = function (e) {
  i = e.x;
  j = e.y;
}
l=i=j=1;

o(function () {
  var dstyle = d[s];
  var cstyle = c[s];
  var a = M.PI/2-M.atan2(i-u,j-u);

  if (!--l) {
    l = 5;
    cstyle.webkitTransform = cstyle.transform = &#x27;rotate(&#x27; + a + &#x27;rad)&#x27;;
  }
  dstyle.top = (d.T = (d.T - M.sin(a)+t) % t) + p;
  dstyle.left = (d.L = (d.L - M.cos(a)+t) % t) + p;
}, 24);

o(bullet.bind(0,0,c),3*t);</code></pre><h3>Room For Improvement</h3><p>Just about every aspect of this could benefit from some love.  From using <a href="https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame"><code>requestAnimationFrame</code></a> for better performance or avoiding strings for colors, all the way to massive overhauls such as, you know, <em>not</em> destroying the canvas and using the DOM instead, I could have done a lot better.  There are still a couple weeks before the contest ends, so I may revisit it, though I don&#x27;t expect I have a chance of winning.</p><p>I did, however, learn an immense amount from this challenge.  Working under the 1K restriction forced me to think about cost differently.  Day to day, I develop WebRTC applications designed for modern browsers on good networks.  The size of the JavaScript file is almost never a factor in our technical decisions.  Finding myself suddenly worrying about the length of CSS properties was an interesting twist.  I would highly recommend giving it a try.  Even if your final product isn&#x27;t a masterpiece, you&#x27;ll learn to think about your code in a completely different way.  And hey, you&#x27;ll probably still do better than I did.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Variations on a Vanilla Accordion List]]></title>
            <link>https://www.wakamoleguy.com/p/theme-and-variations-accordion</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/theme-and-variations-accordion</guid>
            <pubDate>Sun, 16 Feb 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[In the last post, I walked through one way to make a <a href="/p/vanilla-accordion/">simple accordion list</a> using <a href="http://vanillawebdiet.com/">vanilla JavaScript</a>.  Today, I'll explore several ways an accordion list could be tweaked, sometimes for performance, sometimes for semantics, and sometimes just for style.  No one solution is ever perfect for everybody, so the aim here is to give you ideas for how to best fit the widget to your needs.  And if you don't need an accordion list on your web site, perhaps you can at least walk away having learned a couple questions to ask yourself when adding other fancy widgets to your site.  But enough delay...let's get to it!
]]></description>
            <content:encoded><![CDATA[<p>In the last post, I walked through one way to make a <a href="https://www.wakamoleguy.com/p/vanilla-accordion/">simple accordion list</a> using <a href="http://vanillawebdiet.com/">vanilla JavaScript</a>.  Today, I&#x27;ll explore several ways an accordion list could be tweaked, sometimes for performance, sometimes for semantics, and sometimes just for style.  No one solution is ever perfect for everybody, so the aim here is to give you ideas for how to best fit the widget to your needs.  And if you don&#x27;t need an accordion list on your web site, perhaps you can at least walk away having learned a couple questions to ask yourself when adding other fancy widgets to your site.  But enough delay...let&#x27;s get to it!</p><h3>One-Pass DOM Query</h3><p>In the <a href="https://www.wakamoleguy.com/p/vanilla-accordion/">original article</a>, the JavaScript used <code>document.querySelectorAll</code> to find the accordions, and then another <code>accordion.querySelectorAll</code> to find the click targets within each accordion.  This forces the browser to traverse the DOM of the accordions at least twice (more for nested accordions).  We can avoid this by querying for only the click targets, and then implicitly finding the accordions from there.  Here&#x27;s the CodePen:</p><div data-height="640" data-theme-id="1062" data-slug-hash="mJhlf" data-default-tab="js" class="codepen"><pre><code class="language-javascript lang-javascript">(function () {
  var accordions, targets, ancestor, i;
  
  if(!document.querySelectorAll || !document.body.classList || !Array.prototype.indexOf) return;
  
  targets = document.querySelectorAll(&amp;#x27;.accordion &amp;gt; section &amp;gt; h1&amp;#x27;);
  

  for (i = 0; i &amp;lt; targets.length; i++) {
    ancestor = targets[i].parentNode.parentNode;
    if (!ancestor.classList.contains(&amp;#x27;js&amp;#x27;)) {
      ancestor.accordionTargetBehavior = (function () {
        var currentTarget;
        
        return function () {
          if (currentTarget)
            currentTarget.classList.remove(&amp;#x27;expanded&amp;#x27;);
          currentTarget = this.parentNode;
          currentTarget.classList.add(&amp;#x27;expanded&amp;#x27;);
        };
      })();
    }
    
    targets[i].addEventListener(&amp;#x27;click&amp;#x27;, ancestor.accordionTargetBehavior, false);
    ancestor.classList.add(&amp;#x27;js&amp;#x27;);
  }
})();</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/mJhlf">Accordion Variation - One DOM Pass</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><p>Instead of querying for the accordions, we go straight for the heading elements with <code>document.querySelectorAll(&#x27;.accordion &gt; section &gt; h1&#x27;);</code> and use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node.parentNode"><code>parentNode</code></a> to find the accordion from there.  We also take advantage of the <code>.js</code> class, previously just used to mark accordions as active, to avoid initializing an accordion twice.</p><p>Finally, we cache the click handler function on the accordion element itself, where it can contain a reference to the currently expanded element in a closure.  Each heading in the accordion uses that same function, and therefore has the ability to update the current target.</p><p>I ran this variation through <a href="http://jsperf.com/">jsPerf</a> to see if the changes actually made a difference, and by golly they did!  In both Chrome and Firefox, speeds increased by factors of 2 to 4.  You can see the full results and run the tests yourself on the <a href="http://jsperf.com/accordion-selection">Accordion Selection jsPerf page</a>.</p><h3>DL-DD-DT - Using Definition Lists for Accordions</h3><p>When looking for examples of accordions in the wild, I came across <a href="http://www.mozilla.org/en-US/firefox/mobile/faq/">this one on Mozilla&#x27;s Mobile Firefox FAQ page.</a> The list itself uses an unordered list, but each section contains question and answer pairs represented as a definition list.  Wouldn&#x27;t it be cool if the questions themselves expanded out to show the answers?</p><p>Unfortunately, as shown by the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl">examples on MDN</a>, definition lists have a man-to-many relationship between terms and definitions.  This, along with their flat structure, makes selecting sections of definition lists challenging.  With a little help from <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_selectors">CSS3 general sibling selectors</a>, we can get past these hurdles.</p><p data-height="257" data-theme-id="1062" data-slug-hash="HAFhs" data-default-tab="result" class="codepen">See the Pen <a href="http://codepen.io/wakamoleguy/pen/HAFhs">Accordion Variation - dd</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p><p>The HTML is a simple definition list.  Note that Firefox and Chrome both have multiple definitions.  The JavaScript is tweaked to select on definition elements rather than sections, but is otherwise the same as the original.</p><p>The CSS is where the magic happens.  There are three main selectors at work here. <code>.accordion.js &gt; dt.expanded ~ dd</code> selects all of the definitions following an expanded term.  For example, if Chrome is expanded, it will find the Chrome definitions <em>and</em> the Internet Explorer definition.  We need to make sure that the IE defintion has CSS of a higher priority applied to it.  For that, <code>.accordion.js &gt; dt.expanded ~ dt:not(.expanded) ~ dd</code> does the trick.  After an expanded term, it finds the next unexpanded term, and then selects all of the definitions from then on.  Finally, we need a way to select the definitions before the expanded term.  <code>.accordion.js &gt; dt:not(.expanded) ~ dd</code> gets the job done. Note that this is lower priority than the expanded selector, and won&#x27;t interfere with those styles.</p><p>This still doesn&#x27;t deal with multiple terms that share one definition, although I don&#x27;t think that would be very difficult.  Using JavaScript to mark all those terms as expanded or cleverly applying the adjacent sibling selector (<code>+</code>) would probably work.</p><h3>Keyboard Navigation</h3><p>Our original accordion was not very friendly to keyboard users.  It would be nice if we could <kbd>Tab</kbd> between accordion headings and expand them by pressing <kbd>Return</kbd>.  Well, we can with just a little extra markup.  By adding &#x27;permalinks&#x27; to each heading, we automatically get keyboard access.  Pressing enter will invoke the &#x27;click&#x27; handler, as well.  We just need to be sure to prevent the default behavior of the event to avoid page jumping.  Go ahead and click inside the CodePen and use <kbd>Tab</kbd>, <kbd>Shift</kbd>+<kbd>Tab</kbd>, and <kbd>Return</kbd> to test it out.</p><p data-height="350" data-theme-id="1062" data-slug-hash="DmCdw" data-default-tab="result" class="codepen">See the Pen <a href="http://codepen.io/wakamoleguy/pen/DmCdw">Accordion Variation - Keyboard</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p><h3>Multiple Selection</h3><p>Sometimes it&#x27;s important to be able to expand multiple sections of the accordion at once.  This is an incredibly easy modification...just get rid of tracking the currentTarget:</p><p data-height="430" data-theme-id="1062" data-slug-hash="pCqht" data-default-tab="result" class="codepen">See the Pen <a href="http://codepen.io/wakamoleguy/pen/pCqht">Accordion Variation - Multiple</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p><h3>Accordion?  Nah, let&#x27;s do tabs.</h3><p>You&#x27;ve spent all this time on an accordion list, and now the designer comes to you saying that accordions are out and tabs are all the rage.  Hours of work starting from scratch?  Nah!  Just a few CSS changes.  That&#x27;s right.  All of this uses the same JavaScript and HTML as our original accordion.</p><p data-height="238" data-theme-id="1062" data-slug-hash="qAigx" data-default-tab="result" class="codepen">See the Pen <a href="http://codepen.io/wakamoleguy/pen/qAigx">Accordion Variation - Tabs</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p><h3>Conclusion</h3><p>As you can see, it&#x27;s easy to quickly expand the realm of possibilities, even from a base as simple as the vanilla accordion widget.  What is important to your website or application?  Performance on slower devices?  Keyboard controls for accessibility? Most, if not all, of these variations can be mixed and matched, too.  And hey, if you are inspired to create your own variations or you found this article helpful or even if you hated it, <a href="https://twitter.com/wakamoleguy">tweet me about it</a>.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Basic Vanilla Accordion List]]></title>
            <link>https://www.wakamoleguy.com/p/vanilla-accordion</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/vanilla-accordion</guid>
            <pubDate>Thu, 06 Feb 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[Here lies my first contribution to the <a href="http://vanillawebdiet.com/">Vanilla Web Diet</a>.  I first coded up this accordion list several months ago as part of the <a href="https://www.getonsip.com">GetOnSIP</a> project.  No simple widget can be perfect for every use case.  In this post, I walk through a simple version of a collapsible accordion list, with customization ideas to come later.
]]></description>
            <content:encoded><![CDATA[<p>Here lies my first contribution to the <a href="http://vanillawebdiet.com/">Vanilla Web Diet</a>.  The Diet has gotten quite a following recently, and it even has <a href="http://coding.smashingmagazine.com/2012/11/13/the-vanilla-web-diet/">a book coming out about it</a>.  I first coded up this accordion list several months ago as part of the <a href="https://www.getonsip.com/">GetOnSIP</a> project.  Since then, I&#x27;ve tried several times to write up a complete post about its inner workings.  And I&#x27;ve failed.  I&#x27;ve realized that there are really many different things to consider, from the HTML structure to the CSS effects, to the actual behavior of the list.  No one solution is right for everybody.</p><p>Rather than give up, I decided to break it up into two posts.  In this one, I&#x27;ll show off a very basic, almost primitive accordion list.  In a future post, I will go over many different behavioral, semantic, and stylistic directions to take to customize an accordion list to fit your exact needs.</p><p>In the end, the goal is not to create a one-size-fits-all widget that is perfect for everybody.  That is the kind of goal best suited for frameworks.  The goal is to show what is possible with vanilla JavaScript, because sometimes you don&#x27;t need to download an extra 80K just to make a section of your site collapsible.</p><p>Anyways, enough of that.  Here we go.</p><h3>The HTML</h3><p>A lot of different structures could be turned into an accordion list.  From <a href="http://jqueryui.com/accordion/">jQuery UI&#x27;s unsemantic &lt;div&gt;s and &lt;span&gt;s</a> to ordered or unordered lists to even &lt;dl&gt; definition lists, just about anything can play the role of a collapsible set of content blocks.  For this basic accordion, I chose to use HTML5 &lt;section&gt; elements, as I felt it made the example the cleanest.</p><div data-height="257" data-theme-id="1062" data-slug-hash="lJhys" data-default-tab="html" class="codepen"><pre><code class="language-html lang-html">&lt;section class=&quot;accordion&quot;&gt;
  &lt;section&gt;
    &lt;h1&gt;Yesterday&lt;/h1&gt;
    &lt;p&gt;I was sick yesterday, so not much happened.&lt;/p&gt;
  &lt;/section&gt;
  &lt;section&gt;
    &lt;h1&gt;Today&lt;/h1&gt;
    &lt;p&gt;I have a bunch of things to do today:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Grocery shopping&lt;/li&gt;
      &lt;li&gt;Stop at the bank&lt;/li&gt;
      &lt;li&gt;Dinner and a movie&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/section&gt;
  &lt;section&gt;
    &lt;h1&gt;Road Blocks&lt;/h1&gt;
    &lt;p&gt;I&#x27;m sick!&lt;p&gt;
  &lt;/section&gt;
&lt;/section&gt;</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/lJhys">Vanilla Accordion</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><p>There&#x27;s not much to see:  a section to become an accordion and three sub-sections to hide and show.  I&#x27;ve included a nested list just to prove that the accordion is fairly robust in what content it can show.  The outer &lt;section&gt; gets the class <code>accordion</code>, but otherwise there is no extra markup.  Remember that if JavaScript is disabled or fails to load, the user will still see the HTML.  Keep it clean.</p><h3>The JavaScript</h3><p>The most basic accordion has very simple behavior.  In the beginning, all list items are collapsed; only the heading content is visible.  On interacting with the heading (click or touch, for example), the other content in the list item expands out and becomes visible, at the same time collapsing any other items.  Here is the code, followed by an in-depth explanation.</p><div data-height="257" data-theme-id="1062" data-slug-hash="lJhys" data-default-tab="js" class="codepen"><pre><code class="language-javascript lang-javascript">(function () {
  var accordions, i;

  // Make sure the browser supports what we are about to do.
  if (!document.querySelectorAll || !document.body.classList) return;

  // Using a function helps isolate each accordion from the others
  function makeAccordion(accordion) {
    var targets, currentTarget, i;

    targets = accordion.querySelectorAll(&#x27;.accordion &gt; * &gt; h1&#x27;);
    for(i = 0; i &lt; targets.length; i++) {
      targets[i].addEventListener(&#x27;click&#x27;, function () {
        if (currentTarget)
          currentTarget.classList.remove(&#x27;expanded&#x27;);

        currentTarget = this.parentNode;
        currentTarget.classList.add(&#x27;expanded&#x27;);
      }, false);
    }

    accordion.classList.add(&#x27;js&#x27;);
  }

  // Find all the accordions to enable
  accordions = document.querySelectorAll(&#x27;.accordion&#x27;);

  // Array functions don&#x27;t apply well to NodeLists
  for(i = 0; i &lt; accordions.length; i++) {
    makeAccordion(accordions[i]);
  }

})();</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/lJhys">Vanilla Accordion</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><p>Okay, so there&#x27;s a lot going on in just a few lines of code.  Let&#x27;s break it down.</p><h3>Short Circuit When Unsupported</h3><p>We depend on the browser having implemented <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element.classList">element.classList</a> (<a href="http://caniuse.com/classlist">Can I use...</a>) and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document.querySelectorAll">Document.querySelectorAll</a> (<a href="http://caniuse.com/queryselector">Can I use...</a>).  If they don&#x27;t have those, the accordion won&#x27;t work.  Rather than crash, we detect this and exit cleanly.</p><h3>Find Things Once</h3><p>DOM access is slow. We deal with this by fetching everything we need up front and caching it for later.  This especially shines when clicking to expand a new section.  We could search the sections siblings for any expanded sections, but that is slow and tedious.  Instead, we hold on to the currently expanded section so we have it ready to go.  And when we do click a new section, all we have to do is swap a couple classes and update the variable.  Easy-peasy!</p><p>Some of you may be saying &quot;But hey! Aren&#x27;t you doing a whole bunch of querySelectorAll calls? Doesn&#x27;t that traverse the DOM way more than it needs to?&quot; Umm...yeah.  A clever person could find a way to traverse the DOM once, looking only for accordion sections&#x27; heading elements an inferring the outer accordion from there.  Perhaps that will make a return visit in another post. For now, I&#x27;m satisfied not having to go back to the DOM after initialization.</p><h3>Mark Working Accordions</h3><pre><code class="language-javascript lang-javascript">accordion.classList.add(&#x27;js&#x27;);</code></pre><p>This may seem unnecessary, but it&#x27;s imperative to keeping the accordion accessible.  Remember that for modern browsers which can support the accordion, we would like to start with the headers collapsed.  And yet older browsers should see expanded content.  We accomplish this by adding the <code>.js</code> class to the accordion.  This marks it as enabled and provides a CSS hook to style on.</p><h2>The CSS</h2><p>This is where our hard work in JavaScript land will pay off.  By adding relevant classes to a semantic HTML structure, the CSS involved becomes fairly simple.  I left off vendor prefixes. Browsers that don&#x27;t support the full transition effect will gracefully degrade to switching instantly between visible and invisible.</p><div data-height="257" data-theme-id="1062" data-slug-hash="lJhys" data-default-tab="css" class="codepen"><pre><code class="language-css lang-css">.accordion.js &gt; * {
   overflow: hidden;
}

.accordion.js &gt; *:not(.expanded) &gt; *:not(h1) {
    max-height: 0;
    margin-top: 0;
    margin-bottom: 0;
    opacity: 0;
    visibility: hidden;
}

.accordion.js &gt; .expanded &gt; *:not(h1) {
    max-height: 10em;
    opacity: 1;
    visibility: visible;
}

.accordion.js &gt; * &gt; h1 {
    cursor: pointer;
    visibility: visible;
}

.accordion.js &gt; * &gt; *:not(h1) {
    transition:
        max-height 1s,
        visibility 1s,
        margin 1s,
        opacity 1s;
}</code></pre><p>See the Pen <a href="http://codepen.io/wakamoleguy/pen/lJhys">Vanilla Accordion</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p></div><p>Most of the magic here is hidden in transition the <code>max-height</code> of non-heading children of collapsible content.  Ideally, we would like the content to transition from <code>height: 0</code> to <code>height: auto</code>, but animating to the automatic height of an element isn&#x27;t possible.  Instead, we overshoot with <code>max-height: 10em</code>.  The 10em will vary depending on the content; you must pick a value bigger than the content will every display (so as to avoid trimming), but overshooting by too much will cause odd animation timing.</p><p>We also strip the vertical margins of collapsed content while they are collapsed, which prevents weird spacing issues.  I also like to add an opacity shift, too, to get a fade effect.</p><p>Finally, not that each style is protected by the <code>.accordion.js</code> selector, so they will only apply to enabled accordions.  Users in older browsers will be shown a block of content with only default styling.</p><h2>Conclusion</h2><p>It certainly isn&#x27;t a silver bullet, but in just 33 lines of (commented, spaced) JavaScript and even less CSS, you can get a nice accordion effect on your page.  Here&#x27;s the final result:</p><p data-height="400" data-theme-id="1062" data-slug-hash="lJhys" data-default-tab="result" class="codepen">See the Pen <a href="http://codepen.io/wakamoleguy/pen/lJhys">Vanilla Accordion</a> by Will Mitchell (<a href="http://codepen.io/wakamoleguy">@wakamoleguy</a>) on <a href="http://codepen.io/">CodePen</a>.</p><p>So next time you are creating a web site or web app, don&#x27;t just run to a bloated UI library. Instead, take a few minutes to assess the situation and decide what you really need.  Bytes do affect performance, and sometimes less really is more.  You, too, can help get the web back on its vanilla diet.</p><p>Tune in next time for some more options on customizing accordions, including different HTML structures, keyboard access, and more!</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Wakamoleguy.com Launch]]></title>
            <link>https://www.wakamoleguy.com/p/launch</link>
            <guid isPermaLink="false">https://www.wakamoleguy.com/p/launch</guid>
            <pubDate>Mon, 13 Jan 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[Hi. My name is Will Mitchell, but I often go by **wakamoleguy**. Today marks the launch of [wakamoleguy.com](http://www.wakamoleguy.com/), my new site. Okay, so it has been up since Saturday, but it didn't have any content on it until now.

What is [wakamoleguy.com](http://www.wakamoleguy.com/)? It's my website. For the time being, that means it's my personal blog. I'll keep the subject matter pretty technical, although I won't commit to talking about any one topic. I'll write what I know. Since I'm currently doing a lot of web development, that probably means mostly JavaScript and HTML5 posts at first.

As I write and accumulate examples, I hope to host those on [wakamoleguy.com](http://www.wakamoleguy.com/) as well. Experiments and proofs of concept may show up here, too. In the end, I hope it will become my home on the web.

If you experience a delay when visiting this site, please excuse me. I am using [free Heroku hosting](https://www.heroku.com/) which takes five or ten seconds to wake up after inactivity. Anyways, thank you for putting up with it, welcome, and enjoy your stay!

Cheers!
]]></description>
            <content:encoded><![CDATA[<p>Hi. My name is Will Mitchell, but I often go by <strong>wakamoleguy</strong>. Today marks the launch of <a href="http://www.wakamoleguy.com/">wakamoleguy.com</a>, my new site. Okay, so it has been up since Saturday, but it didn&#x27;t have any content on it until now.</p><p>What is <a href="http://www.wakamoleguy.com/">wakamoleguy.com</a>? It&#x27;s my website. For the time being, that means it&#x27;s my personal blog. I&#x27;ll keep the subject matter pretty technical, although I won&#x27;t commit to talking about any one topic. I&#x27;ll write what I know. Since I&#x27;m currently doing a lot of web development, that probably means mostly JavaScript and HTML5 posts at first.</p><p>As I write and accumulate examples, I hope to host those on <a href="http://www.wakamoleguy.com/">wakamoleguy.com</a> as well. Experiments and proofs of concept may show up here, too. In the end, I hope it will become my home on the web.</p><p>If you experience a delay when visiting this site, please excuse me. I am using <a href="https://www.heroku.com/">free Heroku hosting</a> which takes five or ten seconds to wake up after inactivity. Anyways, thank you for putting up with it, welcome, and enjoy your stay!</p>]]></content:encoded>
        </item>
    </channel>
</rss>