Advent of Code 2024 day 10, RPG edition

This is the tenth day of Advent of Code, let’s solve today’s puzzles with RPG.

The puzzle as well as the input data are available here.

The code is available here.

Part 1

We are provided with a (stream) file containing a topographic map.

We need to indentify hiking trails going from altitude 0 to 9.

We need to determine, for each position at altitude 0, how many position at altitude 9 we can reach following a hiking trail.

As usual, we read the input file with QSYS2.IFS_READ_UTF8 table function, we concatenate all lines with LISTAGG.

We locate each position with altitude 0. From each one, we look in all 4 directions for a position at altitude 1 and repeat the process until we reach altitude 9. Each time we reach altitude 9, we register the position of the end of the hiking trail. We then count the number of altitude 9 positions reached and reset the list for the next trailhead.

Here is the RPG code for part 1:

**free
ctl-opt dftactgrp(*no);  // We're using procedure so we can't be in the default activation group

dcl-pi *n;
  input char(50);
end-pi;

dcl-pr explore;
  pos int(10) value;
  search char(1) value;
end-pr;

dcl-pr process;
  pos int(10) value;
  search char(1) value;
end-pr;

dcl-c WIDTH 54;
dcl-c HEIGHT 54;
dcl-c LENGTH 2916;

dcl-s fileName varchar(50);
dcl-s data char(LENGTH);

dcl-s index int(10) inz(1);
dcl-s trailheads int(5) dim(*auto:292); // Store reachable ends of trails from current traihead
dcl-s result int(20) inz(0);

fileName = %trim(input);

// Read the input data from the IFS, concatenating all lines
exec sql select listagg(line) into :data from table(qsys2.ifs_read_utf8(path_name => :fileName));

//  Search first trailhead 
index = %scan('0':data);

dou index = 0;
  
  explore(index:'1');   // find 1 around current position
  result += %elem(trailheads);  // append number of trail ends from current trailhead
  %elem(trailheads) = 0;  // reset trail ends
  if index = LENGTH;    // If we're not on the last position, find next 0
    index = 0;
  else;
    index = %scan('0':data:index+1);
  endif;
enddo;

snd-msg *info 'Result: ' + %char(result) %target(*pgmbdy:1); // Send message with answer

*inlr = *on;
return;

dcl-proc explore;

dcl-pi *n;
  pos int(10) value;
  search char(1) value;
end-pi;
  
  dcl-s line int(5);
  dcl-s col int(5);

  line = %div(pos-1:WIDTH)+1;
  col = %rem(pos-1:WIDTH)+1;

  // explore up
  if line > 1;
    process(pos-WIDTH:search);
  endif;

  // explore right
  if col < WIDTH;
    process(pos+1:search);
  endif;

  // explore down
  if line < HEIGHT;
    process(pos+WIDTH:search);
  endif;

  // explore left
  if col > 1;
    process(pos-1:search);
  endif;

end-proc;

dcl-proc process;

dcl-pi *n;
  pos int(10) value;
  search char(1) value;
end-pi;
dcl-s target char(1);

target = %subst(data:pos:1);
if target = search;    // If the position is the requested elevation
  if search = '9';     // If we are at the end of the trail
    if not(pos in trailheads);   // IF the trail end hasn't already been registered
      trailheads(*next) = pos;   // add the trail end to the list
    endif;
  else;                // If we are not at the end of the trail
    explore(pos:%char(%int(search)+1));  // Explore from here for the next elevation level
  endif;
endif;

end-proc;

Part 2

In part 2, we count the total number of hiking trails going from altitude 0 to altitude 9.

Instead of registering the positions of the end of the trail, we just count how many times we reach altitude 9.

**free
ctl-opt dftactgrp(*no);  // We're using procedure so we can't be in the default activation group

dcl-pi *n;
  input char(50);
end-pi;

dcl-pr explore;
  pos int(10) value;
  search char(1) value;
end-pr;

dcl-pr process;
  pos int(10) value;
  search char(1) value;
end-pr;

dcl-c WIDTH 54;
dcl-c HEIGHT 54;
dcl-c LENGTH 2916;

dcl-s fileName varchar(50);
dcl-s data char(LENGTH);

dcl-s index int(10) inz(1);
dcl-s result int(20) inz(0);

fileName = %trim(input);

// Read the input data from the IFS, concatenating all lines
exec sql select listagg(line) into :data from table(qsys2.ifs_read_utf8(path_name => :fileName));

index = %scan('0':data);

dou index = 0;
  explore(index:'1');
  if index = LENGTH;
    index = 0;
  else;
    index = %scan('0':data:index+1);
  endif;
enddo;

snd-msg *info 'Result: ' + %char(result) %target(*pgmbdy:1); // Send message with answer

*inlr = *on;
return;

dcl-proc explore;

dcl-pi *n;
  pos int(10) value;
  search char(1) value;
end-pi;
  
  dcl-s line int(5);
  dcl-s col int(5);

  line = %div(pos-1:WIDTH)+1;
  col = %rem(pos-1:WIDTH)+1;

  // explore up
  if line > 1;
    process(pos-WIDTH:search);
  endif;

  // explore right
  if col < WIDTH;
    process(pos+1:search);
  endif;

  // explore down
  if line < HEIGHT;
    process(pos+WIDTH:search);
  endif;

  // explore left
  if col > 1;
    process(pos-1:search);
  endif;

end-proc;

dcl-proc process;

dcl-pi *n;
  pos int(10) value;
  search char(1) value;
end-pi;
dcl-s target char(1);

target = %subst(data:pos:1);
if target = search;
  if search = '9';
    result += 1;
  else;
    explore(pos:%char(%int(search)+1));
  endif;
endif;

end-proc;