Search code examples
sasdo-loops

Do loop with variable iteration (SAS)


I am trying to write a SAS program that simulates a variation of golf, for 2 halves of 9 holes each:

For 1 half of 9 holes:

  1. Start with nine, twelve-faced dice with values -1,0,1,2,3,4 with constant probabilities.

  2. Pick the dice with the lowest values, and store them into an array.

  3. Remove however many dice had the lowest value (i.e., if 0 was the lowest value, and there were 3 of them, there are only 6 dice remaining for the 2nd iteration). Repeat until array has 9 elements.

  4. Sum these scores together to get the score for first half.

I was able to write the following code that took the lowest score for each round, then removed one dice per round (for a total of 9 rounds in 1 half). But I do not know how I can alter it, or adapt it, so that a varying number of dice can be removed per round (so total number of rounds <= 9).

do i = 1 to 9; 

  do j = 9 to 1 by -1; 

       if i - j <= 0 then 
           dice(j) = rantbl(seed, p1n, p0, p1, p2, p3, p4) - 2; 
       else dice(j) = 100;
  end;

  half1(i) = min(of dice1-dice9);

end;

I was thinking of defining an array without a specified number of elements, and having an outer do while loop with an ending condition of dim(array) = 9. But I am not sure how to define how many elements to remove each time.

Can someone give me some advice on how to approach this? I'm in an introductory graduate SAS programming class, so I'm still pretty new to this.

Thanks!


Solution

  • Perhaps something like this? You need one array to store the generated values of the dice. You need two accumulators to store the total score and the number of dice used. You need to add logic to terminate the loop when you have accumulated 9 scores. You can use the count of the number of dice selected to also control the loop that generates the dice rolls. So if you have already "used" 5 values then you only need to generate 4 random values.

    data test;
      if _n_=1 then call streaminit(12345);        /* use default method */
    * simulate 5 "rounds" or "half-rounds" ;
    do round=1 to 5;
      put / round= ;
      nscore= 0;
      score=0;
      array dice (9) _temporary_;
      do roll=1 to 9 while (nscore < 9) ;
        put  'Start ' roll= score= nscore= @;
        * roll ;
        call missing(of dice(*));
        do i=nscore+1 to 9 ;
          dice(i) = ceil(6*rand('uniform'))-2;
        end;
        * Find minimum ;
        min1 = min(of dice(*));
        do i=nscore+1 to 9 while (nscore < 9) ;
          if dice(i)=min1 then do;
            score=sum(score,min1);
            nscore=sum(nscore,1);
          end;
        end;
        put ' End ' roll= score= nscore=;
      end;
      output;
    end;
    run;