<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="https://perrotta.dev/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Advent-of-Code on ¬ just serendipity 🍀</title>
    <link>https://perrotta.dev/</link>
    <description>Recent content in Advent-of-Code on ¬ just serendipity 🍀</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <managingEditor>serendipity@perrotta.dev (Thiago Perrotta)</managingEditor>
    <webMaster>serendipity@perrotta.dev (Thiago Perrotta)</webMaster>
    <copyright>© 2013 - 2026 Thiago Perrotta ·
  a fork of [hugo ʕ•ᴥ•ʔ bear](https://github.com/janraasch/hugo-bearblog/)
</copyright>
    <lastBuildDate>Thu, 26 Mar 2026 18:46:44 +0100</lastBuildDate>
    <atom:link href="https://perrotta.dev/tags/advent-of-code/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Advents
      </title>
      <link>https://perrotta.dev/2024/12/advents/</link>
      <pubDate>Fri, 27 Dec 2024 20:36:42 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advents/</guid>
      <description>&lt;p&gt;♠ Too many advents:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt;: my favorite. See &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;coding&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://jimmyhmiller.github.io/advent-of-papers&#34;&gt;Advent of Papers&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.debugdecember.com/&#34;&gt;Debug December&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://htmhell.dev/adventcalendar/&#34;&gt;HTMLHell Advent Calendar&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Surely you will never run out of daily technical challenges to do in December!&lt;/p&gt;&#xA;&lt;p&gt;And don&amp;rsquo;t forget about the likes of &lt;a href=&#34;https://wordly.org/&#34;&gt;Wordly&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advents&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 17
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-17/</link>
      <pubDate>Wed, 25 Dec 2024 16:13:30 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-17/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/17&#34;&gt;Day #17&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a simulation problem, a quite delightful one to implement.&lt;/p&gt;&#xA;&lt;p&gt;Using python data classes would have been natural, but I went full imperative in&#xA;this one.&lt;/p&gt;&#xA;&lt;p&gt;Part 2 would require clever backwards computation, and I wasn&amp;rsquo;t interested in&#xA;doing so. I liked the approach from &lt;a href=&#34;https://todd.ginsberg.com/post/advent-of-code/2024/day17/&#34;&gt;Todd&#xA;Ginsberg&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    a, b, c = [int(line.split()[2]) for line in lines[0:3]]&#xA;    program = [int(op) for op in lines[4].split()[1].split(&amp;#34;,&amp;#34;)]&#xA;    ip = 0&#xA;    stdout = []&#xA;&#xA;    def combo(operand):&#xA;        assert 0 &amp;lt;= operand &amp;lt; 7&#xA;&#xA;        if 0 &amp;lt;= operand &amp;lt;= 3:&#xA;            return operand&#xA;        elif operand == 4:&#xA;            return a&#xA;        elif operand == 5:&#xA;            return b&#xA;        elif operand == 6:&#xA;            return c&#xA;&#xA;    while ip &amp;lt; len(program) - 1:&#xA;        opcode = program[ip]&#xA;        operand = program[ip &amp;#43; 1]&#xA;&#xA;        # adv, division&#xA;        if opcode == 0:&#xA;            numerator = a&#xA;            denominator = 2 ** combo(operand)&#xA;            a = numerator // denominator&#xA;        # bxl, bitwise xor&#xA;        elif opcode == 1:&#xA;            b ^= operand&#xA;        # bst, modulo&#xA;        elif opcode == 2:&#xA;            b = combo(operand) % 8&#xA;        # jnz&#xA;        elif opcode == 3:&#xA;            if a != 0:&#xA;                ip = operand&#xA;                continue&#xA;        # bxc, bitwise xor&#xA;        elif opcode == 4:&#xA;            b ^= c&#xA;        # out&#xA;        elif opcode == 5:&#xA;            stdout.append(combo(operand) % 8)&#xA;        # bdv&#xA;        elif opcode == 6:&#xA;            numerator = a&#xA;            denominator = 2 ** combo(operand)&#xA;            b = numerator // denominator&#xA;        # cdv&#xA;        elif opcode == 7:&#xA;            numerator = a&#xA;            denominator = 2 ** combo(operand)&#xA;            c = numerator // denominator&#xA;&#xA;        ip &amp;#43;= 2&#xA;&#xA;    # part one&#xA;    print(&amp;#34;,&amp;#34;.join(map(str, stdout)))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 17&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 9
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-9/</link>
      <pubDate>Wed, 25 Dec 2024 16:09:53 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-9/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/9&#34;&gt;Day #9&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;A disk fragmentation problem.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s mostly an ad-hoc problem, there isn&amp;rsquo;t much commentary to make.&lt;/p&gt;&#xA;&lt;p&gt;Part two was quite annoying so I simply skipped it.&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;def expand(disk: list[int]) -&amp;gt; str:&#xA;    output = []&#xA;    fill = True&#xA;    d = 0&#xA;&#xA;    for n in disk:&#xA;        if fill:&#xA;            output &amp;#43;= [str(s) for s in n * [d]]&#xA;            d &amp;#43;= 1&#xA;        else:&#xA;            output &amp;#43;= n * &amp;#39;.&amp;#39;&#xA;        fill = not fill&#xA;&#xA;    return output&#xA;&#xA;def defrag(disk: str) -&amp;gt; str:&#xA;    p = expand(disk)&#xA;&#xA;    left = 0&#xA;    right = len(p) - 1&#xA;&#xA;    while left &amp;lt; right:&#xA;        if p[left] == &amp;#39;.&amp;#39;:&#xA;            p[left], p[right] = p[right], p[left]&#xA;            right -= 1&#xA;            while p[right] == &amp;#39;.&amp;#39; and left &amp;lt; right:&#xA;                right -= 1&#xA;&#xA;        left &amp;#43;= 1&#xA;&#xA;    return p&#xA;&#xA;def checksum(disk):&#xA;    total = 0&#xA;&#xA;    for i, d in enumerate(disk):&#xA;        if d == &amp;#39;.&amp;#39;:&#xA;            break&#xA;        total &amp;#43;= i * int(d)&#xA;&#xA;    return total&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    disk = [int(x) for x in lines[0]]&#xA;&#xA;    # part one&#xA;    print(checksum(defrag(disk)))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 9&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 8
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-8/</link>
      <pubDate>Fri, 20 Dec 2024 22:47:51 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-8/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/8&#34;&gt;Day #8&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;This is a problem in a 2D grid. I like to start by making a frequency map&#xA;(dictionary) from the frequencies to the coordinates where they occur:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;from collections import defaultdict&#xA;&#xA;# {&amp;#39;0&amp;#39;: ((1,8), ...)}&#xA;freq_map = defaultdict(tuple)&#xA;for x, line in enumerate(lines):&#xA;    for y, field in enumerate(line):&#xA;        if field.isalnum():&#xA;            freq_map[field] &amp;#43;= ((x, y),)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then it&amp;rsquo;s just a matter of going through every coordinate pair for a given&#xA;frequency. &lt;code&gt;combinations()&lt;/code&gt; from &lt;code&gt;itertools&lt;/code&gt; is great for that:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;from itertools import combinations&#xA;&#xA;antinodes = set()&#xA;&#xA;for all_coords in freq_map.values():&#xA;    for coord1, coord2 in combinations(all_coords, 2):&#xA;        antinodes.update(compute_antinodes(coord1, coord2, len(lines), len(lines[0])))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The meat of the code lives in &lt;code&gt;compute_antinodes&lt;/code&gt;. We need to compute two&#xA;coordinates and check whether they are within bounds:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;def within_bounds(x, y, height, width):&#xA;    return 0 &amp;lt;= x &amp;lt; height and 0 &amp;lt;= y &amp;lt; width&#xA;&#xA;def compute_antinodes(coord1, coord2, height, width):&#xA;    x1, y1 = coord1&#xA;    x2, y2 = coord2&#xA;&#xA;    dx = x2 - x1&#xA;    assert dx &amp;gt;= 0&#xA;&#xA;    dy = y2 - y1&#xA;&#xA;    antinodes = ()&#xA;&#xA;    for (x0, y0, direction) in ((x1, y1, -1), (x2, y2, &amp;#43;1)):&#xA;        x, y = x0 &amp;#43; direction * dx, y0 &amp;#43; direction * dy&#xA;        if within_bounds(x, y, height, width):&#xA;            antinodes &amp;#43;= ((x, y),)&#xA;&#xA;    return antinodes&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;assert&lt;/code&gt;ion gives us peace of mind.&lt;/p&gt;&#xA;&lt;p&gt;The answer is the number of &lt;code&gt;antinodes&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For part two, we need to extend the &lt;code&gt;compute_antinodes&lt;/code&gt; logic to keep going&#xA;until it gets out-of-bounds:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;def compute_antinodes(coord1, coord2, height, width, unbounded=False):&#xA;    x1, y1 = coord1&#xA;    x2, y2 = coord2&#xA;&#xA;    dx = x2 - x1&#xA;    assert dx &amp;gt;= 0&#xA;&#xA;    dy = y2 - y1&#xA;&#xA;    if unbounded:&#xA;        antinodes = ((x1, y1), (x2, y2))&#xA;    else:&#xA;        antinodes = ()&#xA;&#xA;    for (x0, y0, direction) in ((x1, y1, -1), (x2, y2, &amp;#43;1)):&#xA;        steps = 1&#xA;        while True:&#xA;            x, y = x0 &amp;#43; direction * steps * dx, y0 &amp;#43; direction * steps * dy&#xA;            if within_bounds(x, y, height, width):&#xA;                antinodes &amp;#43;= ((x, y),)&#xA;                steps &amp;#43;= 1&#xA;            else:&#xA;                break&#xA;&#xA;    return antinodes&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;#!/usr/bin/env python3&#xA;from collections import defaultdict&#xA;from itertools import combinations&#xA;&#xA;import sys&#xA;&#xA;def within_bounds(x, y, height, width):&#xA;    return 0 &amp;lt;= x &amp;lt; height and 0 &amp;lt;= y &amp;lt; width&#xA;&#xA;def compute_antinodes(coord1, coord2, height, width, unbounded=False):&#xA;    x1, y1 = coord1&#xA;    x2, y2 = coord2&#xA;&#xA;    dx = x2 - x1&#xA;    assert dx &amp;gt;= 0&#xA;&#xA;    dy = y2 - y1&#xA;&#xA;    if unbounded:&#xA;        antinodes = ((x1, y1), (x2, y2))&#xA;    else:&#xA;        antinodes = ()&#xA;&#xA;    for (x0, y0, direction) in ((x1, y1, -1), (x2, y2, &amp;#43;1)):&#xA;        steps = 1&#xA;        while True:&#xA;            x, y = x0 &amp;#43; direction * steps * dx, y0 &amp;#43; direction * steps * dy&#xA;            if within_bounds(x, y, height, width):&#xA;                antinodes &amp;#43;= ((x, y),)&#xA;                steps &amp;#43;= 1&#xA;            else:&#xA;                break&#xA;&#xA;    return antinodes&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    # {&amp;#39;0&amp;#39;: ((1,8), ...)}&#xA;    freq_map = defaultdict(tuple)&#xA;    for x, line in enumerate(lines):&#xA;        for y, field in enumerate(line):&#xA;            if field.isalnum():&#xA;                freq_map[field] &amp;#43;= ((x, y),)&#xA;&#xA;    antinodes = set()&#xA;&#xA;    for all_coords in freq_map.values():&#xA;        for coord1, coord2 in combinations(all_coords, 2):&#xA;            antinodes.update(compute_antinodes(coord1, coord2, len(lines), len(lines[0])))&#xA;&#xA;    # part one&#xA;    print(len(antinodes))&#xA;&#xA;    antinodes = set()&#xA;&#xA;    for all_coords in freq_map.values():&#xA;        for coord1, coord2 in combinations(all_coords, 2):&#xA;            antinodes.update(compute_antinodes(coord1, coord2, len(lines), len(lines[0]), unbounded=True))&#xA;&#xA;    # part two&#xA;    print(len(antinodes))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Instead of using tuples or coordinates all over the place, we could simply have&#xA;modified the map inplace, and then iterated over it in the end to count the&#xA;antinodes. I like the tuple abstraction better, and it&amp;rsquo;s quite efficient anyway.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 8&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Just
      </title>
      <link>https://perrotta.dev/2024/12/just/</link>
      <pubDate>Fri, 13 Dec 2024 01:16:41 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>advent-of-code</category>
      <category>bestof</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/just/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://github.com/casey/just&#34;&gt;Just&lt;/a&gt; is a command runner, a modern replacement&#xA;for GNU Make.&lt;/p&gt;&#xA;&lt;p&gt;It is written in Rust, has sensible defaults, and lots of syntactic sugar.&#xA;A good analogy is &lt;code&gt;fish&lt;/code&gt; versus &lt;code&gt;bash&lt;/code&gt; when comparing &lt;code&gt;just&lt;/code&gt; to &lt;code&gt;make&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s very easy to learn from its&#xA;&lt;a href=&#34;https://github.com/casey/just?tab=readme-ov-file&#34;&gt;README.md&lt;/a&gt; alone as it&amp;rsquo;s&#xA;quite comprehensive. There&amp;rsquo;s also a &lt;a href=&#34;https://just.systems/man/en/&#34;&gt;gitbook&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://til.simonwillison.net/django/just-with-django&#34;&gt;Simon Willison&lt;/a&gt; prompted&#xA;me to try it out.&lt;/p&gt;&#xA;&lt;p&gt;As an exercise I decided to convert the &lt;code&gt;Makefile&lt;/code&gt; used to manage this blog into&#xA;a &lt;code&gt;Justfile&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The original &lt;code&gt;Makefile&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-makefile&#34;&gt;# Sitemap URL&#xA;SITEMAP = https://perrotta.dev/sitemap.xml&#xA;&#xA;# Hugo port&#xA;PORT := 1313&#xA;&#xA;# Abort if hugo is not installed.&#xA;ifeq (, $(shell which hugo))&#xA;  $(error &amp;#34;No hugo in $$PATH, install it first&amp;#34;)&#xA;endif&#xA;&#xA;all:&#xA;&#x9;hugo server --bind=&amp;#34;0.0.0.0&amp;#34; --buildDrafts --port $(PORT) --watch&#xA;&#xA;build:&#xA;&#x9;hugo --environment production --gc --minify&#xA;&#xA;clean:&#xA;&#x9;$(RM) -r public/ resources/&#xA;&#xA;ping:&#xA;&#x9;# Ping Google about changes in the sitemap&#xA;&#x9;curl -sS -o /dev/null &amp;#34;https://www.google.com/ping?sitemap=$(SITEMAP)&amp;#34;&#xA;&#x9;# Ping Bing (DuckDuckGo, etc) about changes in the sitemap&#xA;&#x9;curl -sS -o /dev/null &amp;#34;https://www.bing.com/ping?sitemap=$(SITEMAP)&amp;#34;&#xA;&#xA;.PHONY: all build clean ping&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Initially I asked ChatGPT to convert it to a &lt;code&gt;Justfile&lt;/code&gt; but it was a disaster,&#xA;even after a couple of iterations. Then I did it myself&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/just/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. The &lt;code&gt;Justfile&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-justfile&#34;&gt;set dotenv-load&#xA;&#xA;watch:&#xA;&#x9;hugo server --buildDrafts --port ${PORT:-1313} --watch&#xA;&#xA;build:&#xA;&#x9;hugo --environment production --gc --minify&#xA;&#xA;# Create a new post. Usage: `just new &amp;#34;advent of code day 8&amp;#34;`&#xA;new post:&#xA;&#x9;hugo new content/posts/`date &amp;#34;&amp;#43;%Y-%m-%d&amp;#34;`-{{ kebabcase(post) }}.md&#xA;&#xA;clean:&#xA;&#x9;rm -rf public/ resources/&#xA;&#xA;# Ping Google and Bing about changes in the sitemap&#xA;ping sitemap=&amp;#34;https://perrotta.dev/sitemap.xml&amp;#34;:&#xA;&#x9;curl -sS -o /dev/null &amp;#34;https://www.google.com/ping?sitemap={{ sitemap }}&amp;#34;&#xA;&#x9;curl -sS -o /dev/null &amp;#34;https://www.bing.com/ping?sitemap={{ sitemap }}&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The main differences:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Environment variables: use &lt;code&gt;{{ foo }}&lt;/code&gt; instead of &lt;code&gt;$(FOO)&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Exception: environment variables loaded from &lt;code&gt;.env&lt;/code&gt; (via &lt;code&gt;set dotenv-load&lt;/code&gt;)&#xA;use &lt;code&gt;$FOO&lt;/code&gt; or &lt;code&gt;${FOO}&lt;/code&gt; instead, like POSIX shell variables&lt;/li&gt;&#xA;&lt;li&gt;Use &lt;code&gt;rm -rf&lt;/code&gt; instead of &lt;code&gt;$(RM) -r&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Rules accept parameters. Look at &lt;code&gt;new post&lt;/code&gt; as an example. Example usage:&#xA;&lt;code&gt;just new &amp;quot;advent of code day 8&amp;quot;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Run shell commands within rules with backticks. &lt;code&gt;$(cmd)&lt;/code&gt; does not work.&lt;/li&gt;&#xA;&lt;li&gt;Some handy out-of-the-box functions such as &lt;code&gt;kebabcase()&lt;/code&gt;. No need to&#xA;implement this kind of string manipulation in plain shell script!&lt;/li&gt;&#xA;&lt;li&gt;Documentation comments above rules are recognized. They are displayed as help&#xA;/ usage text when running &lt;code&gt;just -l&lt;/code&gt;. No need for hacky &lt;a href=&#34;https://perrotta.dev/2024/08/self-documented-makefiles/&#34;&gt;self-documented&#xA;&lt;code&gt;Makefile&lt;/code&gt;&lt;/a&gt; setups!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% just -l&#xA;Available recipes:&#xA;    build&#xA;    clean&#xA;    new post # Create a new post. Usage: `just new &amp;#34;advent of code day 8&amp;#34;`&#xA;    ping sitemap=&amp;#34;https://perrotta.dev/sitemap.xml&amp;#34; # Ping Google and Bing about changes in the sitemap&#xA;    watch&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;With a bit of LLM prompting in lieu of Google or Stack Overflow searches.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/just/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Just&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 7
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-7/</link>
      <pubDate>Thu, 12 Dec 2024 23:12:31 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-7/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/7&#34;&gt;Day #7&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Part one: dynamic programming!&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def calibrate_one(test_value, operands):&#xA;&#xA;    @lru_cache(maxsize=None)&#xA;    def dp_calibrate(acc, index):&#xA;        if acc == test_value and index == len(operands):&#xA;            return True&#xA;&#xA;        if acc &amp;gt; test_value or index == len(operands):&#xA;            return False&#xA;&#xA;        return dp_calibrate(acc &amp;#43; operands[index], index &amp;#43; 1) or dp_calibrate(acc * operands[index], index &amp;#43; 1)&#xA;&#xA;    return dp_calibrate(operands[0], 1)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I learned this style from &lt;a href=&#34;https://neetcode.io/&#34;&gt;NeetCode&lt;/a&gt;. An inner function to&#xA;drive the memoization alongside &lt;code&gt;lru_cache&lt;/code&gt;. Beautiful!&lt;/p&gt;&#xA;&lt;p&gt;In my initial solution I passed the whole operands tuple as the second argument.&#xA;Later on I changed it to pass the current index in the tuple, which is simpler.&lt;/p&gt;&#xA;&lt;p&gt;Part two is a natural extension of part one, with an extra operator:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def calibrate_two(test_value, operands):&#xA;&#xA;    @lru_cache(maxsize=None)&#xA;    def dp_calibrate(acc, index):&#xA;        if index == len(operands):&#xA;            return acc == test_value&#xA;&#xA;        if acc &amp;gt; test_value:&#xA;            return False&#xA;&#xA;        return dp_calibrate(acc &amp;#43; operands[index], index &amp;#43; 1) or dp_calibrate(acc * operands[index], index &amp;#43; 1) or dp_calibrate(int(str(acc) &amp;#43; str(operands[index])), index &amp;#43; 1)&#xA;&#xA;    return dp_calibrate(operands[0], 1)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;from functools import lru_cache&#xA;&#xA;def calibrate_one(test_value, operands):&#xA;&#xA;    @lru_cache(maxsize=None)&#xA;    def dp_calibrate(acc, index):&#xA;        if acc == test_value and index == len(operands):&#xA;            return True&#xA;&#xA;        if acc &amp;gt; test_value or index == len(operands):&#xA;            return False&#xA;&#xA;        return dp_calibrate(acc &amp;#43; operands[index], index &amp;#43; 1) or dp_calibrate(acc * operands[index], index &amp;#43; 1)&#xA;&#xA;    return dp_calibrate(operands[0], 1)&#xA;&#xA;def calibrate_two(test_value, operands):&#xA;&#xA;    @lru_cache(maxsize=None)&#xA;    def dp_calibrate(acc, index):&#xA;        if index == len(operands):&#xA;            return acc == test_value&#xA;&#xA;        if acc &amp;gt; test_value:&#xA;            return False&#xA;&#xA;        return dp_calibrate(acc &amp;#43; operands[index], index &amp;#43; 1) or dp_calibrate(acc * operands[index], index &amp;#43; 1) or dp_calibrate(int(str(acc) &amp;#43; str(operands[index])), index &amp;#43; 1)&#xA;&#xA;    return dp_calibrate(operands[0], 1)&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    total_one = total_two = 0&#xA;&#xA;    for line in lines:&#xA;        test_value, operands = line.split(&amp;#39;:&amp;#39;)&#xA;        test_value = int(test_value)&#xA;        operands = [int(x) for x in operands.split()]&#xA;&#xA;        if calibrate_one(test_value, operands):&#xA;            total_one &amp;#43;= test_value&#xA;&#xA;        if calibrate_two(test_value, operands):&#xA;            total_two &amp;#43;= test_value&#xA;&#xA;    # part one&#xA;    print(total_one)&#xA;&#xA;    # part two&#xA;    print(total_two)&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 7&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code: discussion group
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-discussion-group/</link>
      <pubDate>Thu, 12 Dec 2024 19:30:53 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-discussion-group/</guid>
      <description>&lt;p&gt;♠ Assuming you are following this year&amp;rsquo;s advent of code, you are welcome to join&#xA;&lt;a href=&#34;https://t.me/&amp;#43;mtPcW45EuFBjNGMx&#34;&gt;our Telegram discussion group&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-discussion-group/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. It is&#xA;a supergroup, one of its channels is &lt;code&gt;#adventofcode&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a moderated group, and this invitation link will expire within 2&#xA;weeks of the time of this post.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-discussion-group/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code: discussion group&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 11
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-11/</link>
      <pubDate>Thu, 12 Dec 2024 19:15:35 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-11/</guid>
      <description>&lt;p&gt;♠ Link to &lt;a href=&#34;https://adventofcode.com/2024/day/11&#34;&gt;Day #11&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Part one can be done with a simulation.&lt;/p&gt;&#xA;&lt;p&gt;It is very delightful to do it in python: lists are quite flexible, and&#xA;converting from integers to strings and vice-versa is seamless. Counting the&#xA;number of digits of &lt;code&gt;x&lt;/code&gt; is just a matter of &lt;code&gt;len(str(x))&lt;/code&gt;. In C++ it&amp;rsquo;s a bit&#xA;kludgier with &lt;code&gt;std::string(x).size()&lt;/code&gt; and &lt;code&gt;std::stoi(s)&lt;/code&gt;, but then you need to&#xA;remember which header to import&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-2024-day-11/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I thought of using &lt;code&gt;reduce&lt;/code&gt; to do &lt;code&gt;blink(blink(stone))...&lt;/code&gt; and so on:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;print(len(reduce(lambda stone: blink(stone), range(25), stones)))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;nonetheless it&amp;rsquo;s more readable to simply use a plain &lt;code&gt;for-range&lt;/code&gt; loop:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;for _ in range(25):&#xA;    stones = blink(stones)&#xA;print(len(stones))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The secret sauce is in &lt;code&gt;blink&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def blink(stones):&#xA;    stones_next = []&#xA;&#xA;    for stone in stones:&#xA;        s = str(stone)&#xA;&#xA;        if stone == 0:&#xA;            stones_next.append(1)&#xA;&#xA;        elif len(s) % 2 == 0:&#xA;            index = len(s) // 2&#xA;            stones_next.append(int(s[:index]))&#xA;            stones_next.append(int(s[index:]))&#xA;&#xA;        else:&#xA;            stones_next.append(stone * 2024)&#xA;&#xA;    return stones_next&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;For part two we need to be cleverer. In principle the same approach would work,&#xA;however it takes too long to process due to its exponential nature. In my laptop&#xA;I can get up to the 42nd &lt;code&gt;blink&lt;/code&gt; iteration without losing my patience to wait&#xA;even longer.&lt;/p&gt;&#xA;&lt;p&gt;The main observation to account for is that we only care about the length of the&#xA;stone sequence, hence the original task transforms into a simple 2D dynamic&#xA;programming problem.&lt;/p&gt;&#xA;&lt;p&gt;I call:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;print(dp_blink(stones, 75))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Which is defined this way:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def dp_blink(stones, times):&#xA;    from functools import lru_cache&#xA;&#xA;    @lru_cache(maxsize=None)&#xA;    def dp(stone: int, times: int) -&amp;gt; int:&#xA;        if times == 0:&#xA;            return 1&#xA;&#xA;        return sum([dp(stone, times - 1) for stone in blink([stone])])&#xA;&#xA;    return sum([dp(stone, times) for stone in stones])&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The DP consists of the stone, and how many times are left for you to blink at it.&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;def blink(stones):&#xA;    stones_next = []&#xA;&#xA;    for stone in stones:&#xA;        s = str(stone)&#xA;&#xA;        if stone == 0:&#xA;            stones_next.append(1)&#xA;&#xA;        elif len(s) % 2 == 0:&#xA;            index = len(s) // 2&#xA;            stones_next.append(int(s[:index]))&#xA;            stones_next.append(int(s[index:]))&#xA;&#xA;        else:&#xA;            stones_next.append(stone * 2024)&#xA;&#xA;    return stones_next&#xA;&#xA;def dp_blink(stones, times):&#xA;    from functools import lru_cache&#xA;&#xA;    @lru_cache(maxsize=None)&#xA;    def dp(stone: int, times: int) -&amp;gt; int:&#xA;        if times == 0:&#xA;            return 1&#xA;&#xA;        return sum([dp(stone, times - 1) for stone in blink([stone])])&#xA;&#xA;    return sum([dp(stone, times) for stone in stones])&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    stones = [int(stone) for stone in lines[0].split()]&#xA;&#xA;    for _ in range(25):&#xA;        stones = blink(stones)&#xA;&#xA;    # part one&#xA;    print(len(stones))&#xA;&#xA;    # This is very slow, with an exponential complexity runtime.&#xA;    # What did you expect?&#xA;    #&#xA;    # for i in range(50):  # 50 = 75 - 25&#xA;    #     print(i)&#xA;    #     stones = blink(stones)&#xA;&#xA;    # # part two&#xA;    # print(len(stones))&#xA;&#xA;    stones = [int(stone) for stone in lines[0].split()]&#xA;&#xA;    # part two&#xA;    print(dp_blink(stones, 75))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;It&amp;rsquo;s &lt;code&gt;#include &amp;lt;string&amp;gt;&lt;/code&gt;.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-2024-day-11/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 11&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 6
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-6/</link>
      <pubDate>Thu, 12 Dec 2024 15:26:35 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-6/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/6&#34;&gt;Day #6&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Part one is a classic 2D matrix (graph) traversal problem.&lt;/p&gt;&#xA;&lt;p&gt;To store state I created a &lt;code&gt;visited&lt;/code&gt; set with the &lt;code&gt;(x, y)&lt;/code&gt; coordinates.&#xA;Alternatively I could have changed the input inplace, but I didn&amp;rsquo;t want to deal&#xA;with the immutability of python strings, i.e. given:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;l = [&amp;#34;.....&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;you can&amp;rsquo;t simply do &lt;code&gt;l[0][0] = &#39;X&#39;&lt;/code&gt;, because python strings are immutable. We&#xA;could define a new string and assign it to &lt;code&gt;l[0]&lt;/code&gt;, or we could change the input&#xA;to:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;l = [&amp;#39;.&amp;#39;, &amp;#39;.&amp;#39;, &amp;#39;.&amp;#39;, &amp;#39;.&amp;#39;, &amp;#39;.&amp;#39;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;so that replacing characters becomes trivial.&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;def find(lines, c):&#xA;    for i, line in enumerate(lines):&#xA;        if c in line:&#xA;            return i, line.index(c)&#xA;    raise ValueError(f&amp;#39;Could not find {c} in lines&amp;#39;)&#xA;&#xA;def move(pos, dir, lines, visited):&#xA;    dirs_clockwise = ((1, 0), (0, -1), (-1, 0), (0, 1))&#xA;&#xA;    while True:&#xA;        next_pos = pos[0] &amp;#43; dir[0], pos[1] &amp;#43; dir[1]&#xA;&#xA;        if next_pos[0] &amp;lt; 0 or next_pos[0] &amp;gt;= len(lines) or next_pos[1] &amp;lt; 0 or next_pos[1] &amp;gt;= len(lines[0]):&#xA;            break&#xA;&#xA;        if lines[next_pos[0]][next_pos[1]] in &amp;#39;.^&amp;#39;:&#xA;            pos = next_pos&#xA;            visited.add(pos)&#xA;        elif lines[next_pos[0]][next_pos[1]] == &amp;#39;#&amp;#39;:&#xA;            dir = dirs_clockwise[(dirs_clockwise.index(dir) &amp;#43; 1) % 4]&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    pos = find(lines, &amp;#39;^&amp;#39;)&#xA;    dir = (-1, 0)  # up&#xA;&#xA;    visited = set((pos,))&#xA;&#xA;    move(pos, dir, lines, visited)&#xA;&#xA;    # part one&#xA;    print(len(visited))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I did not solve part two yet. I know how to do it, but my initial approach is&#xA;too brute force to my taste. Perhaps I&amp;rsquo;ll come up with something clever later&#xA;on.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 6&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 5
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-5/</link>
      <pubDate>Sun, 08 Dec 2024 23:24:27 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-5/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/5&#34;&gt;Day #5&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;It is a topological sort problem, plain and simple.&lt;/p&gt;&#xA;&lt;p&gt;In part one all we care about is whether certain input sequences are valid,&#xA;within the sort constraints. It&amp;rsquo;s very straightforward to verify that by&#xA;exhaustively checking all constraints (&amp;ldquo;edges&amp;rdquo;):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import sys&#xA;&#xA;def is_correct(update, edges):&#xA;    position = defaultdict(lambda: sys.maxsize, {node: i for (i, node) in enumerate(update)})&#xA;&#xA;    for (first, second) in edges:&#xA;        if first in update and second in update and position[first] &amp;gt; position[second]:&#xA;            return False&#xA;    return True&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;position&lt;/code&gt; is a dictionary representing in which index (position) each element&#xA;occurs. I make use of a &lt;code&gt;defaultdict&lt;/code&gt; with a very large value set by default&#xA;(instead of a vanilla &lt;code&gt;dict&lt;/code&gt;) to avoid the need to explicitly check for element&#xA;presence.&lt;/p&gt;&#xA;&lt;p&gt;In part two we need to perform the actual topological sort. Or&amp;hellip;do we? Doing&#xA;toposort would be the most efficient way to resolve it, however, in this case,&#xA;plain brute force is good enough:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def toposort(update, edges):&#xA;    position = defaultdict(lambda: sys.maxsize, {node: i for (i, node) in enumerate(update)})&#xA;&#xA;    change = True&#xA;    while change:&#xA;        change = False&#xA;        for (first, second) in edges:&#xA;            if first in update and second in update and position[first] &amp;gt;= position[second]:&#xA;                position[first] = position[second] - 1&#xA;                change = True&#xA;&#xA;    return sorted(update, key=lambda x: position[x])&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Once again, we iterate through all the input constraints until we find a&#xA;violation. Whenever we find one, we fix the position of the element in the wrong&#xA;order by updating it to occur before the other element. We repeat this procedure&#xA;until there are no more violations.&lt;/p&gt;&#xA;&lt;p&gt;The full source:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;from collections import defaultdict&#xA;import sys&#xA;&#xA;def is_correct(update, edges):&#xA;    position = defaultdict(lambda: sys.maxsize, {node: i for (i, node) in enumerate(update)})&#xA;&#xA;    for (first, second) in edges:&#xA;        if first in update and second in update and position[first] &amp;gt; position[second]:&#xA;            return False&#xA;    return True&#xA;&#xA;def toposort(update, edges):&#xA;    position = defaultdict(lambda: sys.maxsize, {node: i for (i, node) in enumerate(update)})&#xA;&#xA;    change = True&#xA;    while change:&#xA;        change = False&#xA;        for (first, second) in edges:&#xA;            if first in update and second in update and position[first] &amp;gt;= position[second]:&#xA;                position[first] = position[second] - 1&#xA;                change = True&#xA;&#xA;    return sorted(update, key=lambda x: position[x])&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    edges = []&#xA;    updates = []&#xA;&#xA;    for line in lines:&#xA;        if &amp;#34;|&amp;#34; in line:&#xA;            edges.append(list(map(int, line.split(&amp;#34;|&amp;#34;))))&#xA;        elif len(line) == 0:&#xA;            continue&#xA;        else:&#xA;            updates.append(list(map(int, line.split(&amp;#34;,&amp;#34;))))&#xA;&#xA;    total_one = total_two = 0&#xA;    for update in updates:&#xA;        if is_correct(update, edges):&#xA;            total_one &amp;#43;= update[len(update) // 2]&#xA;        else:&#xA;            sorted_update = toposort(update, edges)&#xA;            total_two &amp;#43;= sorted_update[len(sorted_update) // 2]&#xA;&#xA;    # part one&#xA;    print(total_one)&#xA;&#xA;    # part two&#xA;    print(total_two)&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 5&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 4
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-4/</link>
      <pubDate>Fri, 06 Dec 2024 11:44:39 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-4/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/4&#34;&gt;Day #4&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a pretty typical 2D matrix search problem, or a graph search problem, if&#xA;you will.&lt;/p&gt;&#xA;&lt;p&gt;The problem is naturally unraveled into the following searches:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;horizontally&lt;/li&gt;&#xA;&lt;li&gt;horizontally, reversed&lt;/li&gt;&#xA;&lt;li&gt;vertically&lt;/li&gt;&#xA;&lt;li&gt;vertically, reversed&lt;/li&gt;&#xA;&lt;li&gt;diagonally, all 4 directions (NW, NE, SW, SE)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;It&amp;rsquo;s possible to write a single pair of for loops that addresses the general&#xA;case. The (classic) idea is to think of all 8 compass directions to move along&#xA;the matrix:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;(1, 0)&lt;/li&gt;&#xA;&lt;li&gt;(-1, 0)&lt;/li&gt;&#xA;&lt;li&gt;(0, 1)&lt;/li&gt;&#xA;&lt;li&gt;(0, -1)&lt;/li&gt;&#xA;&lt;li&gt;(1, 1)&lt;/li&gt;&#xA;&lt;li&gt;(-1, -1)&lt;/li&gt;&#xA;&lt;li&gt;(-1, 1)&lt;/li&gt;&#xA;&lt;li&gt;(1, -1)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Within the inner iteration, change &lt;code&gt;x += dx&lt;/code&gt; and &lt;code&gt;y += dy&lt;/code&gt; (or &lt;code&gt;i += di&lt;/code&gt;, &lt;code&gt;j += dj&lt;/code&gt;, naming is hard). I did this many times in C++ though, and I want to write&#xA;elegant Python code.&lt;/p&gt;&#xA;&lt;p&gt;Therefore I came up with the following solution instead, with nested list&#xA;comprehensions:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def search_horizontal(matrix, keyword):&#xA;    return sum((True for row in matrix for i in range(len(row) - len(keyword) &amp;#43; 1) if &amp;#34;&amp;#34;.join(row[i:i &amp;#43; len(keyword)]) in [keyword, keyword[::-1]]))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It follows the same principle as the original intent, however it leverages&#xA;list slices so that we can omit the &lt;code&gt;dx/dy&lt;/code&gt; step.&lt;/p&gt;&#xA;&lt;p&gt;The vertical search is pretty straightforward: it is just a matter of running&#xA;the horizontal search in the transposed matrix (&lt;code&gt;zip(*matrix)&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;I must confess that using &lt;code&gt;zip&lt;/code&gt; to transpose matrices always felt magical and a&#xA;mere coincidence that it just works™. Ruby has a &lt;code&gt;.transpose&lt;/code&gt; method, which is&#xA;more readable.&lt;/p&gt;&#xA;&lt;p&gt;For the diagonal search, I couldn&amp;rsquo;t think of an elegant list comprehension&#xA;manner to address it. Is it even possible to &amp;ldquo;2D slice&amp;rdquo; in Python?&lt;/p&gt;&#xA;&lt;p&gt;After-the-fact I decided to ask ChatGPT, and it is indeed possible, but it&#xA;requires NumPy:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;If a is 2-D, returns the diagonal of a with the given offset, i.e., the&#xA;collection of elements of the form a[i, i+offset]. If a has more than two&#xA;dimensions, then the axes specified by axis1 and axis2 are used to determine&#xA;the 2-D sub-array whose diagonal is returned. The shape of the resulting array&#xA;can be determined by removing axis1 and axis2 and appending an index to the&#xA;right equal to the size of the resulting diagonals.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The method call resembles &lt;code&gt;numpy.array([[1, 2], [3, 4]]).diagonal(offset=1)&lt;/code&gt;,&#xA;perhaps with the aid of &lt;code&gt;.flip()&lt;/code&gt; to account for the other direction.&lt;/p&gt;&#xA;&lt;p&gt;Anyway, my plain diagonal search is:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def search_diagonal(matrix, keyword):&#xA;    rows = len(matrix)&#xA;    cols = len(matrix[0])&#xA;&#xA;    count = 0&#xA;&#xA;    for i in range(rows):&#xA;        for j in range(cols):&#xA;            if i &amp;#43; len(keyword) &amp;lt;= rows and j &amp;#43; len(keyword) &amp;lt;= cols:&#xA;                if &amp;#34;&amp;#34;.join(matrix[i &amp;#43; k][j &amp;#43; k] for k in range(len(keyword))) in [keyword, keyword[::-1]]:&#xA;                    count &amp;#43;= 1&#xA;            if i &amp;#43; len(keyword) &amp;lt;= rows and j - len(keyword) &amp;gt;= -1:&#xA;                if &amp;#34;&amp;#34;.join(matrix[i &amp;#43; k][j - k] for k in range(len(keyword))) in [keyword, keyword[::-1]]:&#xA;                    count &amp;#43;= 1&#xA;&#xA;    return count&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Part two is fundamentally a different problem.&lt;/p&gt;&#xA;&lt;p&gt;One way to address it is to search for all &lt;code&gt;&#39;A&#39;&lt;/code&gt; characters, and then look&#xA;around its &amp;ldquo;edges&amp;rdquo; to see if they contain exactly two &lt;code&gt;&#39;M&#39;&lt;/code&gt; and two &lt;code&gt;&#39;S&#39;&lt;/code&gt;, and&#xA;that they are properly arranged:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def search_double_mas(matrix):&#xA;    rows = len(matrix)&#xA;    cols = len(matrix[0])&#xA;&#xA;    count = 0&#xA;&#xA;    for i in range(1, rows - 1):&#xA;        for j in range(1, cols - 1):&#xA;            if matrix[i][j] != &amp;#39;A&amp;#39;:&#xA;                continue&#xA;&#xA;            # look at a QWERTY keyboard to make sense of these variable names&#xA;            q = matrix[i - 1][j - 1]&#xA;            e = matrix[i - 1][j &amp;#43; 1]&#xA;            z = matrix[i &amp;#43; 1][j - 1]&#xA;            c = matrix[i &amp;#43; 1][j &amp;#43; 1]&#xA;            edges = [q, e, z, c]&#xA;&#xA;            if edges.count(&amp;#39;M&amp;#39;) != 2 or edges.count(&amp;#39;S&amp;#39;) != 2:&#xA;                continue&#xA;&#xA;            if q == e or q == z:&#xA;                count &amp;#43;= 1&#xA;&#xA;    return count&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I couldn&amp;rsquo;t find an opportunity for reuse of the solution from part one.&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;def search_horizontal(matrix, keyword):&#xA;    return sum((True for row in matrix for i in range(len(row) - len(keyword) &amp;#43; 1) if &amp;#34;&amp;#34;.join(row[i:i &amp;#43; len(keyword)]) in [keyword, keyword[::-1]]))&#xA;&#xA;def search_vertical(matrix, keyword):&#xA;    return search_horizontal(zip(*matrix), keyword)&#xA;&#xA;def search_diagonal(matrix, keyword):&#xA;    rows = len(matrix)&#xA;    cols = len(matrix[0])&#xA;&#xA;    count = 0&#xA;&#xA;    for i in range(rows):&#xA;        for j in range(cols):&#xA;            if i &amp;#43; len(keyword) &amp;lt;= rows and j &amp;#43; len(keyword) &amp;lt;= cols:&#xA;                if &amp;#34;&amp;#34;.join(matrix[i &amp;#43; k][j &amp;#43; k] for k in range(len(keyword))) in [keyword, keyword[::-1]]:&#xA;                    count &amp;#43;= 1&#xA;            if i &amp;#43; len(keyword) &amp;lt;= rows and j - len(keyword) &amp;gt;= -1:&#xA;                if &amp;#34;&amp;#34;.join(matrix[i &amp;#43; k][j - k] for k in range(len(keyword))) in [keyword, keyword[::-1]]:&#xA;                    count &amp;#43;= 1&#xA;&#xA;    return count&#xA;&#xA;def search_double_mas(matrix):&#xA;    rows = len(matrix)&#xA;    cols = len(matrix[0])&#xA;&#xA;    count = 0&#xA;&#xA;    for i in range(1, rows - 1):&#xA;        for j in range(1, cols - 1):&#xA;            if matrix[i][j] != &amp;#39;A&amp;#39;:&#xA;                continue&#xA;&#xA;            # look at a QWERTY keyboard to make sense of these variable names&#xA;            q = matrix[i - 1][j - 1]&#xA;            e = matrix[i - 1][j &amp;#43; 1]&#xA;            z = matrix[i &amp;#43; 1][j - 1]&#xA;            c = matrix[i &amp;#43; 1][j &amp;#43; 1]&#xA;            edges = [q, e, z, c]&#xA;&#xA;            if edges.count(&amp;#39;M&amp;#39;) != 2 or edges.count(&amp;#39;S&amp;#39;) != 2:&#xA;                continue&#xA;&#xA;            if q == e or q == z:&#xA;                count &amp;#43;= 1&#xA;&#xA;    return count&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    keyword = &amp;#34;XMAS&amp;#34;&#xA;&#xA;    # [&amp;#39;abcd&amp;#39;, &amp;#39;efgh&amp;#39;, &amp;#39;ijkl&amp;#39;] -&amp;gt; [[&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;, &amp;#39;d&amp;#39;], [&amp;#39;e&amp;#39;, &amp;#39;f&amp;#39;, &amp;#39;g&amp;#39;, &amp;#39;h&amp;#39;], [&amp;#39;i&amp;#39;, &amp;#39;j&amp;#39;, &amp;#39;k&amp;#39;, &amp;#39;l&amp;#39;]]&#xA;    matrix = [list(line) for line in lines]&#xA;&#xA;    # part one&#xA;    print(search_horizontal(matrix, keyword) &amp;#43; search_vertical(matrix, keyword) &amp;#43; search_diagonal(matrix, keyword))&#xA;&#xA;    # part two&#xA;    print(search_double_mas(matrix))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 4&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 3
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-3/</link>
      <pubDate>Tue, 03 Dec 2024 16:41:23 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-3/</guid>
      <description>&lt;p&gt;♠ Link to &lt;a href=&#34;https://adventofcode.com/2024/day/3&#34;&gt;Day #3&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a pretty typical regex problem.&#xA;To choose not to use regex is to endeavour in pain.&lt;/p&gt;&#xA;&lt;p&gt;The regex for part one to extract all occurrences of &lt;code&gt;mul&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;r&amp;#39;mul\(\d&amp;#43;,\d&amp;#43;\)&amp;#39;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Note that with &lt;code&gt;r&lt;/code&gt; there is no need to escape the backslashes in Python.&lt;/p&gt;&#xA;&lt;p&gt;Later on I extract the numbers with &lt;code&gt;r&#39;\d+&#39;&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If we really wanted we could do everything with a single regex by using&#xA;capturing groups, however it would become less readable.&lt;/p&gt;&#xA;&lt;p&gt;Once the numbers are captured, it&amp;rsquo;s just a matter of accumulating their product.&lt;/p&gt;&#xA;&lt;p&gt;I craft and test my regex with the support of &lt;a href=&#34;https://regex101.com/&#34;&gt;https://regex101.com/&lt;/a&gt; and then&#xA;follow up with the Python interpreter in my laptop.&lt;/p&gt;&#xA;&lt;p&gt;Part two adds two more operators, which we can easily account for with an or&#xA;(&lt;code&gt;|&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import re&#xA;import sys&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    prod = prod_two = 0&#xA;&#xA;    for memory in lines:&#xA;        ops = re.findall(r&amp;#39;mul\(\d&amp;#43;,\d&amp;#43;\)&amp;#39;, memory)&#xA;&#xA;        for op in ops:&#xA;            (f1, f2) = map(int, re.findall(r&amp;#39;\d&amp;#43;&amp;#39;, op))&#xA;            prod &amp;#43;= f1 * f2&#xA;&#xA;    # part one&#xA;    print(prod)&#xA;&#xA;    enabled = True&#xA;    for memory in lines:&#xA;        ops = re.findall(r&amp;#34;mul\(\d&amp;#43;,\d&amp;#43;\)|do\(\)|don&amp;#39;t\(\)&amp;#34;, memory)&#xA;&#xA;        for op in ops:&#xA;            if &amp;#34;don&amp;#39;t&amp;#34; in op:&#xA;                enabled = False&#xA;            elif &amp;#34;do&amp;#34; in op:&#xA;                enabled = True&#xA;            elif &amp;#39;mul&amp;#39; in op:&#xA;                (f1, f2) = map(int, re.findall(r&amp;#39;\d&amp;#43;&amp;#39;, op))&#xA;&#xA;                if enabled:&#xA;                    prod_two &amp;#43;= f1 * f2&#xA;&#xA;    # part two&#xA;    print(prod_two)&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I intended to use &lt;a href=&#34;https://docs.python.org/3/whatsnew/3.10.html&#34;&gt;&lt;code&gt;match&lt;/code&gt;&lt;/a&gt; merely&#xA;for style points however it&amp;rsquo;s only available from Python 3.10+, thus I sticked&#xA;with a mere &lt;code&gt;if-elif&lt;/code&gt; construct.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 3&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 2
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-2/</link>
      <pubDate>Tue, 03 Dec 2024 01:15:00 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-2/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/2&#34;&gt;Day #2&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;The first part is straightforward. It felt right to use &lt;a href=&#34;https://docs.python.org/3/library/itertools.html#itertools.pairwise&#34;&gt;&lt;code&gt;pairwise&lt;/code&gt;&lt;/a&gt; to compute the differences between each adjacent pair:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;diffs = [(b - a) for (a,b) in pairwise(map(int, line.split(&amp;#39; &amp;#39;)))]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then we combine it with &lt;code&gt;all&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def is_safe(diffs):&#xA;    return all(1 &amp;lt;= n &amp;lt;= 3 for n in diffs) or all(-3 &amp;lt;= n &amp;lt;= -1 for n in diffs)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Note that it is necessary to use two &lt;code&gt;all&lt;/code&gt; expressions. It feels tempting to do:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;all(1 &amp;lt;= n &amp;lt;= 3 or -3 &amp;lt;= n &amp;lt;= -1 for n in diffs)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;however that&amp;rsquo;s incorrect. For example: &lt;code&gt;diffs = [1, -1, 1, -1]&lt;/code&gt; with an input&#xA;such as &lt;code&gt;[1, 2, 1, 2]&lt;/code&gt; would pass the test even though it shouldn&amp;rsquo;t.&lt;/p&gt;&#xA;&lt;p&gt;It also feels tempting to use &lt;code&gt;abs()&lt;/code&gt; but then an additional check would be&#xA;necessary to ensure the diffs are either all positive or all negative.&lt;/p&gt;&#xA;&lt;p&gt;The second part was trickier.&lt;/p&gt;&#xA;&lt;p&gt;Initially I was doing:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;list(1 &amp;lt;= n &amp;lt;= 3 for n in diffs).count(False) &amp;lt;= 1 or list(-3 &amp;lt;= n &amp;lt;= -1 for n in diffs).count(False) &amp;lt;= 1&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;but then I realized I misunderstood the problem.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;1 2 7 8 9&lt;/code&gt; line, whose diff is &lt;code&gt;[1, 5, 1, 1]&lt;/code&gt;, illustrates it well: in&#xA;principle it would pass the test by dropping &amp;ldquo;5&amp;rdquo; from the diff. However, that&#xA;cannot be correct, because &lt;code&gt;2 -&amp;gt; 8&lt;/code&gt; is too big of a jump.&lt;/p&gt;&#xA;&lt;p&gt;The brute force way is to drop elements one by one, splitting the original list&#xA;into two, and then checking &lt;code&gt;is_safe&lt;/code&gt; in the merged sublists. That would&#xA;require computing &lt;code&gt;diffs&lt;/code&gt; every time, which would yield an &lt;code&gt;O(n^2)&lt;/code&gt; solution.&lt;/p&gt;&#xA;&lt;p&gt;We can do better by pre-computing &lt;code&gt;diffs&lt;/code&gt; only once, and then adding a bit of&#xA;manipulation to reconstruct what the merged diffs would be. The end goal is to&#xA;compute this:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python3&#34;&gt;is_safe(diffs[:i-1] &amp;#43; [l[i&amp;#43;1] - l[i-1]] &amp;#43; diffs[i&amp;#43;1:]):&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;i.e. the left part of &lt;code&gt;diffs&lt;/code&gt;, the right part of &lt;code&gt;diffs&lt;/code&gt;, and a rolling diff&#xA;element in the middle.&lt;/p&gt;&#xA;&lt;p&gt;The full solution:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;from itertools import pairwise&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    safe = 0&#xA;    safe_damp = 0&#xA;&#xA;    def is_safe(diffs):&#xA;        return all(1 &amp;lt;= n &amp;lt;= 3 for n in diffs) or all(-3 &amp;lt;= n &amp;lt;= -1 for n in diffs)&#xA;&#xA;    for line in lines:&#xA;        l = list(map(int, line.split(&amp;#39; &amp;#39;)))&#xA;        diffs = [(b - a) for (a,b) in pairwise(l)]&#xA;&#xA;        is_this_safe = is_safe(diffs)&#xA;        if is_this_safe:&#xA;            safe &amp;#43;= 1&#xA;            safe_damp &amp;#43;= 1&#xA;            continue&#xA;&#xA;        for i in range(len(l)):&#xA;            if i == 0:&#xA;                if is_safe(diffs[1:]):&#xA;                    safe_damp &amp;#43;= 1&#xA;                    break&#xA;            elif i == len(l) - 1:&#xA;                if is_safe(diffs[:-1]):&#xA;                    safe_damp &amp;#43;= 1&#xA;                    break&#xA;            else:&#xA;                if is_safe(diffs[:i-1] &amp;#43; [l[i&amp;#43;1] - l[i-1]] &amp;#43; diffs[i&amp;#43;1:]):&#xA;                    safe_damp &amp;#43;= 1&#xA;                    break&#xA;&#xA;    # part one&#xA;    print(safe)&#xA;&#xA;    # part two&#xA;    print(safe_damp)&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A few notes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;there&amp;rsquo;s no need for &lt;code&gt;pairwise&lt;/code&gt;; a plain &lt;code&gt;for-range&lt;/code&gt; loop would have done the&#xA;job just fine; &lt;code&gt;pairwise&lt;/code&gt; is stylish though&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;1 &amp;lt;= n &amp;lt;= 3&lt;/code&gt; is syntactic sugar for &lt;code&gt;1 &amp;lt;= n and n &amp;lt;= 3&lt;/code&gt;. Python is sweet.&lt;/li&gt;&#xA;&lt;li&gt;part two could become a bit more elegant by introducing another helper&#xA;function&lt;/li&gt;&#xA;&lt;li&gt;naming is hard&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;pairwise&lt;/code&gt; is only available from Python 3.10+. macOS 15 (Sequoia) ships with&#xA;Python 3.9. Oh well&amp;hellip;I needed to use the Python binary from homebrew.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 2&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2024: Day 1
      </title>
      <link>https://perrotta.dev/2024/12/advent-of-code-2024-day-1/</link>
      <pubDate>Sun, 01 Dec 2024 22:29:19 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2024/12/advent-of-code-2024-day-1/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2024/day/1&#34;&gt;Day #1&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;This is just a warm-up.&lt;/p&gt;&#xA;&lt;p&gt;Given two lists of integers, iterate over them and sum the absolute difference&#xA;between each pair. &lt;code&gt;zip&lt;/code&gt; + &lt;code&gt;sum&lt;/code&gt; is the perfect pair&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-2024-day-1/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; for the job.&lt;/p&gt;&#xA;&lt;p&gt;Part two: iterate over the left list whilst accumulating how often the element&#xA;appears in the right list. &amp;ldquo;How often&amp;rdquo; has, almost always, the smell of a&#xA;&lt;a href=&#34;https://docs.python.org/3/library/collections.html#collections.Counter&#34;&gt;&lt;code&gt;Counter&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The full solution&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-2024-day-1/#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;from collections import Counter&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    left = []&#xA;    right = []&#xA;&#xA;    for line in lines:&#xA;        l, r = map(int, line.split())&#xA;        left.append(l)&#xA;        right.append(r)&#xA;&#xA;    left.sort()&#xA;    right.sort()&#xA;&#xA;    # part one&#xA;    print(sum(abs(l - r) for (l, r) in zip(left, right)))&#xA;&#xA;    freqs = Counter(right)&#xA;&#xA;    # part two&#xA;    print(sum(l * freqs[l] for l in left))&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=3WpdCZC9q6w&#34;&gt;I&amp;rsquo;m not sure I like it, And I&amp;rsquo;m so tired of&#xA;fighting&lt;/a&gt;&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-2024-day-1/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;The git repository is ever-evolving and the source of truth, whereas the&#xA;blog post is a snapshot. I&amp;rsquo;ll experiment with cross-posting solutions here&#xA;even though it duplicates the repository ones.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/advent-of-code-2024-day-1/#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2024: Day 1&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2023: Day 1
      </title>
      <link>https://perrotta.dev/2023/12/advent-of-code-2023-day-1/</link>
      <pubDate>Mon, 04 Dec 2023 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2023/12/advent-of-code-2023-day-1/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2023/day/1&#34;&gt;Day #1&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;The first part is straightforward: extract the first and last digit from each&#xA;line and sum them.&lt;/p&gt;&#xA;&lt;p&gt;Part two gets trickier: we need to handle spelled-out digits like &amp;ldquo;one&amp;rdquo;, &amp;ldquo;two&amp;rdquo;,&#xA;etc. The naive approach of replacing spellings with digits fails for overlapping&#xA;cases like &amp;ldquo;eightwothree&amp;rdquo; which should yield 83, not 23.&lt;/p&gt;&#xA;&lt;p&gt;The solution: find the leftmost and rightmost match among all digit spellings&#xA;and numeric digits, then combine them.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;&#xA;def get_calibration_value(line: str) -&amp;gt; int:&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    Extract the first and the last digit from the string, and return a number&#xA;    composed by them, in that order.&#xA;    &amp;#39;1abc2&amp;#39; -&amp;gt; 12&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    digits = [c for c in line if c.isdigit()]&#xA;    return int(digits[0] &amp;#43; digits[-1])&#xA;&#xA;&#xA;SPELLINGS = {&#xA;    # &amp;#39;zero&amp;#39;: &amp;#39;0&amp;#39;,  # not in the problem statement&#xA;    &amp;#39;one&amp;#39;: &amp;#39;1&amp;#39;,&#xA;    &amp;#39;two&amp;#39;: &amp;#39;2&amp;#39;,&#xA;    &amp;#39;three&amp;#39;: &amp;#39;3&amp;#39;,&#xA;    &amp;#39;four&amp;#39;: &amp;#39;4&amp;#39;,&#xA;    &amp;#39;five&amp;#39;: &amp;#39;5&amp;#39;,&#xA;    &amp;#39;six&amp;#39;: &amp;#39;6&amp;#39;,&#xA;    &amp;#39;seven&amp;#39;: &amp;#39;7&amp;#39;,&#xA;    &amp;#39;eight&amp;#39;: &amp;#39;8&amp;#39;,&#xA;    &amp;#39;nine&amp;#39;: &amp;#39;9&amp;#39;,&#xA;}&#xA;&#xA;&#xA;# This attempt is incorrect because of the following test case:&#xA;#   eightwothree -&amp;gt; eigh23 -&amp;gt; 23&#xA;# Whereas it should have been 83.&#xA;def get_calibration_value_with_spellings_attempt_1(line: str) -&amp;gt; int:&#xA;    for spelling, digit in SPELLINGS.items():&#xA;        line = line.replace(spelling, digit)&#xA;&#xA;    return get_calibration_value(line)&#xA;&#xA;&#xA;def get_calibration_value_with_spellings(line: str) -&amp;gt; int:&#xA;    targets = set(list(SPELLINGS.keys()) &amp;#43; list(SPELLINGS.values()))&#xA;&#xA;    # from the left&#xA;    indices = {}&#xA;    for target in targets:&#xA;        index = line.find(target)&#xA;        if index != -1:&#xA;            indices[target] = index&#xA;&#xA;    [target_min, _] = min(list(indices.items()), key=lambda x: x[1])&#xA;&#xA;    # from the right&#xA;    indices = {}&#xA;    for target in targets:&#xA;        index = line.rfind(target)&#xA;        if index != -1:&#xA;            indices[target] = index&#xA;&#xA;    [target_max, _] = max(list(indices.items()), key=lambda x: x[1])&#xA;&#xA;    if target_min in SPELLINGS:&#xA;        target_min = SPELLINGS[target_min]&#xA;&#xA;    if target_max in SPELLINGS:&#xA;        target_max = SPELLINGS[target_max]&#xA;&#xA;    return int(target_min &amp;#43; target_max)&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    # Part I&#xA;    print(sum([get_calibration_value(line) for line in lines]))&#xA;&#xA;    # Part II&#xA;    print(sum([get_calibration_value_with_spellings(line) for line in lines]))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2023: Day 1&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 10
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-10/</link>
      <pubDate>Mon, 12 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-10/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/10&#34;&gt;Day #10&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Calculate signal strength and render CRT output.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    X = 1&#xA;    cycle = 1&#xA;    cycle_to_X = {cycle: X}&#xA;&#xA;    for line in lines:&#xA;        if line == &amp;#39;noop&amp;#39;:&#xA;            cycle &amp;#43;= 1&#xA;        else:&#xA;            increment = int(line.split(&amp;#39; &amp;#39;)[1])&#xA;            X &amp;#43;= increment&#xA;            cycle &amp;#43;= 2&#xA;        cycle_to_X[cycle] = X&#xA;&#xA;    strength = 0&#xA;&#xA;    for multiple in range(20, max(cycle_to_X.keys()), 40):&#xA;        if multiple in cycle_to_X:&#xA;            strength &amp;#43;= multiple * cycle_to_X[multiple]&#xA;        else:&#xA;            predecessor = max(&#xA;                [key for key in cycle_to_X.keys() if key &amp;lt; multiple])&#xA;            strength &amp;#43;= multiple * cycle_to_X[predecessor]&#xA;&#xA;    # Part 1&#xA;    print(strength)&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 10&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 9
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-9/</link>
      <pubDate>Mon, 12 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-9/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/9&#34;&gt;Day #9&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Simulate rope physics with head and tail.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;DIRECTIONS = {&#xA;    &amp;#39;L&amp;#39;: (-1, 0),  # left&#xA;    &amp;#39;R&amp;#39;: (&amp;#43;1, 0),  # right&#xA;    &amp;#39;D&amp;#39;: (0, -1),  # down&#xA;    &amp;#39;U&amp;#39;: (0, &amp;#43;1),  # up&#xA;}&#xA;&#xA;&#xA;def execute_move(H, T, direction, num_moves, visited):&#xA;    for _ in range(num_moves):&#xA;        # overlapping: only move head&#xA;        if H == T:&#xA;            H = (H[0] &amp;#43; DIRECTIONS[direction][0],&#xA;                 H[1] &amp;#43; DIRECTIONS[direction][1])&#xA;        # next to each other in a &amp;#39;&amp;#43;&amp;#39; fashion: move T only if H moves in same direction&#xA;        elif abs(H[0] - T[0]) &amp;#43; abs(H[1] - T[1]) == 1:&#xA;            H = (H[0] &amp;#43; DIRECTIONS[direction][0],&#xA;                 H[1] &amp;#43; DIRECTIONS[direction][1])&#xA;            if abs(H[0] - T[0]) == 2 or abs(H[1] - T[1]) == 2:&#xA;                T = (T[0] &amp;#43; DIRECTIONS[direction][0],&#xA;                     T[1] &amp;#43; DIRECTIONS[direction][1])&#xA;                visited.add(T)&#xA;        # next to each other in an &amp;#39;x&amp;#39; fashion: move T only if H moves farther away&#xA;        else:&#xA;            H_prev = H&#xA;            H = (H[0] &amp;#43; DIRECTIONS[direction][0],&#xA;                 H[1] &amp;#43; DIRECTIONS[direction][1])&#xA;            if (abs(H[0] - T[0]) &amp;#43; abs(H[1] - T[1])) == 3:&#xA;                T = H_prev&#xA;                visited.add(T)&#xA;&#xA;    return H, T, visited&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    # Initial position of Head and Tail.&#xA;    H = T = (0, 0)&#xA;&#xA;    # Tuple with (x, y) coordinates, assume (0, 0) is the starting point.&#xA;    visited = {(0, 0)}&#xA;&#xA;    for line in lines:&#xA;        direction, num_moves = line.split(&amp;#39; &amp;#39;)&#xA;        H, T, visited = execute_move(H, T, direction, int(num_moves), visited)&#xA;&#xA;    # Part 1&#xA;    print(len(visited))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 9&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 8
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-8/</link>
      <pubDate>Sun, 11 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-8/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/8&#34;&gt;Day #8&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Count visible trees and find best scenic score.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import itertools&#xA;import sys&#xA;&#xA;DIRECTIONS = [&#xA;    [-1, 0],  # left&#xA;    [&amp;#43;1, 0],  # right&#xA;    [0, -1],  # down&#xA;    [0, &amp;#43;1],  # up&#xA;]&#xA;&#xA;&#xA;def is_visible(lines, x, y, is_scenic):&#xA;    this_tree = lines[y][x]&#xA;    scenic = 1&#xA;&#xA;    for direction in DIRECTIONS:&#xA;        visible = True&#xA;&#xA;        step = 1&#xA;        while True:&#xA;            next_x = x &amp;#43; step * direction[0]&#xA;            next_y = y &amp;#43; step * direction[1]&#xA;&#xA;            if 0 &amp;lt;= next_x &amp;lt; len(lines[0]) and 0 &amp;lt;= next_y &amp;lt; len(lines):&#xA;                next_tree = lines[next_y][next_x]&#xA;                if next_tree &amp;gt;= this_tree:&#xA;                    visible = False&#xA;                    break&#xA;                step &amp;#43;= 1&#xA;            else:&#xA;                step -= 1&#xA;                break&#xA;&#xA;        scenic *= step&#xA;&#xA;        if visible and not is_scenic:&#xA;            return visible&#xA;&#xA;    return scenic if is_scenic else visible&#xA;&#xA;&#xA;def compute_inner_visible_trees(lines, *, is_scenic):&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    Cartesian product: [y][x]&#xA;    0 ---&amp;gt; x&#xA;    |&#xA;    |&#xA;  y v&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    if is_scenic:&#xA;        return max(int(is_visible(lines, x, y, is_scenic)) for (x, y) in itertools.product(range(1, len(lines[0]) - 1), range(1, len(lines) - 1)))&#xA;    else:&#xA;        return sum(int(is_visible(lines, x, y, is_scenic)) for (x, y) in itertools.product(range(1, len(lines[0]) - 1), range(1, len(lines) - 1)))&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    outer_visible_trees = 2 * (len(lines) &amp;#43; len(lines[0])) - 4&#xA;&#xA;    # Part 1&#xA;    print(outer_visible_trees &amp;#43; compute_inner_visible_trees(lines, is_scenic=False))&#xA;&#xA;    # Part 2&#xA;    print(compute_inner_visible_trees(lines, is_scenic=True))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 8&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 7
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-7/</link>
      <pubDate>Thu, 08 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-7/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/7&#34;&gt;Day #7&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Find small directories and directory to delete for update.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;from collections import defaultdict&#xA;import sys&#xA;&#xA;&#xA;def exec_cd(directory, pwd):&#xA;    if directory == &amp;#39;..&amp;#39;:&#xA;        pwd = &amp;#39;/&amp;#39;.join(pwd.split(&amp;#39;/&amp;#39;)[:-2]) &amp;#43; &amp;#39;/&amp;#39;&#xA;    elif directory == &amp;#39;/&amp;#39;:&#xA;        pwd = &amp;#39;/&amp;#39;&#xA;    else:&#xA;        pwd &amp;#43;= directory &amp;#43; &amp;#39;/&amp;#39;&#xA;    return pwd&#xA;&#xA;&#xA;def parse_line(line, FILE_TO_SIZE, pwd):&#xA;    if line.startswith(&amp;#39;$ cd &amp;#39;):&#xA;        dir = line.split(&amp;#39;$ cd &amp;#39;)[1]&#xA;        pwd = exec_cd(dir, pwd)&#xA;    elif line.startswith(&amp;#39;$ ls&amp;#39;):&#xA;        pass&#xA;    elif line.startswith(&amp;#39;dir &amp;#39;):&#xA;        dir = pwd &amp;#43; line.split(&amp;#39;dir &amp;#39;)[1]&#xA;    else:&#xA;        size, file_basename = line.split(&amp;#39; &amp;#39;)&#xA;        file = pwd &amp;#43; file_basename&#xA;        FILE_TO_SIZE[file] = int(size)&#xA;    return pwd&#xA;&#xA;&#xA;def parse_input(lines, *, FILE_TO_SIZE, pwd):&#xA;    for line in lines:&#xA;        pwd = parse_line(line, FILE_TO_SIZE, pwd)&#xA;    return FILE_TO_SIZE&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    FILE_TO_SIZE = parse_input(lines, FILE_TO_SIZE={}, pwd=&amp;#39;/&amp;#39;)&#xA;    DIRECTORY_TO_SIZE = defaultdict(int)&#xA;&#xA;    for file, size in FILE_TO_SIZE.items():&#xA;        components = file.split(&amp;#39;/&amp;#39;)[:-1]&#xA;        for i in range(1, len(components) &amp;#43; 1):&#xA;            directory = &amp;#39;/&amp;#39;.join(components[:i])&#xA;            DIRECTORY_TO_SIZE[directory] &amp;#43;= FILE_TO_SIZE[file]&#xA;&#xA;    # Minor fixes for &amp;#39;/&amp;#39; canonicalization&#xA;    DIRECTORY_TO_SIZE[&amp;#39;/&amp;#39;] = DIRECTORY_TO_SIZE[&amp;#39;&amp;#39;]&#xA;    del DIRECTORY_TO_SIZE[&amp;#39;&amp;#39;]&#xA;&#xA;    # Part 1&#xA;    print(sum([value for value in DIRECTORY_TO_SIZE.values() if value &amp;lt;= 100000]))&#xA;&#xA;    # Part 2&#xA;    TOTAL_DISK = 70000000&#xA;    USED_DISK = DIRECTORY_TO_SIZE[&amp;#39;/&amp;#39;]&#xA;    AVAILABLE_DISK = TOTAL_DISK - USED_DISK&#xA;&#xA;    print(next(value for value in sorted(DIRECTORY_TO_SIZE.values())&#xA;          if (AVAILABLE_DISK &amp;#43; value) &amp;gt;= 30000000))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 7&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 6
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-6/</link>
      <pubDate>Wed, 07 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-6/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/6&#34;&gt;Day #6&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Find start-of-packet and start-of-message markers in data stream.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;from collections import defaultdict&#xA;import sys&#xA;&#xA;&#xA;def all_different(window):&#xA;    hash = defaultdict(int)&#xA;    for el in window:&#xA;        hash[el] &amp;#43;= 1&#xA;    return not any(map(lambda x: x &amp;gt; 1, hash.values()))&#xA;&#xA;&#xA;def find_marker(buffer, size):&#xA;    for i in range(len(buffer) - (size - 1)):&#xA;        window = buffer[i:i &amp;#43; size]&#xA;        if (all_different(window)):&#xA;            return i &amp;#43; size&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    buffer = lines[0]&#xA;&#xA;    # Part 1&#xA;    print(find_marker(buffer, 4))&#xA;&#xA;    # Part 2&#xA;    print(find_marker(buffer, 14))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 6&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 5
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-5/</link>
      <pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-5/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/5&#34;&gt;Day #5&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Rearrange crate stacks. Part two moves crates in order rather than one by one.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import itertools&#xA;import sys&#xA;from copy import deepcopy&#xA;&#xA;&#xA;def parse_input(crates_unparsed):&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    Returns a dictionary in the following form:&#xA;&#xA;    {&#xA;      1: &amp;#39;ZN&amp;#39;,&#xA;      2: &amp;#39;MCD&amp;#39;,&#xA;      3: &amp;#39;P&amp;#39;,&#xA;    }&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;&#xA;    crates = {}&#xA;&#xA;    num_stacks = (len(crates_unparsed[0]) &amp;#43; 1) // 4&#xA;    max_height = len(crates_unparsed) - 1&#xA;&#xA;    for i_stack in range(1, num_stacks &amp;#43; 1):&#xA;        stack_xaxis = 4 * (i_stack - 1) &amp;#43; 1&#xA;&#xA;        # List comprehension version, not super readable:&#xA;        # crates[i_stack] = &amp;#39;&amp;#39;.join(list(filter(lambda x: x != &amp;#39; &amp;#39;, [crates_unparsed[max_height - i][stack_xaxis]&#xA;        #                                                            for i in range(1, max_height &amp;#43; 1)])))&#xA;&#xA;        crates[i_stack] = &amp;#39;&amp;#39;&#xA;        for i in range(1, max_height &amp;#43; 1):&#xA;            crate = crates_unparsed[max_height - i][stack_xaxis]&#xA;            if crate != &amp;#39; &amp;#39;:&#xA;                crates[i_stack] &amp;#43;= crate&#xA;&#xA;    return crates&#xA;&#xA;&#xA;def move_crates(moves_unparsed, crates, *, reverse):&#xA;    for move_unparsed in moves_unparsed:&#xA;        _, quantity, _, src, _, dst = move_unparsed.split(&amp;#39; &amp;#39;)&#xA;        quantity, src, dst = int(quantity), int(src), int(dst)&#xA;        move_crate(crates, quantity, src, dst, reverse)&#xA;    return crates&#xA;&#xA;&#xA;def move_crate(crates, quantity, src, dst, reverse):&#xA;    if reverse:&#xA;        crates[dst] &amp;#43;= crates[src][(-1) * quantity:][::-1]&#xA;    else:&#xA;        crates[dst] &amp;#43;= crates[src][(-1) * quantity:]&#xA;    crates[src] = crates[src][:(-1) * quantity]&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    crates_unparsed, moves_unparsed = [list(group) for key, group in itertools.groupby(&#xA;        lines, lambda a: a == &amp;#34;&amp;#34;) if not key]&#xA;&#xA;    crates = parse_input(crates_unparsed)&#xA;&#xA;    # Part 1&#xA;    crates_part1 = move_crates(moves_unparsed, deepcopy(crates), reverse=True)&#xA;    print(&amp;#39;&amp;#39;.join([value[-1] for value in crates_part1.values()]))&#xA;&#xA;    # Part 2&#xA;    crates_part2 = move_crates(moves_unparsed, deepcopy(crates), reverse=False)&#xA;    print(&amp;#39;&amp;#39;.join([value[-1] for value in crates_part2.values()]))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 5&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 4
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-4/</link>
      <pubDate>Mon, 05 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-4/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/4&#34;&gt;Day #4&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Find overlapping cleaning assignment pairs.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;&#xA;def eitherContains(e1, e2):&#xA;    if e1[0] &amp;gt;= e2[0] and e1[1] &amp;lt;= e2[1]:&#xA;        return 1&#xA;    elif e2[0] &amp;gt;= e1[0] and e2[1] &amp;lt;= e1[1]:&#xA;        return 1&#xA;    else:&#xA;        return 0&#xA;&#xA;&#xA;def anyOverlap(e1, e2):&#xA;    return int((e1[1] &amp;gt;= e2[0]) and (e1[0] &amp;lt;= e2[1]))&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    totalEitherContains = 0&#xA;    totalAnyOverlap = 0&#xA;&#xA;    for line in lines:&#xA;        # [[&amp;#39;2&amp;#39;, &amp;#39;4&amp;#39;], [&amp;#39;6&amp;#39;, &amp;#39;8&amp;#39;]]&#xA;        [e1, e2] = [el.split(&amp;#39;-&amp;#39;) for el in line.split(&amp;#39;,&amp;#39;)]&#xA;        # [2, 4], [6, 8]&#xA;        e1, e2 = list(map(int, e1)), list(map(int, e2))&#xA;&#xA;        totalEitherContains &amp;#43;= eitherContains(e1, e2)&#xA;        totalAnyOverlap &amp;#43;= anyOverlap(e1, e2)&#xA;&#xA;    # Part 1&#xA;    print(totalEitherContains)&#xA;&#xA;    # Part 2&#xA;    print(totalAnyOverlap)&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 4&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 2
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-2/</link>
      <pubDate>Sat, 03 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-2/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/2&#34;&gt;Day #2&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Rock paper scissors strategy. Part two uses win/draw/lose outcomes.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;MOVE_SCORE = {&#xA;    # theirs&#xA;    &amp;#39;A&amp;#39;: 1,  # rock&#xA;    &amp;#39;B&amp;#39;: 2,  # paper&#xA;    &amp;#39;C&amp;#39;: 3,  # scissors&#xA;&#xA;    # mine&#xA;    &amp;#39;X&amp;#39;: 1,  # rock&#xA;    &amp;#39;Y&amp;#39;: 2,  # paper&#xA;    &amp;#39;Z&amp;#39;: 3,  # scissors&#xA;}&#xA;&#xA;&#xA;def battle(theirs, mine):&#xA;    if (theirs, mine) in [(&amp;#39;A&amp;#39;, &amp;#39;X&amp;#39;), (&amp;#39;B&amp;#39;, &amp;#39;Y&amp;#39;), (&amp;#39;C&amp;#39;, &amp;#39;Z&amp;#39;)]:&#xA;        return 3  # draw&#xA;    elif (theirs, mine) in [(&amp;#39;A&amp;#39;, &amp;#39;Z&amp;#39;), (&amp;#39;B&amp;#39;, &amp;#39;X&amp;#39;), (&amp;#39;C&amp;#39;, &amp;#39;Y&amp;#39;)]:&#xA;        return 0  # defeat&#xA;    else:&#xA;        return 6  # victory&#xA;&#xA;&#xA;def strategy(theirs, mine):&#xA;    if mine == &amp;#39;Y&amp;#39;:  # draw&#xA;        return chr(ord(theirs) &amp;#43; (ord(&amp;#39;X&amp;#39;) - ord(&amp;#39;A&amp;#39;)))&#xA;    elif mine == &amp;#39;X&amp;#39;:  # lose&#xA;        return {&amp;#39;A&amp;#39;: &amp;#39;Z&amp;#39;, &amp;#39;B&amp;#39;: &amp;#39;X&amp;#39;, &amp;#39;C&amp;#39;: &amp;#39;Y&amp;#39;}[theirs]&#xA;    else:  # win&#xA;        assert mine == &amp;#39;Z&amp;#39;&#xA;        return {&amp;#39;A&amp;#39;: &amp;#39;Y&amp;#39;, &amp;#39;B&amp;#39;: &amp;#39;Z&amp;#39;, &amp;#39;C&amp;#39;: &amp;#39;X&amp;#39;}[theirs]&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    score1, score2 = 0, 0&#xA;&#xA;    for line in lines:&#xA;        theirs, mine = line.split(&amp;#39; &amp;#39;)&#xA;&#xA;        score1 &amp;#43;= MOVE_SCORE[mine] &amp;#43; battle(theirs, mine)&#xA;&#xA;        mine = strategy(theirs, mine)&#xA;        score2 &amp;#43;= MOVE_SCORE[mine] &amp;#43; battle(theirs, mine)&#xA;&#xA;    print(score1)&#xA;    print(score2)&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 2&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 3
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-3/</link>
      <pubDate>Sat, 03 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-3/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/3&#34;&gt;Day #3&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Find misplaced items in rucksacks. Part two finds common items across three rucksacks.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;&#xA;def priority(item):&#xA;    if item.islower():&#xA;        return ord(item) - ord(&amp;#39;a&amp;#39;) &amp;#43; 1&#xA;    else:&#xA;        assert item.isupper()&#xA;        return ord(item) - ord(&amp;#39;A&amp;#39;) &amp;#43; 27&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    total_priority = 0&#xA;&#xA;    # Part 1&#xA;    for line in lines:&#xA;        c1 = line[:len(line)//2]&#xA;        c2 = line[len(line)//2:]&#xA;        item = next(iter(set(c1).intersection(c2)))&#xA;        total_priority &amp;#43;= priority(item)&#xA;&#xA;    print(total_priority)&#xA;&#xA;    # Part 2&#xA;    print(sum([priority(next(iter(set(line1).intersection(line2).intersection(line3))))&#xA;               for (line1, line2, line3) in zip(lines[::3], lines[1::3], lines[2::3])]))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 3&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2022: Day 1
      </title>
      <link>https://perrotta.dev/2022/12/advent-of-code-2022-day-1/</link>
      <pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/12/advent-of-code-2022-day-1/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2022/day/1&#34;&gt;Day #1&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Find the elf carrying the most calories. Part two finds the top three elves.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import itertools&#xA;import sys&#xA;&#xA;&#xA;def main():&#xA;    with open(sys.argv[1]) as input:&#xA;        lines = input.read().splitlines()&#xA;&#xA;    # [&amp;#39;1&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;3&amp;#39;] -&amp;gt; [1, 2, &amp;#39;&amp;#39;, 3]&#xA;    lines = [int(line) if line != &amp;#34;&amp;#34; else line for line in lines]&#xA;&#xA;    # [1, 2, &amp;#39;&amp;#39;, 3] -&amp;gt; [[1, 2], [3]]&#xA;    groups = [list(group) for key, group in itertools.groupby(&#xA;        lines, lambda a: a == &amp;#34;&amp;#34;) if not key]&#xA;&#xA;    # Part 1&#xA;    calories = [sum(group) for group in groups]&#xA;&#xA;    print(max(calories))&#xA;&#xA;    # Part 2&#xA;    print(sum(sorted(calories, reverse=True)[:3]))&#xA;&#xA;&#xA;if __name__ == &amp;#39;__main__&amp;#39;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2022: Day 1&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 1
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-1/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-1/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/1&#34;&gt;Day #1&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Count the number of times a measurement increases from one to the next. Part two&#xA;uses a sliding window of three measurements.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    lines = input.readlines()&#xA;&#xA;numbers = [int(line.strip()) for line in lines]&#xA;&#xA;# Part 1&#xA;print(sum(y &amp;gt; x for x, y in zip(numbers[:-1], numbers[1:])))&#xA;&#xA;# Part 2&#xA;print(sum(y &amp;gt; x for x, y in zip(numbers[:-3], numbers[3:])))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 1&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 2
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-2/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-2/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/2&#34;&gt;Day #2&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Calculate final position using forward, down, and up instructions. Part two introduces an aim variable.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    lines = input.readlines()&#xA;&#xA;units = [line.split(&amp;#39; &amp;#39;) for line in lines]&#xA;&#xA;# Part 1&#xA;x = sum(int(unit[1]) for unit in units if unit[0] == &amp;#39;forward&amp;#39;)&#xA;y = sum(int(unit[1]) if unit[0] == &amp;#39;down&amp;#39; else (-1) * int(unit[1]) if unit[0] == &amp;#39;up&amp;#39; else 0 for unit in units)&#xA;&#xA;print(x * y)&#xA;&#xA;# Part 2&#xA;x = 0&#xA;y = 0&#xA;aim = 0&#xA;&#xA;for unit in units:&#xA;    instruction = unit[0]&#xA;    distance = int(unit[1])&#xA;&#xA;    if instruction == &amp;#39;forward&amp;#39;:&#xA;        x &amp;#43;= distance&#xA;        y &amp;#43;= aim * distance&#xA;    elif instruction == &amp;#39;up&amp;#39;:&#xA;        aim -= distance&#xA;    elif instruction == &amp;#39;down&amp;#39;:&#xA;        aim &amp;#43;= distance&#xA;&#xA;print(x * y)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 2&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 3
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-3/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-3/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/3&#34;&gt;Day #3&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Calculate power consumption using binary diagnostic data. Part two finds oxygen and CO2 ratings using bit criteria.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import numpy as np&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    lines = input.readlines()&#xA;&#xA;lines = [list(line.strip()) for line in lines]&#xA;&#xA;# Part 1&#xA;transposed = np.array(lines).T.tolist()&#xA;&#xA;gamma_str = &amp;#39;&amp;#39;.join([&amp;#39;1&amp;#39; if col.count(&amp;#39;1&amp;#39;) &amp;gt; col.count(&amp;#39;0&amp;#39;) else &amp;#39;0&amp;#39; for col in transposed])&#xA;gamma = int(gamma_str, base = 2)&#xA;&#xA;epsilon_str = &amp;#39;&amp;#39;.join([&amp;#39;0&amp;#39; if c == &amp;#39;1&amp;#39; else &amp;#39;1&amp;#39; for c in gamma_str])&#xA;epsilon = int(epsilon_str, base = 2)&#xA;&#xA;print(gamma * epsilon)&#xA;&#xA;# Part 2&#xA;def oxygen(lines, depth = 0):&#xA;    if len(lines) == 1:&#xA;        return int(&amp;#39;&amp;#39;.join(lines[0]), base = 2)&#xA;&#xA;    transposed = np.array(lines).T.tolist()&#xA;&#xA;    most_common = &amp;#39;1&amp;#39; if transposed[depth].count(&amp;#39;1&amp;#39;) &amp;gt;= transposed[depth].count(&amp;#39;0&amp;#39;) else &amp;#39;0&amp;#39;&#xA;&#xA;    return oxygen([line for line in lines if line[depth] == most_common], depth &amp;#43; 1)&#xA;&#xA;def co2(lines, depth = 0):&#xA;    if len(lines) == 1:&#xA;        return int(&amp;#39;&amp;#39;.join(lines[0]), base = 2)&#xA;&#xA;    transposed = np.array(lines).T.tolist()&#xA;&#xA;    most_common = &amp;#39;1&amp;#39; if transposed[depth].count(&amp;#39;1&amp;#39;) &amp;lt; transposed[depth].count(&amp;#39;0&amp;#39;) else &amp;#39;0&amp;#39;&#xA;&#xA;    return co2([line for line in lines if line[depth] == most_common], depth &amp;#43; 1)&#xA;&#xA;print(oxygen(lines) * co2(lines))&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 3&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 4
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-4/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-4/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/4&#34;&gt;Day #4&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Play bingo with submarine boards. Part one finds first winning board, part two finds last winning board.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import re&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    lines = input.readlines()&#xA;&#xA;draws = list(map(int, lines[0].strip().split(&amp;#39;,&amp;#39;)))&#xA;&#xA;num_boards = len(lines) // 6&#xA;&#xA;boards = [[[[int(el), False] for el in re.split(r&amp;#39;[ ]&amp;#43;&amp;#39;, r.strip())] for r in board] for board in [lines[(6 * n &amp;#43; 2) : 6 * n &amp;#43; 7] for n in range(num_boards)]]&#xA;&#xA;def mark_board(board, draw):&#xA;    for row in board:&#xA;        for el in row:&#xA;            if el[0] == draw:&#xA;                el[1] = True&#xA;                return&#xA;&#xA;def check_rows(board):&#xA;    for row in board:&#xA;        if all(marked for _, marked in row):&#xA;            return True&#xA;    return False&#xA;&#xA;def check_cols(board):&#xA;    for col in zip(*board):&#xA;        if all(marked for _, marked in col):&#xA;            return True&#xA;    return False&#xA;&#xA;def check_board(board):&#xA;    return check_rows(board) or check_cols(board)&#xA;&#xA;def score(board, draw):&#xA;    return sum([n for n, marked in sum(board, []) if not marked]) * draw&#xA;&#xA;def part1(boards, draws):&#xA;    for draw in draws:&#xA;        for board in boards:&#xA;            mark_board(board, draw)&#xA;            if check_board(board):&#xA;                print(score(board, draw))&#xA;                return&#xA;&#xA;def part2(boards, draws):&#xA;    finished = [False] * len(boards)&#xA;&#xA;    for draw in draws:&#xA;        for i, board in enumerate(boards):&#xA;            if finished[i]:&#xA;                continue&#xA;            mark_board(board, draw)&#xA;            if check_board(board):&#xA;                finished[i] = True&#xA;                if all(finished):&#xA;                    print(score(board, draw))&#xA;                    return&#xA;&#xA;part1(boards, draws)&#xA;part2(boards, draws)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 4&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 5
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-5/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-5/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/5&#34;&gt;Day #5&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Draw lines on a grid and count overlapping points. Part two includes diagonal lines.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;from collections import defaultdict&#xA;from itertools import count, islice&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    lines = input.read().splitlines()&#xA;&#xA;def direction(a, b):&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    3, 5 =&amp;gt; &amp;#43;1&#xA;    5, 3 =&amp;gt; -1&#xA;    5, 5 =&amp;gt; 0&#xA;    &amp;#34;&amp;#34;&amp;#34;&#xA;    return 1 if b &amp;gt; a else -1 if a &amp;gt; b else 0&#xA;&#xA;def fill(floor, x1, y1, x2, y2):&#xA;    for x, y in islice(zip(count(start = x1, step = direction(x1, x2)), count(start = y1, step = direction(y1, y2))), max(abs(x2 - x1), abs(y2 - y1)) &amp;#43; 1):&#xA;        floor[(x, y)] &amp;#43;= 1&#xA;&#xA;def part1():&#xA;    floor = defaultdict(int)&#xA;&#xA;    for line in lines:&#xA;        (x1, y1), (x2, y2) = _, _ = [list(map(int, pair.split(&amp;#39;,&amp;#39;))) for pair in line.split(&amp;#39; -&amp;gt; &amp;#39;)]&#xA;        if x1 == x2 or y1 == y2:&#xA;            fill(floor, x1, y1, x2, y2)&#xA;&#xA;    print(sum(el &amp;gt;= 2 for el in floor.values()))&#xA;&#xA;def part2():&#xA;    floor = defaultdict(int)&#xA;&#xA;    for line in lines:&#xA;        (x1, y1), (x2, y2) = _, _ = [list(map(int, pair.split(&amp;#39;,&amp;#39;))) for pair in line.split(&amp;#39; -&amp;gt; &amp;#39;)]&#xA;        fill(floor, x1, y1, x2, y2)&#xA;&#xA;    print(sum(el &amp;gt;= 2 for el in floor.values()))&#xA;&#xA;part1()&#xA;part2()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 5&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 6
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-6/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-6/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/6&#34;&gt;Day #6&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Simulate lanternfish population growth using a counter to track fish by their internal timer.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;from collections import Counter&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    numbers = list(map(int, input.read().split(&amp;#39;,&amp;#39;)))&#xA;&#xA;def simulation(days):&#xA;    fish = Counter(numbers)&#xA;&#xA;    for _ in range(days):&#xA;        next_fish = Counter()&#xA;        for timer, count in fish.items():&#xA;            if timer == 0:&#xA;                next_fish[8] &amp;#43;= fish[timer]&#xA;                next_fish[6] &amp;#43;= fish[timer]&#xA;            else:&#xA;                next_fish[timer - 1] &amp;#43;= fish[timer]&#xA;        fish = next_fish&#xA;&#xA;    print(sum(fish.values()))&#xA;&#xA;simulation(80)&#xA;simulation(256)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 6&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 7
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-7/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-7/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/7&#34;&gt;Day #7&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Calculate optimal position for crab submarines. Part one uses median, part two uses triangular cost function.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import statistics&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    numbers = list(map(int, input.read().split(&amp;#39;,&amp;#39;)))&#xA;&#xA;def part1():&#xA;    median = int(statistics.median(numbers))&#xA;    fuel = int(sum(abs(median - number) for number in numbers))&#xA;&#xA;    print(fuel)&#xA;&#xA;def cost(n):&#xA;    return (n * (n &amp;#43; 1)) / 2&#xA;&#xA;def part2():&#xA;    fuel = float(&amp;#39;inf&amp;#39;)&#xA;&#xA;    for guess in range(min(numbers), max(numbers) &amp;#43; 1):&#xA;        fuel = min(int(sum(cost(abs(guess - number)) for number in numbers)), fuel)&#xA;&#xA;    print(fuel)&#xA;&#xA;part1()&#xA;part2()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 7&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advent of Code 2021: Day 8
      </title>
      <link>https://perrotta.dev/2022/11/advent-of-code-2021-day-8/</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0000</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/11/advent-of-code-2021-day-8/</guid>
      <description>&lt;p&gt;♠ Refer to the &lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/&#34;&gt;previous post&lt;/a&gt; about AoC,&#xA;and to the &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;git repository&lt;/a&gt; with my&#xA;solutions in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;Link to &lt;a href=&#34;https://adventofcode.com/2021/day/8&#34;&gt;Day #8&lt;/a&gt; puzzle.&lt;/p&gt;&#xA;&lt;p&gt;Decode seven-segment display signals. Count unique digit segments in output values.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;import sys&#xA;&#xA;with open(sys.argv[1]) as input:&#xA;    lines = input.read().splitlines()&#xA;&#xA;def part1():&#xA;    total = 0&#xA;&#xA;    for line in lines:&#xA;        outputs = line.split(&amp;#39; | &amp;#39;)[1].split(&amp;#39; &amp;#39;)&#xA;        total &amp;#43;= sum(len(output) in [2, 3, 4, 7] for output in outputs)&#xA;&#xA;    print(total)&#xA;&#xA;part1()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code 2021: Day 8&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Advent of Code
      </title>
      <link>https://perrotta.dev/2022/01/advent-of-code/</link>
      <pubDate>Fri, 28 Jan 2022 17:44:00 -0500</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>coding</category>
      <category>advent-of-code</category>
      <category>bestof</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/01/advent-of-code/</guid>
      <description>&lt;p&gt;♠ Last year I found out about &lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;you-said-what&#34;&gt;&#xA;  You said what?&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/advent-of-code/#you-said-what&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Advent of Code&lt;/strong&gt; by &lt;a href=&#34;http://was.tl/&#34;&gt;Eric Wastl&lt;/a&gt; happens every year since 2015, every December from the 1st to&#xA;the 25th. Each day there&amp;rsquo;s a new programming challenge&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; split into two&#xA;parts. The first part tends to be easier than the second one. The second part&#xA;usually builds upon the first one, being a follow-up task that requires more&#xA;steps and/or with a higher degree of complexity. You can&amp;rsquo;t always reuse the&#xA;bits from the first part to solve the second one though.&lt;/p&gt;&#xA;&lt;p&gt;For those familiar with programming contests like &lt;a href=&#34;https://icpc.global/&#34;&gt;ACM ICPC&lt;/a&gt; or &lt;a href=&#34;https://olimpiada.ic.unicamp.br/&#34;&gt;OBI&lt;/a&gt;, or online judges like &lt;a href=&#34;https://www.spoj.com/&#34;&gt;SPOJ&lt;/a&gt; or &lt;a href=&#34;https://onlinejudge.org/&#34;&gt;UVa&lt;/a&gt;, advent of code feels like home. The main difference is that there is no time pressure and no need to write spaghetti and unreadable code; in fact, writing readable and elegant solutions is encouraged (&lt;em&gt;citation needed&lt;/em&gt;&amp;hellip;).&lt;/p&gt;&#xA;&lt;p&gt;For those familiar with FAANG/Tech whiteboard interviews, advent of code feels a lot like a typical interview. I would even go further and say it&amp;rsquo;s a great way to practice for interviews.&lt;/p&gt;&#xA;&lt;p&gt;It is a great moment to either (i) learn a new exciting programming language or (ii) improve your mastery on programming languages that you already know. I know several people (see below) that used AoC&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; to learn Rust or Kotlin or whatever else was exciting for them at the time. It&amp;rsquo;s surprising that the official Kotlin Docs even contain a section called &lt;a href=&#34;https://kotlinlang.org/docs/advent-of-code.html&#34;&gt;Advent of Code puzzles in idiomatic Kotlin&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Some folks go even further and use it to practice their &lt;a href=&#34;https://codegolf.stackexchange.com/questions/216024/advent-of-code-2020-day-2-part-1&#34;&gt;code golfing&lt;/a&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; or even &lt;a href=&#34;https://ryxcommar.com/2021/12/04/advent-of-code-2021-in-google-sheets-first-4-days/&#34;&gt;Google Sheets&lt;/a&gt; skills. I have a deep amount of respect for them as it&amp;rsquo;s quite a challenge. If you think it stops there, I&amp;rsquo;ve also seen solutions in &lt;a href=&#34;https://github.com/phillbush/aoc&#34;&gt;awk&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/_rsc/status/1476683352493207561&#34;&gt;sed&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Another positive aspect of AoC is that it has an integrated dashboard that tracks your progress as you go. It&amp;rsquo;s a simple element of gamification that immensely improves motivation and fun. You really feel a big desire to collect all those 50 stars&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-about-me&#34;&gt;&#xA;  What about me?&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/advent-of-code/#what-about-me&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;My goal for 2021 was relatively less ambitious than that,  I just wanted to improve my Python skills, more specifically Python 3. I learned Python 2 during my first year in university and used it sparingly at work and for personal endeavours, but always had a knowledge gap in Python 3.&lt;/p&gt;&#xA;&lt;p&gt;I set up a public git repository with &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;my solutions&lt;/a&gt; and aspired to write simple and elegant python, my only &lt;a href=&#34;https://frantic.im/no-constraints-no-fun/&#34;&gt;constraint&lt;/a&gt; was to limit myself to what is available in the standard library of a vanilla python3 installation in Alpine linux, with the exception of &lt;a href=&#34;https://numpy.org/&#34;&gt;&lt;code&gt;numpy&lt;/code&gt;&lt;/a&gt; which is widespread enough to deserve an entry in my &lt;a href=&#34;https://github.com/thiagowfx/adventofcode/blob/master/requirements.txt&#34;&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/a&gt;, and of course devtools like debuggers, linters and auto formatters as needed.&lt;/p&gt;&#xA;&lt;p&gt;As an additional, non-programming challenge I also limited myself to only use the command line. This basically meant no IDEs&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;. My programming environment was ultimately &lt;code&gt;ssh&lt;/code&gt; to an Alpine Linux VPS + &lt;code&gt;tmux&lt;/code&gt; + &lt;code&gt;vim&lt;/code&gt;. To make my life easier, one of the first tasks I accomplished was to write a generic &lt;a href=&#34;https://github.com/thiagowfx/adventofcode/blob/master/2022/Makefile&#34;&gt;&lt;code&gt;Makefile&lt;/code&gt;&lt;/a&gt; to help me test and run my scripts. A typical invocation would look like:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ make DEBUG=1 DAY=3&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;whereas I could choose between the sample input versus the real one with &lt;code&gt;DEBUG&lt;/code&gt;, and the puzzle day with &lt;code&gt;DAY&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Was the experience worth it? &lt;strong&gt;Definitely yes&lt;/strong&gt;! Even though I only completed ~8 puzzles out of the 25 ones due to having my attention split with another project I was working on at the time, the thematic submarine puzzles were hella fun and I learned a lot of python 3 on the way.&lt;/p&gt;&#xA;&lt;p&gt;A few highlights of what I learned &lt;em&gt;and used&lt;/em&gt; from my python &lt;code&gt;2to3&lt;/code&gt; transition were f-strings / string interpolation (&lt;code&gt;print(f&#39;The sum is {sum}&#39;)&lt;/code&gt;), &amp;ldquo;everything is an iterator now&amp;rdquo; even &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;range&lt;/code&gt;, the standard library is awesome and sometimes you stumble upon useful abstractions like &lt;code&gt;Counter&lt;/code&gt; and &lt;code&gt;defaultdict&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt; is different now (&lt;code&gt;key&lt;/code&gt; instead of comparison function), this &lt;code&gt;pdb&lt;/code&gt; debugger thingy, among other topics I can&amp;rsquo;t remember at the moment. I realized the only concept that was previously familiar was the different syntax of the &lt;code&gt;print&lt;/code&gt; function (you have to use parentheses now).&lt;/p&gt;&#xA;&lt;p&gt;In terms of workflow, I also learned that virtual environments are now&#xA;supported natively&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; (&lt;code&gt;python -m venv&lt;/code&gt;), &lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/&#34;&gt;&lt;code&gt;direnv&lt;/code&gt;&lt;/a&gt; is an amazing tool to&#xA;automate/manage environments in git repositories and also happens to have&#xA;first-class python integration, &lt;code&gt;pylint&lt;/code&gt; and &lt;code&gt;autopep8&lt;/code&gt; are good integrations&#xA;with &lt;code&gt;vim&lt;/code&gt; to help spot basic errors and/or suggest best practices, and &lt;code&gt;numpy&lt;/code&gt; takes forever to build from source.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-about-the-community&#34;&gt;&#xA;  What about the community?&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/advent-of-code/#what-about-the-community&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;AoC enjoys a lot of popularity and zeitgeist, especially during times of the COVID-19 pandemic, but even before then. There&amp;rsquo;s a large &lt;a href=&#34;https://www.reddit.com/r/adventofcode/&#34;&gt;/r/adventofcode&lt;/a&gt; subreddit community, lots of people share their solution snippets and impressions on Twitter (&lt;a href=&#34;https://twitter.com/search?q=%23adventofcode&amp;amp;src=typed_query&#34;&gt;#AdventOfCode&lt;/a&gt;), there&amp;rsquo;s a ton of public git repositories on &lt;a href=&#34;https://github.com/search?q=adventofcode&#34;&gt;GitHub&lt;/a&gt; where people share their coding solutions, in pretty much any programming language you can think of, and finally there are many screencasts on &lt;a href=&#34;https://www.youtube.com/results?search_query=advent&amp;#43;of&amp;#43;code&#34;&gt;YouTube&lt;/a&gt;. The Internet in the 2020s sparks creativity in every unimaginable corner.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s so much information that it&amp;rsquo;s impossible to stay on top of everything. Here is a small list of repositories that I followed this year, most of those are acquaintances/friends and/or stumbled upon Twitter:&lt;/p&gt;&#xA;&lt;p&gt;C++:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/riuri/adventofcode&#34;&gt;https://github.com/riuri/adventofcode&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Python:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/sjvrijn/AdventofCode&#34;&gt;https://github.com/sjvrijn/AdventofCode&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/oomenn/AOC&#34;&gt;https://github.com/oomenn/AOC&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Rust:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/dimo414/advent-2021&#34;&gt;https://github.com/dimo414/advent-2021&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/mfs/aoc&#34;&gt;https://github.com/mfs/aoc&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;Edit (2024-08-06)&lt;/strong&gt;: Additions from 2022:&lt;/p&gt;&#xA;&lt;p&gt;C++:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/eariassoto/advent-of-code-cpp&#34;&gt;https://github.com/eariassoto/advent-of-code-cpp&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Python:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/achrafmam2/adventofcode&#34;&gt;https://github.com/achrafmam2/adventofcode&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/mcerdeiro/aoc2022&#34;&gt;https://github.com/mcerdeiro/aoc2022&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I find it&amp;rsquo;s really constructive and useful (and also &lt;em&gt;fun&lt;/em&gt;) to peek at other people&amp;rsquo;s solutions after I coded my own. I have extensive (albeit kinda rusty these days) experience with C++ so I wanted to follow at least one repository coded with it; since I wrote my solutions in python it was also a natural choice to follow a few python repositories; and, finally, I wanted to peek at some languages I am not familiar with to get a gist of them. This year I watched Rust and a few bits of Clojure and Kotlin on Twitter.&lt;/p&gt;&#xA;&lt;p&gt;Finally, for some extra inspiration, there are also some &lt;em&gt;10x programmers&lt;/em&gt;&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; out there that seem to be fans of AoC as well: &lt;a href=&#34;https://github.com/norvig/pytudes&#34;&gt;Peter Norvig&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/_rsc/status/1466089522718986241&#34;&gt;Russ Cox (&lt;em&gt;rsc&lt;/em&gt;)&lt;/a&gt;. There are probably several others I am not aware of.&lt;/p&gt;&#xA;&lt;h2 id=&#34;final-remarks&#34;&gt;&#xA;  Final remarks&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/advent-of-code/#final-remarks&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;I am hoping to participate in AoC this year (2022) as well, and possibly revisit the 2021 puzzles and resolve the rest of the ones I missed as time permits.&lt;/p&gt;&#xA;&lt;p&gt;Hopefully this post encourages and motivates you to try Advent of Code as well! Happy coding.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Or puzzle, if you will.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Acronym not to be confused with a certain &lt;del&gt;annoying&lt;/del&gt;^W politician.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;For those unfamiliar with the concept, code golfing is all about writing a correct solution with the &lt;strong&gt;fewest&lt;/strong&gt; amount of characters.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;For example: PyCharm, and also VSCode, which is getting so big these days I don&amp;rsquo;t even know if it&amp;rsquo;s possible to just call it a simple text editor anymore.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:5&#34;&gt;&#xA;&lt;p&gt;Back in the days, &lt;code&gt;virtualenvwrapper&lt;/code&gt; was all the rage.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:6&#34;&gt;&#xA;&lt;p&gt;The &lt;em&gt;10x programmer&lt;/em&gt; thing is a well-known joke however in this instance the mentioned characters are indeed superb programmers that I immensely respect.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/advent-of-code/#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Advent of Code&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/categories/coding/&#34;&gt;%coding&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Direnv: Automate your Environment Variables
      </title>
      <link>https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/</link>
      <pubDate>Tue, 04 Jan 2022 00:34:07 -0500</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>advent-of-code</category>
      <category>bestof</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://direnv.net/&#34;&gt;Direnv&lt;/a&gt; is a tool to automate your shell to automatically load and unload environment variables on-the-fly, on a per-project (per-directory) basis.&lt;/p&gt;&#xA;&lt;h2 id=&#34;preliminaries-is-it-worth-it&#34;&gt;&#xA;  Preliminaries: Is it worth it?&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#preliminaries-is-it-worth-it&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Questions I like to ask myself before deciding whether to invest my time into learning and potentially &lt;strong&gt;adopting&lt;/strong&gt; a foreign tool are the following:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Is it &lt;strong&gt;popular&lt;/strong&gt; &lt;em&gt;and&lt;/em&gt; &lt;strong&gt;stable&lt;/strong&gt; enough?&#xA;Is it abandonware?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;popularity&#34;&gt;&#xA;  Popularity&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#popularity&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Popularity is relative, it doesn&amp;rsquo;t need to be worthy of the Hacker News frontpage nor Hotness on Reddit, but it needs to be widely available in popular Linux distributions and/or package managers, one install command away from my development environment.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://repology.org/&#34;&gt;Repology&lt;/a&gt; is a good proxy for popularity. Looking at &lt;a href=&#34;https://repology.org/project/direnv/badges&#34;&gt;direnv&lt;/a&gt; therein, it&amp;rsquo;s available for Alpine, Arch, Debian, Fedora, FreeBSD, HomeBrew, Nix, OpenBSD, Ubuntu&amp;hellip;that&amp;rsquo;s more than enough, we can safely conclude &lt;code&gt;direnv&lt;/code&gt; is widely popular.&lt;/p&gt;&#xA;&lt;p&gt;The main takeaway we want to confirm is whether the project isn&amp;rsquo;t too niche and/or an one-man show. Seeing signs of a small-ish community and/or occasional contributions from external users/developers helps build confidence and give credibility to the project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;stability-and-abandonware&#34;&gt;&#xA;  Stability and Abandonware&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#stability-and-abandonware&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Stability is easier to define than popularity and can often be determined just by taking a quick glance at the github (or whichever other forge it&amp;rsquo;s hosted in) page of the project.&lt;/p&gt;&#xA;&lt;p&gt;At the time of this writing, the latest release of &lt;a href=&#34;https://github.com/direnv/direnv&#34;&gt;direnv&lt;/a&gt; was about a week ago (2.30.2, Dec 28th 2021). It&amp;rsquo;s definitely not abandonware and it&amp;rsquo;s well maintained. A few signs that help corroborate that:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Several PRs were merged recently&lt;/li&gt;&#xA;&lt;li&gt;Its issue tracker is quite active, with a good mix of feature requests and bugs&lt;/li&gt;&#xA;&lt;li&gt;I don&amp;rsquo;t like to judge the project based on the number of issues it has, especially if it&amp;rsquo;s popular. Chromium has &lt;a href=&#34;https://bugs.chromium.org/p/chromium/issues/list&#34;&gt;60k+&lt;/a&gt; issues at the time of this writing, yet I wouldn&amp;rsquo;t call it &lt;em&gt;bleeding edge&lt;/em&gt;. Common sense applies. Since &lt;code&gt;direnv&lt;/code&gt; has been around for a while and it&amp;rsquo;s relatively popular, 150+ open issue seems acceptable to me.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Now that &lt;code&gt;direnv&lt;/code&gt; passed the Litmus test for adoption&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, let&amp;rsquo;s get our hands dirty.&lt;/p&gt;&#xA;&lt;h2 id=&#34;installation&#34;&gt;&#xA;  Installation&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#installation&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;There&amp;rsquo;s nothing special here, as &lt;code&gt;direnv&lt;/code&gt; is widely packaged. Pick your poison:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ sudo pacman -Syu direnv  # Arch Linux&#xA;$ doas apk add direnv  # Alpine Linux&#xA;$ sudo apt install direnv  # Debian-based distros&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Is it lightweight?&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ apk info -L direnv&#xA;direnv-2.30.1-r0 contains:&#xA;usr/bin/direnv&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Hell yes! More lightweight than that? Impossible. It&amp;rsquo;s a single binary thanks to Golang. No tons of files or dependencies. I mean:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ du -sh /usr/bin/direnv&#xA;7.5M    /usr/bin/direnv&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;it&amp;rsquo;s a 7MB binary, let&amp;rsquo;s not get ahead of ourselves. But that&amp;rsquo;s fine, really, it&amp;rsquo;s just a dev tool, we don&amp;rsquo;t really deploy it to prod.&lt;/p&gt;&#xA;&lt;h2 id=&#34;use-cases&#34;&gt;&#xA;  Use Cases&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#use-cases&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Everything is controlled with a &lt;code&gt;.envrc&lt;/code&gt; file within a repository root. A typical file could look like this:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;export HOUSE=&amp;#34;ATREIDES&amp;#34;&#xA;layout python3&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://direnv.net/&#34;&gt;upstream website&lt;/a&gt; does a great job at summarizing use cases. I am not here to duplicate documentation, so please go ahead and read it. That said, here are some example use cases I found useful:&lt;/p&gt;&#xA;&lt;h3 id=&#34;use-case-python&#34;&gt;&#xA;  Use Case: Python&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#use-case-python&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Python developers often need to create different virtual environments for different projects. For example, I was participating in &lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt; last year and wrote my solutions in Python 3: &lt;a href=&#34;https://github.com/thiagowfx/adventofcode&#34;&gt;https://github.com/thiagowfx/adventofcode&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Each day&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; I would &lt;code&gt;cd ~/projects/adventofcode&lt;/code&gt;, and then do &lt;code&gt;source ~/.venv/bin/activate&lt;/code&gt;. And guess what, that&amp;rsquo;s for the first terminal where I&amp;rsquo;d run &lt;code&gt;make&lt;/code&gt;, I&amp;rsquo;d also spawn a second one with &lt;code&gt;vim&lt;/code&gt;, thereby needing to activate the virtual environment twice.&lt;/p&gt;&#xA;&lt;p&gt;And this is assuming the virtual environment already exists. If it didn&amp;rsquo;t — for example, after a vanilla &lt;code&gt;git clone&lt;/code&gt;, I&amp;rsquo;d have to do &lt;code&gt;python -m venv .venv&lt;/code&gt; first.&lt;/p&gt;&#xA;&lt;p&gt;Quickly all of this became repetitive and annoying. I kinda &amp;ldquo;cheated&amp;rdquo; and stopped using the virtualenv for a few days, relying on my Linux distribution package manager instead:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% apk add py3-{autopep8,pyflakes,numpy,pylint}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This way, my&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import numpy&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;would correctly work and not yell that &lt;code&gt;numpy&lt;/code&gt; was nowhere to be found.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s not very clean, but it worked. However eventually I wanted to become cleaner and leaner and automate my virtual environment setup. I uninstalled the aforementioned packages after a few days:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;% apk del py3-{autopep8,pyflakes,numpy,pylint}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;therefore forcing me to come up with a better setup. I always had direnv in my TODO list, and this was the perfect moment to try it out.&lt;/p&gt;&#xA;&lt;p&gt;How does &lt;code&gt;direnv&lt;/code&gt; address this?&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Add the &lt;code&gt;direnv&lt;/code&gt; hook to your shell. I actively use two shells&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;zsh&lt;/code&gt;, so I did it twice and then added it to my &lt;a href=&#34;https://github.com/thiagowfx/.dotfiles&#34;&gt;dotfiles&lt;/a&gt;:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Bash:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash&#xA;# https://direnv.net/&#xA;if hash direnv &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&#xA;        eval &amp;#34;$(direnv hook bash)&amp;#34;&#xA;fi&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Zsh:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-zsh&#34;&gt;#!/bin/zsh&#xA;# https://direnv.net/&#xA;if (( $&amp;#43;commands[direnv] )); then&#xA;        eval &amp;#34;$(direnv hook zsh)&amp;#34;&#xA;fi&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;Set up direnv in the AOC repository:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ cat ~/projects/adventofcode/.envrc&#xA;layout python3&#xA;$ direnv allow  # Only needs to be done once&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;That&amp;rsquo;s it: It&amp;rsquo;s a single line of configuration. Now what does it do? All of the above. No magic: whenever you cd into the project directory or any of its subdirectories with one of the configured shells, if the venv doesn&amp;rsquo;t exist:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;it will be automatically created;&lt;/li&gt;&#xA;&lt;li&gt;then it will be sourced&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Now you may ask yourself: Why go through all this trouble? Why not simply create a shell script to do exactly that for you automatically? That&amp;rsquo;s perfectly fine, it&amp;rsquo;s a matter of taste. But then you&amp;rsquo;ll have to maintain that script. The python ecosystem keeps changing — a few years ago I was using &lt;code&gt;virtualenvwrapper&lt;/code&gt; to manage virtual environments, these days it doesn&amp;rsquo;t exist anymore, people use either &lt;code&gt;python -m env&lt;/code&gt; or &lt;code&gt;pyenv&lt;/code&gt; or &lt;code&gt;poetry&lt;/code&gt; or&amp;hellip;it never ends. &lt;a href=&#34;https://drewdevault.com/2021/11/16/Python-stop-screwing-distros-over.html&#34;&gt;Drew DeVault&lt;/a&gt; wrote a good piece about that.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;a href=&#34;https://xkcd.com/1987/&#34;&gt;&lt;img src=&#34;https://imgs.xkcd.com/comics/python_environment.png&#34;&#xA;    alt=&#34;The Python environmental protection agency wants to seal it in a cement chamber, with pictorial messages to future civilizations warning them about the danger of using sudo to install random Python packages.&#34;&gt;&lt;/a&gt;&lt;figcaption&gt;&#xA;      &lt;p&gt;XKCD Courtesy of Randall Munroe&lt;/p&gt;&#xA;    &lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;Maintenance is not the only burden, scalability is also one: If you use python in several repositories, you&amp;rsquo;ll now have to include your script in all of them.&lt;/p&gt;&#xA;&lt;p&gt;Considering that &lt;code&gt;direnv&lt;/code&gt; is flexible enough in other scenarios, I consider its adoption in this situation a good trade-off to make.&lt;/p&gt;&#xA;&lt;h3 id=&#34;use-case-hugo&#34;&gt;&#xA;  Use Case: Hugo&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#use-case-hugo&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;This blog is written in Hugo. I have a &lt;code&gt;Makefile&lt;/code&gt; with a bunch of environment variables to manage its setup:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ make dev&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Whenever I am working in my VPS, for reasons outside of the scope of this post I need to use a different port other than the default one for Hugo (&lt;code&gt;1313&lt;/code&gt;). Since I am using variables, I could just do:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ make PORT=1234 dev&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;However, to make this change permanent (&amp;ldquo;fire-and-forget&amp;rdquo;), I could also do:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ echo &amp;#39;export PORT=1234&amp;#39; | tee -a .envrc&#xA;$ direnv allow  # Only needs to be done once&#xA;$ make dev&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This way, whenever I run &lt;code&gt;make&lt;/code&gt; I wouldn&amp;rsquo;t even need to think twice about which port to use.&lt;/p&gt;&#xA;&lt;p&gt;Of course, a small improvement that should be done in this scenario is to add &lt;code&gt;direnv&lt;/code&gt; related files to your &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;$ git ignore direnv &amp;gt;&amp;gt; .gitignore&#xA;&#xA;# Created by https://www.toptal.com/developers/gitignore/api/direnv&#xA;# Edit at https://www.toptal.com/developers/gitignore?templates=direnv&#xA;&#xA;### direnv ###&#xA;.direnv&#xA;.envrc&#xA;&#xA;# End of https://www.toptal.com/developers/gitignore/api/direnv&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;other-use-cases&#34;&gt;&#xA;  Other use cases?&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#other-use-cases&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;I don&amp;rsquo;t have other real use cases to share because only recently I became familiarized with &lt;code&gt;direnv&lt;/code&gt;. That said, the &lt;a href=&#34;https://direnv.net/man/direnv-stdlib.1.html&#34;&gt;direnv docs&lt;/a&gt; are very comprehensive of its full potential usage.&lt;/p&gt;&#xA;&lt;p&gt;Some use cases that I like:&lt;/p&gt;&#xA;&lt;dl&gt;&#xA;&lt;dt&gt;&lt;code&gt;dotenv&lt;/code&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;Automatically sources &lt;code&gt;.env&lt;/code&gt; (note: not to confuse with &lt;code&gt;.envrc&lt;/code&gt;) files, which are widely common in projects managed with &lt;code&gt;docker-compose&lt;/code&gt;.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;code&gt;source_env&lt;/code&gt; + &lt;code&gt;env_vars_required&lt;/code&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;Alongside &lt;code&gt;.gitignore&lt;/code&gt;, this is a great way to source secrets (e.g. API keys or tokens) and not accidentally check them into your repository.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;code&gt;fetchurl&lt;/code&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;&lt;code&gt;bash | curl&lt;/code&gt; is a cancer&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; that should arguably be stopped due to its inherent security risks. That said, &lt;code&gt;direnv&lt;/code&gt; provides a safer way to work with it because you can specify a hash to ensure you&amp;rsquo;re downloading the same script — if an attacker or malicious actor modified it, direnv would throw an error.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;code&gt;path_add&lt;/code&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;If your project outputs to e.g. &lt;code&gt;build/&amp;lt;...&amp;gt;/bin&lt;/code&gt; or similar (typical in &lt;code&gt;cmake&lt;/code&gt; projects and AFAIK in Rust ones too), you could add that directory to your &lt;code&gt;PATH&lt;/code&gt; so that you could easily execute your binaries, without having to write the full subdirectory path each time.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;code&gt;layout&lt;/code&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;Besides python, &lt;code&gt;direnv&lt;/code&gt; supports several other programming languages out-of-the-box. Popular examples include &lt;code&gt;go&lt;/code&gt;, &lt;code&gt;nix&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;perl&lt;/code&gt; and &lt;code&gt;ruby&lt;/code&gt;.&lt;/dd&gt;&#xA;&lt;/dl&gt;&#xA;&lt;h2 id=&#34;downsides&#34;&gt;&#xA;  Downsides?&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#downsides&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;One could call &lt;code&gt;direnv&lt;/code&gt; bloated because of all of the aforementioned capabilities. If it doesn&amp;rsquo;t spark joy for your taste, consider using &lt;a href=&#34;https://github.com/hyperupcall/autoenv&#34;&gt;autoenv&lt;/a&gt; which is basically a leaner version of &lt;code&gt;direnv&lt;/code&gt;, meant mostly for doing one thing and doing it well: setting and unsetting variables.&lt;/p&gt;&#xA;&lt;p&gt;Other than that, &lt;code&gt;direnv&lt;/code&gt; is pretty much a great piece of software.&lt;/p&gt;&#xA;&lt;p&gt;One thing I didn&amp;rsquo;t cover is how secure it is: You need to run &lt;code&gt;direnv allow&lt;/code&gt; explicitly in order to tell &lt;code&gt;direnv&lt;/code&gt; that you trust a given &lt;code&gt;.envrc&lt;/code&gt; file. If you don&amp;rsquo;t do it, &lt;code&gt;direnv&lt;/code&gt; will refuse to source it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ touch .envrc&#xA;direnv: error ~/projects/foo/.envrc is blocked. Run `direnv allow` to approve its content&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you run &lt;code&gt;direnv allow&lt;/code&gt; but later on the file is modified (for example, after &lt;code&gt;git pull&lt;/code&gt;, whereby you retrieve a modification from a teammate), &lt;code&gt;direnv&lt;/code&gt; will once again refuse to operate. You&amp;rsquo;ll need to whitelist it again by re-running &lt;code&gt;direnv allow&lt;/code&gt;. Direnv will snapshot/hash the file contents of &lt;code&gt;.envrc&lt;/code&gt; remember it across sessions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;references&#34;&gt;&#xA;  References&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#references&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://cuddly-octo-palm-tree.com/posts/2021-12-12-tyska-direnv/&#34;&gt;Tools You Should Know About: direnv&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Obviously the aforementioned list was non-exhaustive. There are a few other questions that you may want to ask, out of scope of this article, such as: (i) does the project have an OSS or FLOSS license? (ii) does the project depend on Java?&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Advent of code challenges are released one by one, thereby forcing you to wait until the next day in order to get the next challenge.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;more on this another day&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;c.f. &lt;a href=&#34;https://curlpipesh.tumblr.com/&#34;&gt;https://curlpipesh.tumblr.com/&lt;/a&gt;, &lt;a href=&#34;https://gnu.moe/wallofshame.md&#34;&gt;https://gnu.moe/wallofshame.md&lt;/a&gt;&amp;#160;&lt;a href=&#34;https://perrotta.dev/2022/01/direnv-automate-your-environment-variables/#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Direnv: Automate your Environment Variables&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/advent-of-code/&#34;&gt;#advent-of-code&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
