BookmarkSubscribeRSS Feed
skjhzzang
Calcite | Level 5
 
5 REPLIES 5
ed_sas_member
Meteorite | Level 14

Hi @skjhzzang 

 

Please have a look at the following resource, which tries to solve the N-Queens problems using several programming  languages: https://rosettacode.org/wiki/N-queens_problem#SAS

You can easily put the '8' in a macrovariable inside a macro-program.

 

Hope this helps,

 

Best,

RichardDeVen
Barite | Level 11

'Pure' macro is really not the environment for typical recursion and fundamental computation.  Regardless, it's not impossible.

 

Example:

%* translated to SAS macro - Richard DeVenezia
%* Based on code at https://www.geeksforgeeks.org/n-queen-problem-backtracking-3/;
%* contributed by Princi Singh ;

%macro logBoard(N);
  %* requires: macro symbols BOARD_1_1 to BOARD_<N>_<N> to exist in callers scope;
  %local i j row;

  %put NOTE: ------------- &=N;

  %do i = 1 %to &N;
    %let row = ;
    %do j = 1 %to &N;
      %let row = &row &&BOARD_&I._&J.;
    %end; 
    %put NOTE: &row;
  %end;

  %put NOTE: -------------;
%mend;

%macro isSafePlace(row, col, N);
  %* requires: macro symbols BOARD_1_1 to BOARD_<N>_<N> to exist in callers scope;
  %local i j index;
  %do j = 1 %to &col;
    %if &&BOARD_&ROW._&J. %then %do;
      0 /* not safe */
      %return;
    %end;
  %end;

  %let i = &row;
  %let j = &col;
  %do index = 1 %to &N;
    %if &&BOARD_&I._&J. %then %do;
      0 /* not safe */
      %return;
    %end;
    
    %let i = %eval(&i-1); %if &i < 1 %then %goto leave1;
    %let j = %eval(&j-1); %if &j < 1 %then %goto leave1;
  %end;
%leave1:

  %let i = &row;
  %let j = &col;
  %do index = 1 %to &N;
    %if &&BOARD_&I._&J. %then %do;
      0 /* not safe */
      %return;
    %end;
    
    %let i = %eval(&i+1); %if &i > &N %then %goto leave2;
    %let j = %eval(&j-1); %if &j <  1 %then %goto leave2;
  %end;
%leave2: 

  1 /* is safe */
%mend;

%macro queensRecursion(col, N);
  %local i j;
  %if &col > &N %then %do; 
    1  /* solution found */
    %return;
  %end;

  %do i = 1 %to &N;
    %if %isSafePlace(&i, &col, &N) %then %do;
      %let BOARD_&I._&COL. = 1;

      %if %queensRecursion(%eval(&col+1), &N) %then %do;
        1
        %return;
      %end;

      /* backtrack */
      %let BOARD_&I._&COL. = 0;
    %end;
  %end;

  0 /* could not be placed safely */
%mend;


%macro queens(N);
  %local i j;
  %do i = 1 %to &N;
  %do j = 1 %to &N;
    %local BOARD_&I._&J;
    %let BOARD_&I._&J = 0;
  %end;
  %end;
  
  %if not %queensRecursion(1, &N) %then %do;
    %put WARNING: No Queens solution found for &=N;
    %return;
  %end;

  %logBoard(&N)
%mend;

options mprint nomlogic nosymbolgen;

%queens(6)

Log

758  %queens(6)
      ------------- N=6
NOTE: 0 0 0 1 0 0
NOTE: 1 0 0 0 0 0
NOTE: 0 0 0 0 1 0
NOTE: 0 1 0 0 0 0
NOTE: 0 0 0 0 0 1
NOTE: 0 0 1 0 0 0
      -------------
Ksharp
Super User

When n=6 , there are four solutions .

EDITED.

EDITED again.

 

%let n=6 ;


data have;
 do i=1 to &n;
   do j=1 to &n;
      output;
   end;
 end;
run;
 
data want(keep=path);
 set have(obs=&n);
if _n_=1 then do;
  array row{%eval(&n*&n)} _temporary_;
  array col{%eval(&n*&n)} _temporary_;
  array flag{%eval(&n*&n)} _temporary_;

  length path _path  $ 400 temp $ 20;
  declare hash pa(ordered:'y');
  declare hiter hi_path('pa');
  pa.definekey('n');
  pa.definedata('n','path');
  pa.definedone();
end;

count=1;n=1;path=catx(' ',i,j);pa.add();
do while(hi_path.next()=0);
 if n ne 1 then pa.remove(key:_n);_n=n;

  idx=0;
  do i=1 to &n;
   do j=1 to &n;
     idx+1;row{idx}=i;col{idx}=j;flag{idx}=0;
   end;
  end;

  do k=1 to countw(path,'|');
   temp=scan(path,k,'|');
   first=input(scan(temp,1),best.);
   second=input(scan(temp,-1),best.);
   /*Remove - | / \ nodes*/
   do idx=1 to &n*&n;
     if first=row{idx} or second=col{idx} or 
        abs(first-row{idx})=abs(second-col{idx}) then flag{idx}=1;
   end;
  end;

  _path=path;   
   do idx=1 to &n*&n;
     if row{idx}=k and flag{idx}=0 then do;
       count+1;n=count;
	   path=catx('|',path,catx(' ',row{idx},col{idx}));
       pa.add(); 	
       if countw(path,'|')=&n then output;
       path=_path;
     end;
   end;
end;
pa.clear();	
run; 

data temp;
 set want;
 array var{&n} $ 20;
 do k=1 to &n;
   var{k}=scan(path,k,'|');
 end;
 keep var1-var&n ;
run;

data _null_;
 set temp end=last;
 call execute(catt("data solution_",_n_,";array var{&n};do i=1 to &n;do j=1 to &n;
 if findw('",catx('|',of var1-var&n),"',catx(' ',i,j),'|') then var{j}=1;else var{j}=0;end;
 output;end;drop i j;run;"));
run;

 

Ksharp
Super User

Better using PROC OPTMODEL .and calling @RobPratt 

RobPratt
SAS Super FREQ

Please see this documentation example for the constraint programming solver in PROC OPTMODEL.

 

You can change the value of n to whatever you want.  If you want to find all solutions, use the FINDALLSOLNS in the SOLVE statement.

sas-innovate-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 5 replies
  • 1073 views
  • 2 likes
  • 5 in conversation