[[{“value”:”This is the nineth 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 disk map. It is a single line containing alternatively files and free space sizes (one digit for each).
We need to defragment the disk by moving blocks from files at the end of the disk to the free space at the begining of the disk.
We then need to calculate the filesystem checksum (see the puzzle for the exact definition).
As usual, we read the input file with QSYS2.IFS_READ_UTF8 table function.
We defragment and compute the checksum in one pass by processing the disk map from both ends: we process alternatively the files from the lelft and fill the free space with blocks from the right.
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-c LENGTH 19999;
dcl-s fileName varchar(50);
dcl-s data char(LENGTH);
dcl-s position int(10) inz(0);
dcl-s leftID int(10) inz(0);
dcl-s rightID int(10) inz(9999);
dcl-s leftIndex int(10) inz(1);
dcl-s rightIndex int(10) inz(19999);
dcl-s leftCount int(3);
dcl-s rightCount int(3);
dcl-s i int(3);
dcl-s result int(20) inz(0);
fileName = %trim(input);
// Read the input data from the IFS, concatenating all lines
exec sql select line into :data from table(qsys2.ifs_read_utf8(path_name => :fileName));
leftCount = %int(%subst(data:1:1));
rightCount = %int(%subst(data:19999:1));
dow leftIndex < rightIndex;
for i = 1 to leftcount;
result += position*leftID;
position += 1;
endfor;
leftIndex += 1;
leftCount = %int(%subst(data:leftindex:1));
for i = 1 to leftCount;
if rightCount = 0;
rightIndex -= 2;
rightCount = %int(%subst(data:rightIndex:1));
rightID -= 1;
endif;
result += position*rightID;
rightCount -= 1;
position += 1;
endfor;
leftIndex += 1;
leftCount = %int(%subst(data:leftIndex:1));
leftID += 1;
enddo;
for i = 1 to rightCount;
result += position*rightID;
position += 1;
endfor;
snd-msg *info ‘Result: ‘ + %char(result) %target(*pgmbdy:1); // Send message with answer
*inlr = *on;
return;
Part 2
In part 2, we change the defragmentation rules:
we can only move a whole file from the end of the disk to a free space
we start moving files from the end of the disk
we move a file to the leftmost free space big enough for the file
if there is no free space for a file, it is not moved at all
We solve this puzzle in 3 passes:
we compute the initial begining position of each file
we perform the actual defragmentation be changing the begining position of each file
we compute the checksum
**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-c LENGTH 19999;
dcl-s fileName varchar(50);
dcl-s data char(LENGTH);
dcl-s position int(10) inz(0);
dcl-s leftID int(10) inz(0);
dcl-s rightID int(10) inz(9999);
dcl-s leftIndex int(10) inz(1);
dcl-s rightIndex int(10) inz(19999);
dcl-s leftCount int(3);
dcl-s rightCount int(3);
dcl-s i int(5);
dcl-s j int(5);
dcl-s positions int(10) dim(10000);
dcl-s fillings int(10) dim(9999);
dcl-s result int(20) inz(0);
fileName = %trim(input);
// Read the input data from the IFS, concatenating all lines
exec sql select line into :data from table(qsys2.ifs_read_utf8(path_name => :fileName));
// Calculate initial position of each File
for i = 1 to 10000;
positions(i) = position;
if i < 10000;
position += %int(%subst(data:2*(i-1)+1:1))+%int(%subst(data:2*(i-1)+2:1));
endif;
endfor;
// Defragment
for i = 19999 downto 3 by 2;
rightCount = %int(%subst(data:i:1));
j = 2;
leftCount = %int(%subst(data:j:1));
dow j<=i and rightCount > leftCount;
j += 2;
leftCount = %int(%subst(data:j:1));
enddo;
if leftCount >= rightCount;
positions(%div(i+1:2)) = positions(%div(j:2))+%int(%subst(data:j-1:1))+fillings(%div(j:2));
fillings(%div(j:2)) += rightCount;
leftCount -= rightCount;
%subst(data:j:1) = %char(leftCount);
endif;
endfor;
// Compute checksum
for i = 1 to 10000;
position = positions(i);
for j = 1 to %int(%subst(data:2*(i-1)+1:1));
result += (i-1)*position;
position += 1;
endfor;
endfor;
snd-msg *info ‘Result: ‘ + %char(result) %target(*pgmbdy:1); // Send message with answer
*inlr = *on;
return;”}]] Read More