Advent of Code 2022: Day 5

The two tasks in this problem again differ only in a small element, how multiple crates are moved from one column to another. This difference is captured in a procedure, passed to a main control procedure, process_crates:

The manipulation of the crates requires some further operations on the list data structure, treating each list as a single- or double-ended queue, where appropriate:

The more complex part of the problem is to decode the input file format, which falls into two parts:

  1. the definition and layout of the crates on columns.
  2. the definition of the moves.

For the first part, we rely on the crates all being of the form "[N]", where N is a single-letter name for the crate. A new string-scanning construct is find:

The positions returned by find are used to determine the columns for each crate from the input.

For the second part, the lines follow a standard format, starting with "move", and are processed like the ranges from Day 4.

The following line is interesting, in how it extracts the top crate from each column, concatenating them all into a string:

  every result ||:= pull(!crates) | " "

Final Program

procedure main(inputs)
  local filename

  if *inputs = 1 then {
    filename := inputs[1]

    # Part 1 solution
    write("Part 1 top crates are: ", process_crates(filename, make_move_singly))
    # Part 2 solution
    write("Part 2 top crates are: ", process_crates(filename, make_move_multiple))
  } else {
    write("Provide a filename of data")
  }
end

procedure read_crates(file)                       # <1>
  local column, crate, crates, line, posn

  crates := []

  every line := !file do {
    if find("[", line) then {                     # <2>
      every posn := find("[", line) do {          # <3>
        column := (posn-1)/4 + 1                  # <4>
        crate := line[posn+1]                     # <5>
        # put crate on column
        while *crates < column do {               # <6>
          put(crates, [])
        }
        push(crates[column], crate)               # <7>
      }
    } else {                                      # <8>
      return crates
    }
  }

  stop ("Invalid file format")
end

procedure make_move_singly(crates, move_count, move_from, move_to)
  every 1 to move_count do  {
    put(crates[move_to], pull(crates[move_from]))
  }
end

procedure make_move_multiple(crates, move_count, move_from, move_to)
  local hook

  hook := []
  every 1 to move_count do  {
    push(hook, pull(crates[move_from]))
  }
  every put(crates[move_to], !hook)
end

procedure process_crates(filename, make_move_proc)
  local file, line
  local crates, move_count, move_from, move_to
  local result

  file := open(filename) | stop("Could not open file")
  crates := read_crates(file)                                   # <9>

  # process moves
  every line := !file do {                                      # <10>
    line ? if =("move ") then {
      move_count := tab(many(&digits))
      =(" from ")
      move_from := tab(many(&digits))
      =(" to ")
      move_to := tab(many(&digits))
      make_move_proc(crates, move_count, move_from, move_to)    # <11>
    }
  }

  close(file)

  result := ""
  every result ||:= pull(!crates) | " "                         # <12>
  return result
end
  1. Given a file, returns a list of columns, with the names of all the crates.
  2. Checks if the line is part of the crate-definition.
  3. If it is, then loop through the position of all crates.
  4. Some mathematics is used to find the column number ...
  5. ... and the crate name.
  6. Make sure there are enough crate definitions in the crates list.
  7. Add the crate to the appropriate column.
  8. When the line is not a crate-definition, return the crates list.
  9. First, read in the crate definitions ...
  10. ... then process each remaining line, looking for "move" definitions.
  11. Process each move in turn.
  12. Extract the top crate name of each column for the final result, or empty space for an empty column.

Page from Peter's Scrapbook, output from a VimWiki on 2024-01-29.