Advent of Code 2022 in APL Day 1 to 3

December 6, 2025

TechnologyAPLProgrammingAdvent-Of-CodeComputer Science

The Advent of Code is a yearly series of (christmas-themed) programming challenges. To learn a new programming languages, solving these is a great start; As i am doing here with APL.

APL is a programming Language from the 60s, originally intended to replace mathematical syntax. For example, instead of a sum

∑k=1N1k2\sum_{k=1}^N \frac{1}{k^2}

one would write

001+/1÷⍳N*2

Explanation:

Symbols
Meaning
⍳Nis a vector of natural numbers (1,…,N)(1, \dots, N)
1÷⍳N*2then is the vector (1,14,…,1N2)\left( 1, \frac{1}{4}, \dots, \frac{1}{N^2} \right)
+/is a sum-reduction, i.e. every element of the argument-vector is summed-up

I am currently on day 8 of Year 2022 in APL. The current state is on Github.

Day 1

Credit: Link

Challenge

We must find the Elf carrying the most Calories and report (output) that maximum total Calorie count. The input is a list of numbers, where each number represents the Calories of a food item. Blank Lines seperate the Elves. Example:

0011000
0022000
0033000
004
0054000
006
0075000
0086000
009
0107000
0118000
0129000
013
01410000

Part 2

In the Advent Of Code, there is always a second challenge, which introduces a complication: Now, we need to find the top-3 elves and compute the total calories between them.

Implementation

We read the input into a vector of vectors, where each entry in the outer vector is an elve, and the inner vectors contain the calories.

001input ← ⊃⎕NGET '/home/fabian/misc/apl/aoc2022/d1_input.txt' 1 ⍝ Lines as a vector
002mask ← (≢¨ input) ≠ 0 ⍝ Detect emptys 1 for value else 0
003nums ← {⍵≡'' : 0 ⋄ ⍎⍵}¨ input ⍝ Convert to flat vector of numeric values
004diffMask ← mask ∧ ~0,¯1↓mask ⍝ Diffs
005grouped ← diffMask ⊂ nums ⍝ After each 1 in the diff, split into sub vector
006sums ← +/¨grouped ⍝ Sum each sub vector
007⌈/sums ⍝ Get and print maximum
008+/ 3↑sums[⍒sums] ⍝ Sum of Top 3 Values

Explanation:

Symbol / Expression
Meaning
≢Tally. Returns the number of elements in a vector. For character vectors, this is the string length.
(≢¨ input)Applies ≢ to each element of input, producing a vector of string lengths.
(≢¨ input) ≠ 0Compares each length to 0. Produces 1 for non-empty strings and 0 for empty strings.
mask ← (≢¨ input) ≠ 0Creates a boolean mask indicating where input elements are non-empty.
~Logical NOT. Flips 0 ↔ 1.
↓Drop. Removes elements from the beginning (positive) or end (negative) of a vector.
¯1↓maskDrops the last element of mask.
0,¯1↓maskPrepends a 0 to the shortened mask, shifting it right by one position.
~0,¯1↓maskLogical NOT of the shifted mask.
mask ∧ ~0,¯1↓maskLogical AND. True where a non-empty element follows an empty one (or the start). This marks the start of a new group.
diffMask ← mask ∧ ~0,¯1↓maskA “difference mask” identifying the first element of each contiguous run of values.
⊂Partitioned Enclose. Groups elements of the right argument based on markers in the left argument.
diffMask ⊂ numsGroups nums into sub-vectors, starting a new group wherever diffMask is 1.
grouped ← diffMask ⊂ numsResult: a nested vector where numeric values are grouped according to runs of non-empty input entries.
sums ← +/¨grouped Now we can apply the sum-reduction to each group
⌈/sumsFinally we use a maximum reduction to get the result for part 1
⍒sumsReturns the indices, which would sort the vector sums descending
sums[⍒sums]So this is the sorted vector
+/ 3↑sums[⍒sums] And we get part 2 by applying a sum-reduction to the top-3 (3↑) elements

Day 2

Credit: Link

Challenge

The task involves calculating your total score in a multi-round Rock Paper Scissors tournament based on an encrypted Strategy Guide. This guide is interpreted in two different ways (Part One and Part Two). Our Input is the result of each game as lines in a file:

001A Y
002B X
003C X
004...

Part One: Simple Mapping (Shape-to-Shape)

In this interpretation, the second column directly indicates the shape you should play.

Column 1 (Opponent)
Column 2 (You)
A = Rock (1 pt)X = Rock (1 pt)
B = Paper (2 pts)Y = Paper (2 pts)
C = Scissors (3 pts)Z = Scissors (3 pts)

Scoring Rules:

  • Outcome: Loss (0 pts), Draw (3 pts), Win (6 pts).
  • Total Score: Sum of Your Shape Score + Outcome Score for every round.

Part Two: Decrypted Mapping (Opponent + Required Outcome)

The second column is re-interpreted to indicate the required outcome of the round, meaning you must choose the shape that achieves that result.

Column 1 (Opponent)
Column 2 (Required Outcome)
A = RockX = Loss (0 pts)
B = PaperY = Draw (3 pts)
C = ScissorsZ = Win (6 pts)

Scoring Rules:

  • You must first determine the correct shape to play (Rock, Paper, or Scissors) to get the required outcome.
  • Total Score: Sum of Your Chosen Shape Score + Outcome Score for every round.

Implementation

The implementation plays into APLs strengths: We create a function Score, which we apply to the input-vector; then we take the sum.

001input ← ⊃⎕NGET '/home/fabian/misc/apl/aoc2022/d2_input.txt' 1 ⍝ Lines as a vector
002
003Score ← {
004 o ← 'ABC'⍳⊃⍵[1]
005 m ← 'XYZ'⍳⊃⍵[3]
006 shape ← m
007 outcome ← (m=o)×3 ⍝ Draw
008 outcome +← ((m-o)∊1 ¯2)×6 ⍝ Win
009 shape + outcome
010}
011
012+/ Score ¨ d2_input ⍝ Apply to vec and sum
013
014Score2 ← {
015 o ← 'ABC'⍳⊃⍵[1]
016 outcome ← 'XYZ'⍳⍵[3]
017 m ← (outcome=2) × o ⍝ Draw => same shape
018 m +← (outcome=3) × 1+3|o ⍝ Win => next shape
019 m +← (outcome=1) × 1+3|o-2 ⍝ Lose => previous shape
020 shape ← m
021 outcome ← (outcome-1) × 3
022 shape + outcome
023}
024
025+/ Score2 ¨ input

Day 3

Credit: Link

Challenge

The first task is to identify the single item type that was incorrectly packed into both compartments of each individual rucksack. Each line in the input represents one rucksack. The line is split exactly in half to form Compartment 1 (first half) and Compartment 2 (second half). Goal: Find the only item type (single letter) that exists in both Compartment 1 and Compartment 2 for that rucksack. The output is the sum the priorities of all these common item types across every rucksack.

The priority value for an item type is defined as:

  • Lowercase (a-z): Priorities 1 through 26
  • Uppercase (A-Z): Priorities 27 through 52

Part Two: Group Badges

In Part Two, the objective changes from finding a misplaced item within a single rucksack to identifying a unique Group Badge item that is common among the rucksacks of a group of three Elves. While Part One involves finding the intersection between two equal compartments of one rucksack, Part Two requires finding the item type present in the intersection of the contents of three full rucksacks.

Implementation

The APL implementation leverages set operations to efficiently find the required common characters. We first create the Score function, which maps any item character (a-z, A-Z) to its numerical priority using the Index Of primitive (⍳). For Part One, we apply the ProcessRucksack function to each line, which splits the string into two halves using dyadic slicing, finds the single common element with the Intersection primitive (∩), and applies the Score function before summing the results using Reduction (+/). For Part Two, we structure the input into three-line groups using the Partition operator (⊂), and the ProcessGroup function then uses Intersection Reduction (∩/) to quickly find the common badge character among the three rucksacks before we sum all the badge priorities.

001⎕IO ← 0
002
003input ← ⊃⎕NGET '/home/fabian/misc/apl/aoc2022/d3_input.txt' 1 ⍝ Lines as a vector
004
005Score ← {
006 1 + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'⍳⊃⍵ ⍝ Maps a->1, b->2 ... z->26, A->27 ... Z->52
007}
008
009ProcessRucksack ← {
010 len ← ⍴⍵
011 mid ← len ÷ 2
012 dupes ← ∪ (mid↑⍵) ∩ (mid↓⍵) ⍝ Substring: First Half mid↑⍵; Intersection
013 +/ ¨ Score +/ ¨ dupes
014}
015
016⎕ ← output ← +/ ProcessRucksack ¨ input ⍝ Apply to each Rucksack
017
018mask ← (⍴ input) ⍴ 1 0 0 ⍝ Create mask = 1 0 0 1 0 0 ... for grouping
019groups ← mask ⊂ input ⍝ Put 3 rucksacks into one group
020
021ProcessGroup ← {
022 code ← ∪ ⊃ ∩/ ⍵ ⍝ Intersect and get character
023 Score code ⍝ Evaluate character
024}
025
026⎕ ← output2 ← +/ ProcessGroup ¨ groups ⍝ Sum evaluation for each group
027