{ datagubbe }


datagubbe.se » advent of shell

Advent of Shell

I solved Advent of Code 2020, day 1, part 1 in pure AmigaShell. No ARexx! No cheating!

Approach

Forget head, tail, sed and other such Unix frivolities - or syntactic sugar like "for" and "while". Conditional branching with labels should be enough for everyone!

The tools used are mostly sort, which always sorts in ascending order, and eval, which evaluates mathematical expressions and bitwise logical operations.

For fetching values from the data, I opted for the line editor, edit, which I use to extract a value from a row into a temporary file which is then read into a variable. I also use edit to treat the data file as a list, deleting the first value after each completed loop.

It does take a while to run on my 14 MHz Amiga 1200. I didn't bother timing it, but probably at least a minute.

See a photo of it running (JPG, ~350K)

The code

Click here to show the code without comments.

; Copy data file to RAM disk
copy 1.dat t:

; Work in RAM disk
cd t:

; Sort the data
sort 1.dat 1.sort numeric

; The file 1.outer will be the "list"
; for the outer loop.
copy 1.sort 1.outer

; Editor command for extracting
; the first value of a "list" file.
echo "d 2 1000" > to_next

; Editor command for deleting the first line
; of a file, I.E. removing the first element
; in a "list".
echo "d 1 1" > rem_1st

; Keep these commands in memory in order
; to minimize disk access.
resident c:edit pure=force
resident c:eval pure=force
resident c:type pure=force
resident c:list pure=force

skip outer

; The outer loop
lab outer
  ; Extract first value from list.
  edit 1.outer v.outer with to_next > nil:

  ; Check if we have a value.
  ; If not, skip to "fail", because then we're
  ; at the last item and haven't found any
  ; matching values.
  set outersize=`list 1.outer lformat="%L"`
  if $outersize eq "empty"
    skip fail
  endif

  ; Remove the first item from the list.
  edit 1.outer with rem_1st > nil:

  ; Store the value in a variable
  set outerval=`type v.outer`

  ; Prepare a fresh list for the inner loop.
  copy 1.sort 1.inner

  ; Skip to inner loop.
  skip inner

; The inner loop.
lab inner
  ; Extract first value from list.
  edit 1.inner v.inner with to_next > nil:

  ; Check if we have a value.
  ; If not, skip back to the outer loop, because
  ; we're at the last item and haven't found any
  ; matching values.
  set innersize=`list v.inner lformat="%L"`
  if $innersize eq "empty"
    skip outer back
  endif

  ; Remove first item from list.
  edit 1.inner with rem_1st > nil:

  ; Store the value in a variable
  set innerval=`type v.inner`

  ; Add outer and inner value
  set res=`eval $innerval + $outerval`

  ; Skip back to the next outer value if
  ; we've exceeded the target value.
  if val $res gt 2020
    skip outer back
  endif

  ; If we've hit the target value, calculate
  ; the final result and skip to the end
  ; (I.E. break the loop).
  if val $res eq 2020
    set finalres=`eval $innerval * $outerval`
    skip end
  endif

  ; No match found, continue the inner loop
  skip inner back

lab fail
  echo "No matches found in data."

lab end
  echo "Final result: $finalres"

Download the code (text, ~1K)