Advent of Code APL 2022

Working on Advent of Code 2022 in APL
APL
Advent of Code
Author

Isaac Flath

Published

December 2, 2022

]box on
]rows on
Was ON
Was OFF

In this blog post I will supply my solutions to Advent of Code 2022 as I work through them in APL. I don’t expect to keep up with doing them every day, but will work on them as I have time and keep adding to this post.

1 Day 1

1.1 Solution

f ← ,⎕CSV 'day1_input.txt' ⍬4
sums ← {+/¨ (≢¨⍵) ⊆⊢ ⍵} f
part1 ← ⌈/ sums
part2 ← +/ 3↑sums[⍒sums]
'Part 1 Solution : ' part1
'Part 2 Solution : ' part2
┌──────────────────┬─────┐
│Part 1 Solution : │71780│
└──────────────────┴─────┘
┌──────────────────┬──────┐
│Part 2 Solution : │212489│
└──────────────────┴──────┘

1.2 Explanation

Shared Code:

  • (≢¨f) : Create a mask of items we can use to separate inventories of each elf
  • (≢¨⍵) ⊆⊢ ⍵ : Use mask to break data into sub-arrays for each elf
  • +/¨ (≢¨⍵) ⊆⊢ ⍵ : Sum inventory of each elf

Part 1:

  • ⌈/ : Get maximum value from array created above

Part 2:

  • sums[⍒sums] : Sort array in descending order
  • 3↑sums[⍒sums] : Get first (largest) 3 items in array
  • +/ 3↑sums[⍒sums] : Sum the first (largest) 3 items in array

2 Day 2

2.1 Solution

f ← ⎕CSV 'day2_input.txt' ⍬4
lookup ← {+/ S[C ⍳ ,⍵]}

C S←↓⍉9 2⍴'A X' 4 'B X' 1 'C X' 7 'A Y' 8 'B Y' 5 'C Y' 2 'A Z' 3 'B Z' 9 'C Z' 6
C
S
part1 ← lookup f

C S←↓⍉9 2⍴'A X' 3 'A Y' 4 'A Z' 8 'B X' 1 'B Y' 5 'B Z' 9 'C X' 2 'C Y' 6 'C Z' 7
C
S
part2 ← lookup f
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│A X│B X│C X│A Y│B Y│C Y│A Z│B Z│C Z│
└───┴───┴───┴───┴───┴───┴───┴───┴───┘
4 1 7 8 5 2 3 9 6
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│A X│A Y│A Z│B X│B Y│B Z│C X│C Y│C Z│
└───┴───┴───┴───┴───┴───┴───┴───┴───┘
3 4 8 1 5 9 2 6 7
'Part 1 Solution : ' part1
'Part 2 Solution : ' part2
┌──────────────────┬─────┐
│Part 1 Solution : │13446│
└──────────────────┴─────┘
┌──────────────────┬─────┐
│Part 2 Solution : │13509│
└──────────────────┴─────┘

2.2 Explanation

Shared Code:

  • C ⍳ ,f : Look up each item in f and find its index location in C
  • S[C ⍳ ,⍵] : Use indexes to get array of scores
  • {+/ S[C ⍳ ,⍵]} : Sum array

Part 1:

  • Define mapping of each possibility to score
  • Use function defined above

Part 2:

  • Define mapping of each possibility to score
  • Use function defined above

3 Day 3

3.1 Solution

f ← (⎕A,⍨⎕C ⎕A)∘⍳¨⊃⎕NGET'day3_input.txt'1

part1 ← +/1↑¨{(2÷⍨⍴¨⍵)(↑∩↓)¨⍵}f

part2 ← +/1↑¨∩/{(3÷⍨≢⍵)3⍴⍵}f
'Part 1 Solution : ' part1
'Part 2 Solution : ' part2
┌──────────────────┬──────┐
│Part 1 Solution : │┌────┐│
│                  ││7785││
│                  │└────┘│
└──────────────────┴──────┘
┌──────────────────┬──────┐
│Part 2 Solution : │┌────┐│
│                  ││2633││
│                  │└────┘│
└──────────────────┴──────┘

3.2 Explanation

Shared Code:

  • ⊃⎕NGET'day3_input.txt'1 : Load the data
  • (⎕A,⍨⎕C ⎕A) : Get alphabet (lower and upper case)
  • ∘⍳¨ : Index into each piece of data to find position in alphabet

Part1:

  • ⍴¨w : Get length of each elf’s inventory
  • (2÷⍨⍴¨w) : Divide by 2 to get half-way point
  • {(2÷⍨⍴¨w) (↑∩↓)¨ ⍵} : Function to the intersection of the first and last halves of each elf’s inventory
  • 1↑¨ {(2÷⍨⍴¨w) (↑∩↓)¨ ⍵} f : de-dupe by keeping only 1st result for each elf
  • +/1↑¨∩/{(3÷⍨≢⍵)3⍴⍵}f : Sum

Part2:

  • (3÷⍨≢⍵) : Get number of groups of elves
  • {(3÷⍨≢⍵)3⍴⍵ : Reshape data to be a n_groups x 3 elves matrix
  • ∩/{(3÷⍨≢⍵)3⍴⍵}f : Get the intersection (items that all 3 elves have)
  • 1↑¨∩/{(3÷⍨≢⍵)3⍴⍵}f : de-dupe by keeping only 1st result for each elf
  • +/1↑¨∩/{(3÷⍨≢⍵)3⍴⍵}f : Sum

4 Day 4

4.1 Solution

f ← {⎕csv⍠'Separator' '-'⊢⍵⍬4}¨↓⍉⎕csv'day4_input.txt'
c1 c2 c3 c4 ← ↓⍉⊃,/f
fn ← {a1 a2←⍺ ⋄ w1 w2←⍵ ⋄ a1≤w1 ∧ a2≥w2}

part1 ← +/ (c1 c2 fn c3 c4) ∨ c3 c4 fn c1 c2
part2 ← +/ (c1 c2 fn c3 c3) ∨ c3 c4 fn c1 c1
+/c1 c2 fn c3 c4
+/c3 c4 fn c1 c2
293
333
'Part 1 Solution : ' part1
'Part 2 Solution : ' part2
┌──────────────────┬───┐
│Part 1 Solution : │599│
└──────────────────┴───┘
┌──────────────────┬───┐
│Part 2 Solution : │928│
└──────────────────┴───┘

4.2 Explanation

Shared Code:

  • Read File

    • ⎕csv'day4_input.txt' ⍬4 : Read CSV file

    • ↓⍉⎕csv'day4_input.txt' Transpose and put into format for processing

    • {⎕csv⍠'Separator' '-'⊢⍵⍬4}¨↓⍉⎕csv'day4_input.txt' : Process each column as a nested csv with - as the separator to split out start/end numbers

    • ⊃,/{⎕csv⍠'Separator' '-'⊢⍵⍬4}¨↓⍉5↑⎕csv'day4_input.txt' : Convert nested arrays into flat 2d matrix

    • ↓⍉⊃,/{⎕csv⍠'Separator' '-'⊢⍵⍬4}¨↓⍉5↑⎕csv'day4_input.txt' : Reformat into column vectors for destructured assignment

  • Format Matrix

    • ⊃,/f : Convert nested arrays into flat 2d matrix
    • ↓⍉⊃,/f : Create separate column vectors for destructured assignment
  • Boolean logic

    • a1 a2 ← ⍺ ⋄ w1 w2 ← ⍵ : Destructured assignment to split out function arguments
    • (a1 ≤ w1 ∧ a2 ≥ w2) : Boolean logic for problem

Part 1:

  • c1 c2 fn c3 c4 : Does the 1st elf’s assignment fully enclose the 2nd elf’s assignment?
  • c3 c4 fn c1 c2 : Does the 2nd elf’s assignment fully enclose the 1st elf’s assignment?
  • (c1 c2 fn c3 c4) ∨ c3 c4 fn c1 c2 : Combine with or logic
  • +/ (c1 c2 fn c3 c4) ∨ c3 c4 fn c1 c2 : Sum booleans to get part 1 solution

Part 2:

  • c1 c2 fn c3 c3 : Does the 1st elf’s assignment enclose the 2nd elf’s lowest assignment?
  • c3 c4 fn c1 c1 : Does the 2nd elf’s assignment enclose the 1st elf’s lowest assignment?
  • (c1 c2 fn c3 c3) ∨ c3 c4 fn c1 c1 : Combine with or logic
  • +/ (c1 c2 fn c3 c3) ∨ c3 c4 fn c1 c1 : Sum booleans to get part 2 solution

5 Day 5

5.1 Solution

board moves ← (∊~0=⍴¨f)⊆(f←⊃⎕NGET'day5_input.txt'1)

moves ← ⌽↓(6⍴0 1)/⎕csv⍠'Separator' ' '⊢moves⍬4

board ← ¯1↓⎕csv⍠'Widths' ((8⍴4),3)⊢board⍬4
board ← ' '∘(1↓,⊢⍤/⍨1(⊢∨⌽)0,≠)¨↓⍉⊃¨1↓¨board

step ← {(move from to)←⍺ ⋄ ((⍺⍺ move↑⊃⍵[from])∘,¨@to)(move∘↓¨@from)⍵}
⎕ ← 'part 1: ',⊃¨⊃ ⌽step/moves,⊂board

⎕ ← 'part 2: ',⊃¨⊃ ⊣step/moves,⊂board
part 1: JRVNHHCSJ
part 2: GNFBSBJLH

5.2 Explanation

Shared Code:

  • File Processing

    • (f←⊃⎕NGET'day5_input.txt'1) : Read file
    • (∊~0=⍴¨f) Create boolean mask indicating where the board and moves section split is
    • (∊~0=⍴¨f)⊆(f←⊃⎕NGET'day5_input.txt'1) : Use boolean mask to partition board and moves to separate variables
  • Clean Moves Input

    • ⎕csv⍠'Separator' ' '⊢moves⍬4 : Process moves data as a CSV with space as separator
    • (6⍴0 1)/⎕csv⍠'Separator' ' '⊢moves⍬4 : Remove the non-numeric columns with words in them
    • ↓(6⍴0 1)/⎕csv⍠'Separator' ' '⊢moves⍬4 : Change to vector of columns for processing
    • ⌽↓(6⍴0 1)/⎕csv⍠'Separator' ' '⊢moves⍬4 : Reverse so we can process as a reduction
  • Clean Board Input

    • ⊃¨1↓¨board : Strip brackets and unnest matrix
    • ↓⍉⊃¨1↓¨board: Format into vector of columns for processing
    • ' '∘(1↓,⊢⍤/⍨1(⊢∨⌽)0,≠)↓⍉⊃¨1↓¨board : Remove leading, trailing and duplicate blanks
  • Step Function:

    • (move from to)←⍺ : Break numeric arguments for move instructions into separate variables
    • ⍵[from] : Get the items in the “from” location
    • move↑⊃⍵[from] : Take only the move quantity from the items in the from location
    • (⍺⍺ move↑⊃⍵[from]) : Apply a function to the items in the from location before doing anything else
    • (⍺⍺ move↑⊃⍵[from])∘,¨@to) : Add the items in the from location to the to location
    • (move∘↓¨@from) : Drop the items being moved from the from location
    • {(move from to)←⍺ ⋄ ((⍺⍺ move↑⊃⍵[from])∘,¨@to)(move∘↓¨@from)⍵} : Combine for function definition

Part 1:

  • ⌽ step/moves,⊂board : Call the step function using a reduction across the moves. When moving the boxes reverse the lists so it simulates moving one box at a time.
  • ⊃¨⊃ ⌽ step/moves,⊂board : Take only the first element in each cell

Part 2:

  • ⌽ step/moves,⊂board : Call the step function using a reduction across the moves. When moving the boxes do not reverse (identity function) so it simulates moving a full stack at a time.
  • ⊃¨⊃ ⌽ step/moves,⊂board : Take only the first element in each cell

6 Day 6

6.1 Solution

f← ∊⎕CSV'day6_input.txt'
part1 part2 ← {¯1+⍵+⍵⍳⍨≢¨⍵∪/f}¨ 4 14
'Part 1 Solution : ' part1
'Part 2 Solution : ' part2
┌──────────────────┬────┐
│Part 1 Solution : │1760│
└──────────────────┴────┘
┌──────────────────┬────┐
│Part 2 Solution : │2974│
└──────────────────┴────┘

6.2 Explanation

Shared Code:

  • f← ∊⎕CSV'day6_input.txt' : Read data file
  • ∪/f : Get unique characters from input data
  • ⍵∪/f : Instead of unique characters from input data, unique characters in each group of characters from input data.
  • ≢¨⍵∪/f : Get number of unique characters are in each group
  • ⍵⍳⍨≢¨⍵∪/f : Look for the first group where the number of unique characters is equal to
  • ¯1+⍵+⍵⍳⍨≢¨⍵∪/f : Get ending index of group instead of starting location of group

Part 1:

  • Apply function to window size of 4

Part 2:

  • Apply function to window size of 14

7 The End

I have decided not to finish advent of code in APL for now. There are several reasons for this:

7.1 Personal

  • I went to a dance competition for 4 days an won! I had very ambitious plans to keep up while at the competition. In reality I didn’t even open my laptop while there.
  • My family is visiting and I am spending time with them

7.2 APL

The time it takes to solve each in APL is getting much longer. There are two main things that are super common in advent of code that APL does not handle well. This was a good learning experience.

  • APL seems to be clunky at handling data cleaning, which many of these challenges from here on out include.

  • APL seems to handle flat (ie numeric) arrays extremely well. Nested arrays such as text are not as clean. Many of the problems require text data as well.

This is useful to know. Part of the reason I was interested in working on this is APL was to understand what I would and would not use the language for. Many proponents of APL use it for almost everything - that’s not I think is best in my opinion.

I still plan to use APL as a tool for thought when reading and implement research papers. But once I understand the contents of the paper I will move to another language to apply the concept to real world data.