[[{“value”:”This is the fourth 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 word search. The only word to find is XMAS, it can be written in any direction (horizontal, vertical, diagonal, forware or backward).
We need to find how many XMAS are in the input data.
The IFS file can easily be read using QSYS2.IFS_READ_UTF8 table function. We concatenate each line into a single variable with the LISTAGG SQL function.
We then scan characters sequentially looking for an X.
If the character is an X, we look in 8 directions unless we’re to close to a border, for that, we keep track of the line and column we’re currently in. If we find the word XMAS, we increment the counter.
We could use %SUBST to access any character in the input, instead we’re using pointers for a (maybe?) slightly lighter syntax.
The procedure isXmas is responsible for looking for the word XMAS. Since we ‘flattened’ the input grid into a linear string, travelling in any direction, is just a matter of adding a given offset each time:
to go to the right, the offset is +1
to go to the left, the offset is -1
to go down, the offset is +WIDTH
to go up, the offset is -WIDTH
to go top down, the offset is WIDTH+1
etc…
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 isXmas ind;
offset int(10) value;
end-pr;
dcl-s fileName varchar(50);
dcl-c WIDTH 140;
dcl-c HEIGHT 140;
dcl-c LENGTH const(19600);
dcl-s data char(LENGTH);
dcl-s result int(10) inz(0);
dcl-s line int(10) inz(1);
dcl-s col int(10) inz(1);
dcl-s index int(10);
dcl-s pCurChar pointer;
dcl-s curChar char(1) based(pCurChar);
dcl-s pScanChar pointer;
dcl-s scanChar char(1) based(pScanChar);
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));
pCurChar = %addr(data);
for index = 1 to length;
if curChar = ‘X’;
if col <= WIDTH-3 and isXmas(1); // Checking to the right
result += 1;
endif;
if col <= WIDTH-3 and line <= HEIGHT-3 and isXmas(WIDTH+1); // Checking bottom right
result += 1;
endif;
if line <= HEIGHT-3 and isXmas(WIDTH); // checking down
result += 1;
endif;
if line <= HEIGHT-3 and col >= 4 and isXmas(WIDTH-1); // Checking bottom left
result += 1;
endif;
if col >= 4 and isXmas(-1); // Checking left
result += 1;
endif;
if col >= 4 and line >=4 and isXmas(-WIDTH-1); // Checking top left
result += 1;
endif;
if line >= 4 and isXmas(-WIDTH); // Checking up
result += 1;
endif;
if line >= 4 and col <= WIDTH-3 and isXmas(-WIDTH+1); // Checking top right
result += 1;
endif;
endif;
pCurChar += 1;
if col < WIDTH;
col += 1;
else;
col = 1;
line += 1;
endif;
endfor;
snd-msg *info ‘Result: ‘ + %char(result) %target(*pgmbdy:1); // Send message with answer
*inlr = *on;
return;
dcl-proc isXmas;
dcl-pi *n ind;
offset int(10) value;
end-pi;
pScanChar = pCurChar + offset;
if scanChar <> ‘M’;
return *off;
endif;
pScanChar += offset;
if scanChar <> ‘A’;
return *off;
endif;
pScanChar += offset;
if scanChar <> ‘S’;
return *off;
endif;
return *on;
end-proc;
Part 2
In part 2, we’ll use the same input as in part 1.
There was a misunderstanding, it is an X-MAS puzzle, not an XMAS puzzle so we need to find two MAS in the shape of an X.
For example:
M.S
.A.
M.S
or
M.M
.A.
S.S
This time, we will look for an A and check if it is the center of an X made with MAS.
Since A is the center of an X, we don’t need to look at the first and last lines and columns.
**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-s fileName varchar(50);
dcl-c WIDTH 140;
dcl-c HEIGHT 140;
dcl-c LENGTH const(19600);
dcl-s data char(LENGTH);
dcl-s result int(10) inz(0);
dcl-s line int(10) inz(2);
dcl-s col int(10) inz(2);
dcl-s index int(10);
dcl-s pCurChar pointer;
dcl-s curChar char(1) based(pCurChar);
dcl-s pScanChar1 pointer;
dcl-s scanChar1 char(1) based(pScanChar1);
dcl-s pScanChar2 pointer;
dcl-s scanChar2 char(1) based(pScanChar2);
dcl-s pScanChar3 pointer;
dcl-s scanChar3 char(1) based(pScanChar3);
dcl-s pScanChar4 pointer;
dcl-s scanChar4 char(1) based(pScanChar4);
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));
pCurChar = %addr(data)+WIDTH+1; // We start on the second column of the second line
for index = 1 to (WIDTH-2)*(HEIGHT-2); // We skip the first and last lines and columns
if curChar = ‘A’;
pScanChar1 = pCurChar – WIDTH – 1; // top left
pScanChar2 = pCurChar – WIDTH + 1; // top right
pScanChar3 = pCurChar + WIDTH – 1; // bottom left
pScanChar4 = pCurChar + WIDTH + 1; // bottom right
if (scanChar1 = ‘M’ and scanChar4 = ‘S’) or (scanChar1 = ‘S’ and scanChar4=’M’);
if (scanChar2 = ‘M’ and scanChar3 = ‘S’) or (scanChar2 = ‘S’ and scanChar3=’M’);
result += 1;
endif;
endif;
endif;
if col < WIDTH-1; // If we are not on the second to last column, we advance to the next column
col += 1;
pCurChar += 1;
else; // If we are on the second to last column, we skip to the second column of next line
col = 2;
line += 1;
pCurChar += 3;
endif;
endfor;
snd-msg *info ‘Result: ‘ + %char(result) %target(*pgmbdy:1); // Send message with answer
*inlr = *on;
return;”}]] Read More