<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>adventofcode &amp;mdash; Wizarth&#39;s Blog</title>
    <link>https://wizarth.com.au/tag:adventofcode</link>
    <description></description>
    <pubDate>Fri, 24 Apr 2026 01:55:41 +1000</pubDate>
    <item>
      <title>Advent of Code 2024 - Day 2</title>
      <link>https://wizarth.com.au/advent-of-code-2024-day-2</link>
      <description>&lt;![CDATA[Part 1&#xA;&#xA;Given a collection of sequences of numbers, determine how many sequences meet the criteria (described as &#34;are safe&#34;):&#xA;&#xA;Either&#xA;  The sequence is increasing&#xA;  The sequence is decreasing&#xA;The sequence change is at least 1 and at most 3&#xA;&#xA;After grabbing the input data, it&#39;s worth noting that the sequences are not consistently sized. They vary in length between 5 and 8 numbers, and unlike Day 1, the numbers have varying numbers of digits.&#xA;&#xA;I feel like parseinput could have been implemented using map on the iterables returned by eachline and eachsplit, but the for/push! combination was Good Enough™.&#xA;&#xA;I couldn&#39;t find a built in Julia function to iterate over a collection performing a comparison to the previous element, so I wrote one. The first attempt was implementing all of isincreasing, then I realized it could be used with a functor, which is The Julia Way™.&#xA;&#xA;The ischangeinrange test uses the chaining comparisons feature of Julia, which is really pleasant to write. It also uses the do syntax for declaring a functor, which is part of why applying a functor is The Julia Way™.&#xA;&#xA;function parseinput(src = &#34;input.txt&#34;)&#xA;    sequences = Vector{Vector{Int}}(undef, 0)&#xA;    for line in eachline(src)&#xA;        sequence = Vector{Int}(undef, 0)&#xA;        for digits in eachsplit(line)&#xA;            push!(sequence, parse(Int, digits))&#xA;        end&#xA;        push!(sequences, sequence)&#xA;    end&#xA;&#xA;    sequences&#xA;end&#xA;&#xA;Compare each element of a sequence with the previous element&#xA;If the comparison function returns false, return false immediately&#xA;Otherwise return true&#xA;function comparesequenceelements(f, seq)&#xA;    @assert length(seq)   1&#xA;&#xA;    prev = seq[begin]&#xA;    for cur in seq[begin+1:end]&#xA;        if(!f(prev, cur))&#xA;            return false&#xA;        end&#xA;        prev = cur&#xA;    end&#xA;    return true&#xA;end&#xA;&#xA;isincreasing(seq) = comparesequenceelements(&lt;, seq)&#xA;isdecreasing(seq) = comparesequenceelements(  , seq)&#xA;function ischangeinrange(seq, minchange = 1, maxchange = 3) &#xA;    comparesequenceelements(seq) do prev, cur&#xA;        diff = abs(prev - cur)&#xA;        return minchange &lt;= diff &lt;= maxchange&#xA;    end&#xA;end&#xA;&#xA;issafe(seq) = (isincreasing(seq) || isdecreasing(seq)) &amp;&amp; ischangeinrange(seq)&#xA;&#xA;function mainpart1()&#xA;    coll = parseinput()&#xA;&#xA;    println(&#34;Safe reports:&#34;, count(issafe, coll))&#xA;end&#xA;&#xA;mainpart1()&#xA;&#xA;Part 2&#xA;&#xA;This continues Part 1 by adding another condition under which a sequence can be considered &#34;safe&#34;, named the &#34;Problem Dampener&#34;.&#xA;&#xA;If removing a single element from the sequence makes it pass the conditions, then it should be considered &#34;safe&#34;.&#xA;&#xA;issafewithdampener makes use of Julia&#39;s great index range handling. begin and end make accessing the heads &amp; tails of collections concise, and the code takes advantage of Julia&#39;s behavior of returning an empty collection if you provide a second index that is less than the first (without specifying a negative step).&#xA;&#xA;I also like that because the code uses eachindex, it doesn&#39;t care if the sequence is 1 indexed (the Julia default), or some other starting point. By using prevind and nextind, the code doesn&#39;t assume the sequence is using linear indexing. During compilation, these all get substituted with what is appropriate for the sequence, so there&#39;s no performance overhead for writing more generic code.&#xA;&#xA;function issafewithdampener(seq)&#xA;    if issafe(seq)&#xA;        return true&#xA;    end&#xA;    # Test the sequence, removing an element&#xA;    # If any subsequence returns true, return true&#xA;    for ind in eachindex(seq)&#xA;        subseq = vcat(seq[begin:prevind(seq,ind)], seq[nextind(seq,ind):end])&#xA;        if issafe(subseq)&#xA;            return true&#xA;        end&#xA;    end&#xA;&#xA;    return false&#xA;end&#xA;&#xA;function mainpart2()&#xA;    coll = parseinput()&#xA;&#xA;    println(&#34;Safe reports (with dampener):&#34;, count(issafewithdampener, coll))&#xA;end&#xA;&#xA;main_part2()&#xA;&#xA;#AdventOfCode #JuliaLang]]&gt;</description>
      <content:encoded><![CDATA[<h2 id="part-1" id="part-1">Part 1</h2>

<p>Given a collection of sequences of numbers, determine how many sequences meet the criteria (described as “are safe”):</p>
<ul><li>Either
<ul><li>The sequence is increasing</li>
<li>The sequence is decreasing</li></ul></li>
<li>The sequence change is at least 1 and at most 3</li></ul>

<p>After grabbing the input data, it&#39;s worth noting that the sequences are not consistently sized. They vary in length between 5 and 8 numbers, and unlike Day 1, the numbers have varying numbers of digits.</p>

<p>I feel like <code>parse_input</code> could have been implemented using <code>map</code> on the iterables returned by <code>eachline</code> and <code>eachsplit</code>, but the <code>for</code>/<code>push!</code> combination was Good Enough™.</p>

<p>I couldn&#39;t find a built in Julia function to iterate over a collection performing a comparison to the previous element, so I wrote one. The first attempt was implementing all of <code>is_increasing</code>, then I realized it could be used with a functor, which is The Julia Way™.</p>

<p>The <code>is_change_in_range</code> test uses the chaining comparisons feature of Julia, which is really pleasant to write. It also uses the <code>do</code> syntax for declaring a functor, which is part of why applying a functor is The Julia Way™.</p>

<pre><code class="language-julia">
function parse_input(src = &#34;input.txt&#34;)
    sequences = Vector{Vector{Int}}(undef, 0)
    for line in eachline(src)
        sequence = Vector{Int}(undef, 0)
        for digits in eachsplit(line)
            push!(sequence, parse(Int, digits))
        end
        push!(sequences, sequence)
    end

    sequences
end

# Compare each element of a sequence with the previous element
# If the comparison function returns false, return false immediately
# Otherwise return true
function compare_sequence_elements(f, seq)
    @assert length(seq) &gt; 1

    prev = seq[begin]
    for cur in seq[begin+1:end]
        if(!f(prev, cur))
            return false
        end
        prev = cur
    end
    return true
end

is_increasing(seq) = compare_sequence_elements(&lt;, seq)
is_decreasing(seq) = compare_sequence_elements(&gt;, seq)
function is_change_in_range(seq, min_change = 1, max_change = 3) 
    compare_sequence_elements(seq) do prev, cur
        diff = abs(prev - cur)
        return min_change &lt;= diff &lt;= max_change
    end
end

is_safe(seq) = (is_increasing(seq) || is_decreasing(seq)) &amp;&amp; is_change_in_range(seq)

function main_part1()
    coll = parse_input()

    println(&#34;Safe reports:&#34;, count(is_safe, coll))
end

main_part1()
</code></pre>

<h2 id="part-2" id="part-2">Part 2</h2>

<p>This continues Part 1 by adding another condition under which a sequence can be considered “safe”, named the “Problem Dampener”.</p>

<p>If removing a single element from the sequence makes it pass the conditions, then it should be considered “safe”.</p>

<p><code>is_safe_with_dampener</code> makes use of Julia&#39;s great index range handling. <code>begin</code> and <code>end</code> make accessing the heads &amp; tails of collections concise, and the code takes advantage of Julia&#39;s behavior of returning an empty collection if you provide a second index that is less than the first (without specifying a negative step).</p>

<p>I also like that because the code uses <code>eachindex</code>, it doesn&#39;t care if the sequence is 1 indexed (the Julia default), or some other starting point. By using <code>prevind</code> and <code>nextind</code>, the code doesn&#39;t assume the sequence is using linear indexing. During compilation, these all get substituted with what is appropriate for the sequence, so there&#39;s no performance overhead for writing more generic code.</p>

<pre><code class="language-julia">function is_safe_with_dampener(seq)
    if is_safe(seq)
        return true
    end
    # Test the sequence, removing an element
    # If any subsequence returns true, return true
    for ind in eachindex(seq)
        subseq = vcat(seq[begin:prevind(seq,ind)], seq[nextind(seq,ind):end])
        if is_safe(subseq)
            return true
        end
    end

    return false
end

function main_part2()
    coll = parse_input()

    println(&#34;Safe reports (with dampener):&#34;, count(is_safe_with_dampener, coll))
end

main_part2()
</code></pre>

<p><a href="https://wizarth.com.au/tag:AdventOfCode" class="hashtag"><span>#</span><span class="p-category">AdventOfCode</span></a> <a href="https://wizarth.com.au/tag:JuliaLang" class="hashtag"><span>#</span><span class="p-category">JuliaLang</span></a></p>
]]></content:encoded>
      <guid>https://wizarth.com.au/advent-of-code-2024-day-2</guid>
      <pubDate>Sun, 26 Jan 2025 07:31:42 +0000</pubDate>
    </item>
    <item>
      <title>Advent Of Code 2024 - Day 1</title>
      <link>https://wizarth.com.au/advent-of-code-2024-day-1</link>
      <description>&lt;![CDATA[I decided to do the Advent of Code in Julia, as a way of getting back into coding for fun.&#xA;&#xA;Part 1&#xA;&#xA;Given two lists of numbers, work out the distance between each entry in the list (after sorting the lists), then sum the distances to determine the &#34;similarity&#34;.&#xA;&#xA;This is the first time I&#39;ve written Julia code since 2023-09 , so it involved a lot of referring to the documentation, and it&#39;s not really taking advantage of any Julia language specific features (like all code blocks automatically returning their last value).&#xA;&#xA;Get the distance between two lists, after sorting them&#xA;function listdistances(lhs, rhs)&#xA;    lhssorted = sort(lhs)&#xA;    rhssorted = sort(rhs)&#xA;&#xA;    return map(lhssorted, rhssorted) do left, right&#xA;        return abs(left - right)&#xA;    end&#xA;end&#xA;&#xA;function parseinput(src = &#34;input.txt&#34;)&#xA;    # Format of src&#xA;    # #####   #####\n&#xA;    lhs = Vector{Int}(undef, 0)&#xA;    rhs = Vector{Int}(undef, 0)&#xA;    for line in eachline(src) &#xA;        lhssubstr = line[1:5]&#xA;        rhssubstr = line[9:13]&#xA;        l = parse(Int, lhssubstr; base=10)&#xA;        r = parse(Int, rhssubstr; base=10)&#xA;&#xA;        push!(lhs, l)&#xA;        push!(rhs, r)&#xA;    end&#xA;    return lhs, rhs&#xA;end&#xA;&#xA;function mainpart1()&#xA;    lhs, rhs = parseinput()&#xA;&#xA;    listdist = listdistances(lhs, rhs)&#xA;&#xA;    totaldist = sum(listdist)&#xA;&#xA;    println(&#34;Total dist: &#34;, totaldist)&#xA;end&#xA;&#xA;mainpart1()&#xA;&#xA;Part 2&#xA;&#xA;For each entry in a list, determine how often it appears in a second list, then multiply the entry by that frequency - then sum these factors.&#xA;&#xA;For this one, I was a bit more warmed up and got a bit more concise in my Julia-isms.  The algorithm used is just brute force, but it&#39;s Good Enough™ for this purpose.&#xA;&#xA;Re-using parseinput from Part 1.&#xA;&#xA;function mainpart2()&#xA;    lhs, rhs = parseinput()&#xA;&#xA;    lhsfrequency = map(lhs) do l&#xA;        count(==(l), rhs)&#xA;    end&#xA;&#xA;    similarity = lhs .* lhsfrequency&#xA;&#xA;    println(&#34;Total similarity: &#34;, sum(similarity))&#xA;end&#xA;&#xA;mainpart2()&#xA;&#xA;#AdventOfCode #JuliaLang]]&gt;</description>
      <content:encoded><![CDATA[<p>I decided to do the <a href="https://adventofcode.com/2024">Advent of Code</a> in Julia, as a way of getting back into coding for fun.</p>

<h2 id="part-1" id="part-1">Part 1</h2>

<p>Given two lists of numbers, work out the distance between each entry in the list (after sorting the lists), then sum the distances to determine the “similarity”.</p>

<p>This is the first time I&#39;ve written Julia code since 2023-09 , so it involved a lot of referring to the documentation, and it&#39;s not really taking advantage of any Julia language specific features (like all code blocks automatically returning their last value).</p>

<pre><code class="language-julia"># Get the distance between two lists, after sorting them
function list_distances(lhs, rhs)
    lhs_sorted = sort(lhs)
    rhs_sorted = sort(rhs)

    return map(lhs_sorted, rhs_sorted) do left, right
        return abs(left - right)
    end
end

function parse_input(src = &#34;input.txt&#34;)
    # Format of src
    # #####   #####\n
    lhs = Vector{Int}(undef, 0)
    rhs = Vector{Int}(undef, 0)
    for line in eachline(src) 
        lhs_substr = line[1:5]
        rhs_substr = line[9:13]
        l = parse(Int, lhs_substr; base=10)
        r = parse(Int, rhs_substr; base=10)

        push!(lhs, l)
        push!(rhs, r)
    end
    return lhs, rhs
end

function main_part1()
    lhs, rhs = parse_input()

    list_dist = list_distances(lhs, rhs)

    total_dist = sum(list_dist)

    println(&#34;Total dist: &#34;, total_dist)
end

main_part1()
</code></pre>

<h1 id="part-2" id="part-2">Part 2</h1>

<p>For each entry in a list, determine how often it appears in a second list, then multiply the entry by that frequency – then sum these factors.</p>

<p>For this one, I was a bit more warmed up and got a bit more concise in my Julia-isms.  The algorithm used is just brute force, but it&#39;s Good Enough™ for this purpose.</p>

<p>Re-using <code>parse_input</code> from Part 1.</p>

<pre><code class="language-julia">
function main_part2()
    lhs, rhs = parse_input()

    lhs_frequency = map(lhs) do l
        count(==(l), rhs)
    end

    similarity = lhs .* lhs_frequency

    println(&#34;Total similarity: &#34;, sum(similarity))
end

main_part2()
</code></pre>

<p><a href="https://wizarth.com.au/tag:AdventOfCode" class="hashtag"><span>#</span><span class="p-category">AdventOfCode</span></a> <a href="https://wizarth.com.au/tag:JuliaLang" class="hashtag"><span>#</span><span class="p-category">JuliaLang</span></a></p>
]]></content:encoded>
      <guid>https://wizarth.com.au/advent-of-code-2024-day-1</guid>
      <pubDate>Sun, 26 Jan 2025 04:06:32 +0000</pubDate>
    </item>
  </channel>
</rss>