<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Advent of Code 2021 Day 21 - A SAS Array/SQL-Based Solution in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Advent-of-Code-2021-Day-21-A-SAS-Array-SQL-Based-Solution/m-p/787051#M251395</link>
    <description>&lt;P&gt;&lt;FONT size="3"&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="'Tis the season to be coding..." style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/66929iB115DE2666620478/image-size/small?v=v2&amp;amp;px=200" role="button" title="adventofcode.jpg" alt="'Tis the season to be coding..." /&gt;&lt;span class="lia-inline-image-caption" onclick="event.preventDefault();"&gt;'Tis the season to be coding...&lt;/span&gt;&lt;/span&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="3"&gt;As &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/43560"&gt;@jmhorstman&lt;/a&gt;&amp;nbsp;did &lt;A href="https://communities.sas.com/t5/SAS-Programming/Holiday-Fun-The-Advent-of-Code-using-SAS/m-p/518967" target="_self"&gt;a few years back&lt;/A&gt;, thought I'd take a crack at a few of the &lt;A href="https://adventofcode.com/" target="_self"&gt;Advent of Code 2021&lt;/A&gt; challenges with SAS. Not sure whether to be proud or ashamed of them (&lt;EM&gt;maybe a little of both!&lt;/EM&gt;), but below is how I solved &lt;A href="https://adventofcode.com/2021/day/21" target="_self"&gt;today's Day 21 problem&lt;/A&gt; with SAS array-based (Part I) and SQL-based (Part II) solutions. &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="3"&gt;Imagine I could have tapped PROC FCMP to knock out a recursive solution for Part II, but I personally found the SQL-based one pretty easy to verify against the problem description, and&amp;nbsp;this a one-off problem where performance isn't a concern. Some of the &lt;A href="https://www.reddit.com/r/adventofcode/comments/rl6p8y/2021_day_21_solutions/" target="_self"&gt;solutions in other languages&lt;/A&gt; I reviewed employed more CS-type constructs - regex parsing, recursive functions, lambdas/closures, state vectors, dictionaries, hashing, iterators, maps, memoization and cache packages, decorators, etc. Interesting to see all of the different approaches to get the same answer, though! &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="3"&gt;My SQL solution did take about 16 seconds to run using SAS Studio on&amp;nbsp;&lt;A href="https://welcome.oda.sas.com/home" target="_self"&gt;SAS OnDemand for Academics&lt;/A&gt; (&lt;EM&gt;free, if you haven't tried it!&lt;/EM&gt;). Not too bad for an untuned program using SQL, but it'd be interesting to see how the SQL might perform on another system where more CPUs are available (for auto-scaling) and the MEMCACHE option is available for libraries.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SOLUTION-PART I&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;*==&amp;gt; Advent of Code 2021 Day 21 Part 1: SAS Array-Based Solution
     See https://adventofcode.com/2021/day/21 for problem description;
     
data _null_;                                                               * Advent of Code, Day 21 Part 1;
array pos(*) p1-p2; array score(*) score1-score2;                          * Players' positions, scores;
do i=1 to dim(pos); input @"position: " pos(i); end;                       * Read initial positions of players; 
do while(max(of score:)&amp;lt;1000);                                             * Game over when a player reaches 1000;
  p=coalesce((p+1)*(p&amp;lt;dim(pos))+(p=dim(pos)),1);                           * Determine current player;
  do t=1 to 3; toss+1; pos(p)=mod((pos(p)+mod(toss-1,100)+1)-1,10)+1; end; * Increment player's position (position resets to 1 after 10, increment resets to 1 after 100);
  score(p)+pos(p);                                                         * Add new position to score;
end;
answer=min(of score:)*toss;                                                * Answer is minimum score * number of dice tosses;
put answer=;
datalines;
Player 1 starting position: 1
Player 2 starting position: 5
;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SOLUTION-PART II&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;*==&amp;gt; Advent of Code 2021 Day 21 Part 2: SAS SQL-Based Solution
     Note: Should see better performance if #CPUs&amp;gt;1 (SQL autoscales) and MEMLIB option available for datasets 
     See https://adventofcode.com/2021/day/21#part2 for problem description;

data combos; do d=1 to 3; output; end; * Possible dice face values are 1-3;
proc sql;                     
create table rolls as            /* Table of all possible 3-dice totals (weight N used to try to reduce size/time) */                  
  select roll, count(*) as n from (select t1.d+t2.d+t3.d as roll from combos t1, combos t2, combos t3) t4 group by 1;   

data games;                      /* Read player starting positions, initalize scores and # games to zero */
retain p1 p2 s1 s2 0 games 1;
input @"position: " p1; input @"position: " p2; output; 
datalines;
Player 1 starting position: 1
Player 2 starting position: 5
;
data wins; retain wins1 wins2 0; output; * Initialize a table to hold # games won by each player; 

%macro playgames;
proc sql;
%do %until(&amp;amp;GamesLeft=0);        /* Repeat until all games completed */
create table games as            /* Use dice totals to update player 1 positions/scores &amp;amp; add new games */
  select mod(p1+roll-1,10)+1 as p1, s1+calculated p1 as s1, p2, s2, games*n as games from games, rolls;
create table wins as             /* Count games won by player1 (score of 21+) */             
  select wins1+coalesce(wins,0) as wins1, wins2 from wins, (select sum(games) as wins from games where s1&amp;gt;=21) t2;
create table games as            /* Drop games won by player 1 */
  select * from games where s1&amp;lt;21;
create table games as            /* Use dice totals to update player 2 positions/scores &amp;amp; add new games */
  select mod(p2+roll-1,10)+1 as p2, s2+calculated p2 as s2, p1, s1, games*n as games from games, rolls;
create table wins as             /* Count games won by player1 (score of 21+) */
  select wins1, wins2+coalesce(wins,0) as wins2 from wins, (select sum(games) as wins from games where s2&amp;gt;=21) t2;
create table games as            /* Drop games won by player 2 */
  select * from games where s2&amp;lt;21;
select count(*) into :GamesLeft from games; * Games remaining?; 
%end;
select max(sum(wins1),sum(wins2)) as answer format=16. from wins; * Answer is # games won by winningest player;
quit;
%mend;

%playgames;                      /* Let's roll the dice! */&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Wed, 22 Dec 2021 03:33:21 GMT</pubDate>
    <dc:creator>tc</dc:creator>
    <dc:date>2021-12-22T03:33:21Z</dc:date>
    <item>
      <title>Advent of Code 2021 Day 21 - A SAS Array/SQL-Based Solution</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Advent-of-Code-2021-Day-21-A-SAS-Array-SQL-Based-Solution/m-p/787051#M251395</link>
      <description>&lt;P&gt;&lt;FONT size="3"&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="'Tis the season to be coding..." style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/66929iB115DE2666620478/image-size/small?v=v2&amp;amp;px=200" role="button" title="adventofcode.jpg" alt="'Tis the season to be coding..." /&gt;&lt;span class="lia-inline-image-caption" onclick="event.preventDefault();"&gt;'Tis the season to be coding...&lt;/span&gt;&lt;/span&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="3"&gt;As &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/43560"&gt;@jmhorstman&lt;/a&gt;&amp;nbsp;did &lt;A href="https://communities.sas.com/t5/SAS-Programming/Holiday-Fun-The-Advent-of-Code-using-SAS/m-p/518967" target="_self"&gt;a few years back&lt;/A&gt;, thought I'd take a crack at a few of the &lt;A href="https://adventofcode.com/" target="_self"&gt;Advent of Code 2021&lt;/A&gt; challenges with SAS. Not sure whether to be proud or ashamed of them (&lt;EM&gt;maybe a little of both!&lt;/EM&gt;), but below is how I solved &lt;A href="https://adventofcode.com/2021/day/21" target="_self"&gt;today's Day 21 problem&lt;/A&gt; with SAS array-based (Part I) and SQL-based (Part II) solutions. &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="3"&gt;Imagine I could have tapped PROC FCMP to knock out a recursive solution for Part II, but I personally found the SQL-based one pretty easy to verify against the problem description, and&amp;nbsp;this a one-off problem where performance isn't a concern. Some of the &lt;A href="https://www.reddit.com/r/adventofcode/comments/rl6p8y/2021_day_21_solutions/" target="_self"&gt;solutions in other languages&lt;/A&gt; I reviewed employed more CS-type constructs - regex parsing, recursive functions, lambdas/closures, state vectors, dictionaries, hashing, iterators, maps, memoization and cache packages, decorators, etc. Interesting to see all of the different approaches to get the same answer, though! &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="3"&gt;My SQL solution did take about 16 seconds to run using SAS Studio on&amp;nbsp;&lt;A href="https://welcome.oda.sas.com/home" target="_self"&gt;SAS OnDemand for Academics&lt;/A&gt; (&lt;EM&gt;free, if you haven't tried it!&lt;/EM&gt;). Not too bad for an untuned program using SQL, but it'd be interesting to see how the SQL might perform on another system where more CPUs are available (for auto-scaling) and the MEMCACHE option is available for libraries.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SOLUTION-PART I&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;*==&amp;gt; Advent of Code 2021 Day 21 Part 1: SAS Array-Based Solution
     See https://adventofcode.com/2021/day/21 for problem description;
     
data _null_;                                                               * Advent of Code, Day 21 Part 1;
array pos(*) p1-p2; array score(*) score1-score2;                          * Players' positions, scores;
do i=1 to dim(pos); input @"position: " pos(i); end;                       * Read initial positions of players; 
do while(max(of score:)&amp;lt;1000);                                             * Game over when a player reaches 1000;
  p=coalesce((p+1)*(p&amp;lt;dim(pos))+(p=dim(pos)),1);                           * Determine current player;
  do t=1 to 3; toss+1; pos(p)=mod((pos(p)+mod(toss-1,100)+1)-1,10)+1; end; * Increment player's position (position resets to 1 after 10, increment resets to 1 after 100);
  score(p)+pos(p);                                                         * Add new position to score;
end;
answer=min(of score:)*toss;                                                * Answer is minimum score * number of dice tosses;
put answer=;
datalines;
Player 1 starting position: 1
Player 2 starting position: 5
;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SOLUTION-PART II&lt;/STRONG&gt;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;*==&amp;gt; Advent of Code 2021 Day 21 Part 2: SAS SQL-Based Solution
     Note: Should see better performance if #CPUs&amp;gt;1 (SQL autoscales) and MEMLIB option available for datasets 
     See https://adventofcode.com/2021/day/21#part2 for problem description;

data combos; do d=1 to 3; output; end; * Possible dice face values are 1-3;
proc sql;                     
create table rolls as            /* Table of all possible 3-dice totals (weight N used to try to reduce size/time) */                  
  select roll, count(*) as n from (select t1.d+t2.d+t3.d as roll from combos t1, combos t2, combos t3) t4 group by 1;   

data games;                      /* Read player starting positions, initalize scores and # games to zero */
retain p1 p2 s1 s2 0 games 1;
input @"position: " p1; input @"position: " p2; output; 
datalines;
Player 1 starting position: 1
Player 2 starting position: 5
;
data wins; retain wins1 wins2 0; output; * Initialize a table to hold # games won by each player; 

%macro playgames;
proc sql;
%do %until(&amp;amp;GamesLeft=0);        /* Repeat until all games completed */
create table games as            /* Use dice totals to update player 1 positions/scores &amp;amp; add new games */
  select mod(p1+roll-1,10)+1 as p1, s1+calculated p1 as s1, p2, s2, games*n as games from games, rolls;
create table wins as             /* Count games won by player1 (score of 21+) */             
  select wins1+coalesce(wins,0) as wins1, wins2 from wins, (select sum(games) as wins from games where s1&amp;gt;=21) t2;
create table games as            /* Drop games won by player 1 */
  select * from games where s1&amp;lt;21;
create table games as            /* Use dice totals to update player 2 positions/scores &amp;amp; add new games */
  select mod(p2+roll-1,10)+1 as p2, s2+calculated p2 as s2, p1, s1, games*n as games from games, rolls;
create table wins as             /* Count games won by player1 (score of 21+) */
  select wins1, wins2+coalesce(wins,0) as wins2 from wins, (select sum(games) as wins from games where s2&amp;gt;=21) t2;
create table games as            /* Drop games won by player 2 */
  select * from games where s2&amp;lt;21;
select count(*) into :GamesLeft from games; * Games remaining?; 
%end;
select max(sum(wins1),sum(wins2)) as answer format=16. from wins; * Answer is # games won by winningest player;
quit;
%mend;

%playgames;                      /* Let's roll the dice! */&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 22 Dec 2021 03:33:21 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Advent-of-Code-2021-Day-21-A-SAS-Array-SQL-Based-Solution/m-p/787051#M251395</guid>
      <dc:creator>tc</dc:creator>
      <dc:date>2021-12-22T03:33:21Z</dc:date>
    </item>
  </channel>
</rss>

