SAS dynamic arrays with changing start and stop values - arrays

I am working on a longitudinal dataset where each row is a subject and each column is an event. There are no limits to the number of events that a subject can have, but the events are coded in a few ways. For the sake of this example let's say one of the coded ways is binary (good, bad).
I am trying to find
1) all of the event strings consisting of 3 or more events (with no count limit) that are within 24 hours of one another (on the same subject) from start to finish. There also may be multiple successes of this criteria within the same subject.
2) for each of the successes (string of 3 or more events within 24 hours) I need to count the number of good events.
I've included code that generates similar data to mine. For now I'm simplifying to 26 observations but I have up to 42 for a single subject.
data examp;
informat subject 4. epdt1 epdt2 epdt3 epdt4 epdt5 epdt6 epdt7 epdt8 epdt9 epdt10 epdt11 epdt12 epdt13 epdt14 epdt15 epdt16 epdt17 epdt18 epdt19 epdt20 epdt21 epdt22 epdt23 epdt24 epdt25 epdt26 datetime20.
good1 good2 good3 good4 good5 good6 good7 good8 good9 good10 good11 good12 good13 good14 good15 good16 good17 good18 good19 good20 good21 good22 good23 good24 good25 good26 1.;
input subject epdt1 epdt2 epdt3 epdt4 epdt5 epdt6 epdt7 epdt8 epdt9 epdt10 epdt11 epdt12 epdt13 epdt14 epdt15 epdt16 epdt17 epdt18 epdt19 epdt20 epdt21 epdt22 epdt23 epdt24 epdt25 epdt26
good1 good2 good3 good4 good5 good6 good7 good8 good9 good10 good11 good12 good13 good14 good15 good16 good17 good18 good19 good20 good21 good22 good23 good24 good25 good26;
format subject: 4. epdt: datetime20. good: 1.;
datalines;
3098 . . 25JUL1998:01:46:27 25JUL1998:02:16:05 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3021 13JAN1999:17:31:37 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1982 01FEB1998:02:29:01 12APR1999:19:49:00 03JUN2018:21:00:00 13AUG1999:13:39:00 . . . . . . . . . . . . . . . . . . . . . . 1 . . . . . . . . . . . . . . . . . . . . . . . . .
1093 11APR2015:16:10:57 30AUG2015:00:52:28 14SEP2015:08:24:25 09MAY1999:00:28:37 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4089 29JUN1998:05:18:34 23JUL1998:18:31:11 07FEB1999:05:25:45 07FEB1999:05:29:26 07FEB1999:05:32:04 07FEB1999:05:34:05 14FEB1999:18:00:13 14FEB1999:18:01:02 14FEB1999:18:03:24 14FEB1999:18:05:55 14FEB1999:18:16:45 14FEB1999:18:19:04 14FEB1999:18:31:57 14FEB1999:18:35:22 28JUL1998:18:32:02 31DEC1998:00:22:33 . . . . . . . . 1 1 1 1 1 1 1 1 1 1 1 . 1 . 1 . . . . . . . . . .
3055 18FEB1998:11:34:00 14JUL1998:01:20:34 13OCT1998:10:49:08 30OCT1998:18:14:58 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1239 07MAR1998:06:02:18 01JUN1998:08:18:20 23JUN1998:07:52:11 04JUL1998:08:47:04 29JUL1998:23:16:41 29JUL1998:23:30:03 29JUL1998:23:42:56 30JUL1998:00:08:03 30JUL1998:00:12:30 30JUL1998:00:14:58 30JUL1998:00:36:00 30JUL1998:00:38:33 30JUL1998:00:57:56 30JUL1998:01:01:03 30JUL1998:01:06:10 30JUL1998:01:16:50 30JUL1998:01:24:19 30JUL1998:01:32:30 30JUL1998:01:42:55 30JUL1998:01:50:24 30JUL1998:02:08:46 30JUL1998:02:20:18 30JUL1998:02:22:08 30JUL1998:02:28:52 30JUL1998:02:31:29 30JUL1998:02:51:29 . . 1 . 1 1 1 1 1 1 1 . 1 1 1 1 1 1 1 1 1 1 1 1 . 1
9834 10JUL1999:20:22:24 14JUL1999:00:52:02 14JUL1999:17:02:38 14JUL1999:17:30:06 21FEB2000:12:41:34 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
run;
proc sort data=examp; by subject;
data epwide_dt1;
format apppair $7000.;
set examp;
by subject;
%macro loops;
array eptm (*)epdt1-epdt26; array apptm (*) good1-good26;
*********using the starting value for identifying pairs;
*******trimmed then for the sake of making the macro work;
%do start=1 %to 26;
%do stop=3 %to 26;
%if &start.<&stop. %then %do ;
/***********to figure out if the difference between the pairs of times are 24 hours;*/
tbtw=eptm[&stop.]-eptm[&start.];
/* *********number of points between them;*/
diff=(&stop.)- (&start.);
*******calculate the summaries between all episodes from start to stop;
array appr&start.&stop. (*) ap&start.-ap&stop.;
array stmct&start.&stop.(*) st&start.-st&stop.;
%do i=&start. %to &stop.;
******calculate the number of appropriate episodes;
if apptm[&i] ne . then appr&start.&stop.[&i]=apptm[&i];
else appr&start.&stop.[&i]=0;
totapp=sum(of appr&start.&stop.(*));
if totapp=. then totapp=0;
****after you calculate the total value dump the array before the next itteration;
/*call missing(of appr&start.&stop.{*});*/
if (eptm[&start.] ne . and eptm[&stop.] ne . and diff>=2 and .<tbtw<86400 and totapp>1 ) then do;
appPair=catx(" ",apppair,"(",strip(put(&start., 3.)),"-",strip(put(&stop.,3.)),":", strip(put(totapp,3.)),"Good)");
end;
%end;
%end;
%end;
%end;
%mend;
%loops ;
run;
The error message below is what's resulting:
ERROR: Array subscript out of range at line 1 column 2.
apppair= subject=1093 epdt1=11APR2015:16:10:57 epdt2=30AUG2015:00:52:28 epdt3=14SEP2015:08:24:25
epdt4=09MAY1999:00:28:37 epdt5=. epdt6=. epdt7=. epdt8=. epdt9=. epdt10=. epdt11=. epdt12=. epdt13=. epdt14=. epdt15=.
epdt16=. epdt17=. epdt18=. epdt19=. epdt20=. epdt21=. epdt22=. epdt23=. epdt24=. epdt25=. epdt26=. good1=. good2=.
good3=. good4=. good5=. good6=. good7=. good8=. good9=. good10=. good11=. good12=. good13=. good14=. good15=. good16=.
good17=. good18=. good19=. good20=. good21=. good22=. good23=. good24=. good25=. good26=. FIRST.subject=1
LAST.subject=1 tbtw=1323117 diff=1 ap1=0 ap2=0 ap3=0 st1=. st2=. st3=. totapp=0 ap4=0 st4=. ap5=0 st5=. ap6=0 st6=.
ap7=0 st7=. ap8=0 st8=. ap9=0 st9=. ap10=0 st10=. ap11=0 st11=. ap12=0 st12=. ap13=0 st13=. ap14=0 st14=. ap15=0
st15=. ap16=0 st16=. ap17=0 st17=. ap18=0 st18=. ap19=0 st19=. ap20=0 st20=. ap21=0 st21=. ap22=0 st22=. ap23=0 st23=.
ap24=0 st24=. ap25=0 st25=. ap26=0 st26=. _ERROR_=1 _N_=1
NOTE: Missing values were generated as a result of performing an operation on missing values.
Each place is given by: (Number of times) at (Line):(Column).
1 at 35:20 1 at 57:20 1 at 83:20 1 at 113:20 1 at 147:20 1 at 185:20 1 at 227:20
1 at 273:20 1 at 323:20 1 at 377:20 1 at 435:20 1 at 497:20 1 at 563:20 1 at 633:20
1 at 707:20 1 at 785:20 1 at 867:20 1 at 953:20 1 at 1043:20 1 at 1137:20 1 at 1235:20
1 at 1337:20
NOTE: The SAS System stopped processing this step because of errors.
NOTE: There were 2 observations read from the data set WORK.EXAMP.
WARNING: The data set WORK.EPWIDE_DT1 may be incomplete. When this step was stopped there were 0 observations and
109 variables.
WARNING: Data set WORK.EPWIDE_DT1 was not replaced because this step was stopped.
NOTE: DATA statement used (Total process time):
real time 2.35 seconds
cpu time 2.13 seconds
Thanks in advance for any suggestions!

I am not sure I quite understand your full problem. But consider that if you want to sum the subset of values in an array from index START to index STOP you just use a DO loop.
For example to sum X10 to X20 you could use code like this:
array x (100) ;
start=10;
stop=20;
do i=start to stop;
total=sum(total,0,x(i));
end;
So you should be able to solve this without macro code. Which should make debugging much easier.

I finally got it working!!! I used #Tom 's suggestion to remove the need for creating a sub array of each of the pairs, as it was causing ALOT of problems. I also streamlined the output and asked it to output each pair that is "Good" so that I will be able to evaluate them easier. Previously it was creating appPair (my evaluation summary for each iteration within the start stop loop producing a bunch of extraneous output).
data epwide_dt1;
set examp;
by subject;
if first.subject then totapp=0;
%macro loops;
array eptm (*)epdt1-epdt26;
array apptm (*) good1-good26;
*********using the starting value for identifying pairs;
%do start=1 %to 24;
%do stop=3 %to 26;
%if &start.<&stop. %then %do ;
totapp=0;
/***********to figure out if the difference between the pairs of times are 24 hours;*/
tbtw=eptm[&stop.]-eptm[&start.];
/* *********number of points between them;*/
diff=(&stop.)- (&start.);
%do i=&start. %to &stop.;
******calculate the number of good events;
totapp=sum(totapp, 0,apptm[&i]);
***output the summary on the pair that can be evaluated in the next step;
if &i=&stop. and (eptm[&start.] ne . and eptm[&stop.] ne . and diff>=2 and 0<tbtw<86400 and totapp>1 ) then do;
appPair=catx(" ","(",strip(put(&start., 3.)),"-",strip(put(&stop.,3.)),":", strip(put(totapp,3.)),"Good)");
output;
end;
%end;
%end;
%end;
%end;
%mend;
%loops ;
run;

Related

How can i use the "edges" of a dynamic 2D array as a way to tell my program they are out of limit

I will try my best to explain as well as i can what i mean and what my goal is, sorry if I'm failing to get my point through.
Lets say i have this output when i run my code:
1 2 3 4 5 6 7 8
_________________________
1 | . . . $ . . . .
2 | . . . . . . # .
3 | . # . . . . . .
4 | . . . . 4 . . .
5 | . . . . . . . .
6 | 5 . . . . . . .
7 | . . 5 . # . . .
8 | . . . . . . . .
My code reads 2 dimensions given by the user and then using malloc it gives me this dynamic 2d array.
The little '$' character is the player and the array is the level in which he is allowed to move, all my code that can "move" the player works perfectly fine, the player can collect the random numbers in the board which represent the value of a diamond he finds and if a user wants to move for example 4 spaces in a direction and at the 3d space there is the "#" symbol the character "$" stops and prints a message how many positions he moved before stopping in front of the obstacle. I want to achieve the exact same thing but with the edges of the board, for example in the output i am presenting above, "$" is sitting in the position [1][4] and if a user tries to move "up" in the board there is clearly no more spaces to move so i want to show a message saying just that.
This is the recursive function that gets called when the user wants to move up:
int Up(int **D_Board)
{
int column_pos, row_pos, stop;
column_pos = Current_Position_Column(D_Board);
row_pos = Current_Position_Row(D_Board);
moving++;
if (moving <= moves)
{
if (D_Board[column_pos - 1][row_pos] == '.' || D_Board[column_pos - 1][row_pos] == ' ')
{
D_Board[column_pos][row_pos] = ' ';
column_pos = column_pos - 1;
D_Board[column_pos][row_pos] = '$';
Up(D_Board);
}
else if (D_Board[column_pos - 1][row_pos] == '#')
{
D_Board[column_pos][row_pos] = '$';
stop = moving - 1;
moving = moves;
printf("\nHit an obstacle...\n\nYou only moved %d positions.\n\n", stop);
}
if (D_Board[column_pos - 1][row_pos] >= 0 && D_Board[column_pos - 1][row_pos] <= 9)
{
diamonds = diamonds + D_Board[column_pos - 1][row_pos];
D_Board[column_pos][row_pos] = ' ';
column_pos = column_pos - 1;
D_Board[column_pos][row_pos] = '$';
}
}
else
return 0;
}
If i add the conditions i use when it encounters "#" in the code but instead i define the top row as D_Board[0][row_pos] the code never enters that condition and exits my main loop that constantly asks the player to give inputs and i cant figure out why, i have tried some things without success for example:if (column_pos == 0){do stuffs}; or if(D_Board[column_pos-1][row_pos] == D_Board[0][row_pos]){do stuffs};

inadvertent change of shared memory - c programming

I'm making a programme that uses shared memory, semaphore et message queue to create a board game where programs fight each others.
In my code I create the shared memory which functions well (it seems) and I put in it an int** map.
The problem is, between the map creation and after the return of the same function, the map change alone (I do not modify it). Can you explain me why please?
Here is a sample of my code:
int create_ressources(int *shmid, key_t *key,
player_t *player, board_t *map)
{
printf("%s\n", "--- Entrée dans fonction creat_ressources ---");
create_shared_memory(shmid, key);
create_map(map, shmid); // <- here the map has changed
print_board(map);
return (SUCCESS);
}
void create_shared_memory(int *shmid, const key_t *key)
{
(*shmid) = shmget((*key), SH_SIZE, SHM_W | SHM_R);
if ((*shmid) == -1)
(*shmid) = shmget((*key), SH_SIZE, IPC_CREAT | SHM_W | SHM_R);
if (!*shmid)
exit(ERROR);
}
void create_map(board_t *map, const int *shmid)
{
void *addr = NULL;
addr = shmat((*shmid), NULL, SHM_R | SHM_W);
map = (board_t*)addr;
print_board(map); // <- here the map is good
}
Here is the map when I just created and when it's good:
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
And here is the same map just after the create_map function exit:
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . 3 . 214252960 32767 1023324160 32686 214253192 32767 2 . 2053 . 1021207349 32686 . . 1835008 . 1833744 . 1833744 . .
. 5 . 3932160 . 3956736 . 3954464 . 3971488 . 1835008 . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . 4096 . 1178 . . . 1023435112 32686 3 . . . 1021283966 32686 . . 32 . 1 . 1021226648 32686 1023438176 32686 32 . 47 1 10 . .
. 1023435112 32686 214252960 32767 1021225751 32686 2147479968 3 214252960 32767 1023324160 32686 1021206312 32686 -1 -1 1023434912 3 1021176224 32686 1021249988 32686 214252192 32767 1017297071 32686 . . 1021213293 32686 214253120 1 5636179 . 6 . 214252192 32767 95177 3 1023435072 32686 1023438176 32686 . . 2053 . 5636179
. 1 . 33261 . . . . . 1868984 . 4096 . 3656 . 1522236691 . 852133901 . 1515984691 . . . 1517241387 . 248361376 . . . . . . . . 3 4196129 . 1023435112 32686 . . 1023430720 32686 214253120 32767 . . 1021213735 32686 1
. . . 214253112 32767 . . . 1 1023438176 32686 . . 10 . 214253088 32767 214253104 32767 1023435112 32686 . . . . . . . . . . 1023438176 32686

Checking neighbour elements in flat array

Problem description:
I want to iterate over an array (flattened 2D --> 1D array right now) and keep checking it's nearest neighbours. From that I want to determine if they are dead/alive ('X' or '.') and change their state accordingly to my rules(simplified conway's).
My grid looks like this e.g.:
...............
...........X...
.X.......X...X.
...............
....X..........
....X..........
...............
.....XX........
..........X....
...............
Cells alive: 9
But I have this array flattened to 1D array to iterate over it. So basically it turns to something like this: ....X...X....X. etc.
After writing it down on a paper I think there are several cases to check in this "grid":
TopLeft element (i = 0) - first element, 3 neighbours/cases to check
TopRight element (i = nColumns - 1), as above
BottomLeft element (i = nColumns * nRows - nColumns), as above
BottomRight element (i = nColumns * nRows - 1) - last element, as above
"Border" elements (5 neighbours each without corner elements)
Middle elements with 8 neighbours
But it seems totally stupid to check it with some if's and case statements. If I could use real 2D arrays I think I could just create array of offset (-1, 1), (0, 1)... and so on. But I can't think of a way how to handle this with my code.
I will be very glad for any tips/examples and so on.
My code so far:
cellsAlive=0
#STDIN variables
geneFile=$1
nRows=$2
nColumns=$3
let "cells = $nRows * $nColumns"
declare -i tick_rate # instead maybe use watch or sleep
readarray -t geneArr < $geneFile # -t removes a trailing newline from each line read.
elementsCounts=${#geneArr[#]}
echo -e "--- Coordinates ---"
for (( i = 0; i < $elementsCounts; i++ )); do
echo "${geneArr[$i]}" #| cut -d' ' -f2 $geneFile | head -2
done
echo -e "\n--- Grid ---"
#file must end with a newline
[[ $geneFile && -f $geneFile && -r $geneFile ]] || { printf >&2 'arg must be readable file.\n'; exit; }
array=()
for ((i=0; i<nRows*nColumns; ++i)); do
array+=( '.' )
done
printf "\n"
while read -r x y; do
[[ $x && $y ]] || continue
[[ $x = +([[:digit:]]) && $y = +([[:digit:]]) ]] || continue
((x=10#$x,y=10#$y)) #10 digit base
(( x<nRows && y<nColumns )) || continue
array[x+y*nRows]='X'
if [[ ${array[x+y*nRows]} == 'X' ]]; then
let "cellsAlive += 1"
fi
done < "$geneFile"
# print to stdout and to file
for((i=0;i<nColumns;++i)); do
printf '%s' "${array[#]:i*nRows:nRows}" $'\n'
done | tee currentState
arrayCopy=("${array[#]}")
printf "Cells alive: %d" $cellsAlive ; printf "\n"
# printf "\n"
for (( i = 0; i < ${#arrayCopy[#]}; i++ )); do
#neighboursCount=0
case $i in
"0") if [[ ${arrayCopy[$(($i - 1))]} == 'X' ]] || [[ ${arrayCopy[$(($i + $nColumns))]} == 'X' ]] || [[ ${arrayCopy[$(($i + $nColumns + 1))]} == 'X' ]] ; then #TopLeft
echo "That is just ridiculous way to check it..."
fi ;;
"$(($nColumns - 1))") printf "${arrayCopy[$i]}" ;; #TopRight
"$(($nColumns*$nRows-1))") printf "${arrayCopy[$i]}" ;; #BottomRight
"$(($nColumns*$nRows-$nColumns))") printf "${arrayCopy[$i]}" ;; #BottomLeft
*) ;; #Middle elements with 8 neighbours
esac
done
printf "\n"
Thanks in advance for help.
Example geneFile.txt (add blank like at the end):
1 2
4 5
6 7
13 2
5 7
4 4
9 2
11 1
10 8
ok. Here we go. Because i found this question interesting to be implemented in bash i just wrote an implementation of conway's game of life.
The main part to answer your question is probably: how to access neighbours for a position in a matrix if it is linearized?.
So you can access an element in a flatted matrix by
(row*fieldwidth)+columnoffset.
Every neighbour then can be accessed by adjusting row and columnoffset by +/-1 starting with row and columnoffset at 0.
Have a look at the getnextstate function to view the specialcases.
So here is the implementation.
You are able to provide a file as input containing just CELLALIVEMARKER,CELLDEADMARKER and spaces. If the length for the flatted matrix does not fit the width/height parameter for the FIELD it just pads with random values.
#!/bin/bash
# system values
BASENAME="/usr/bin/basename"
ECHO="/bin/echo"
SLEEP="/bin/sleep"
TPUT="/usr/bin/tput"
GREP="/bin/grep"
WC="/usr/bin/wc"
CAT="/bin/cat"
if [ "${#}" != "4" -a "${#}" != "5" ]; then
${ECHO} "USAGE: ./$(${BASENAME} ${0}) FIELDWIDTH FIELDHEIGHT RULESALIVE RULESDEAD [LINSTARTMATRIX]"
${ECHO} "EXAMPLES: ./$(${BASENAME} ${0}) 50 50 \"2 3\" \"3\""
${ECHO} " ./$(${BASENAME} ${0}) 50 50 \"2 3\" \"3\"" init.mtx
exit
fi
# field values
FWIDTH=${1}
FHEIGHT=${2}
# number of living neighbours for a living cell to stay alive in the next generation
RULESALIVE=($(${ECHO} ${3}))
# number of living neighbours for a dead cell to become alive in the next generation
RULESDEAD=($(${ECHO} ${4}))
CELLALIVEMARKER="o"
CELLDEADMARKER="."
FIELD=() # flatted matrix representation
# if there are just marker values or spaces in the file it is a valid one
${CAT} ${5} | ${GREP} -oq '[^\'${CELLALIVEMARKER}'\'${CELLDEADMARKER}'\ ]'
isvalid="${?}"
if [ "${5}" != "" ] && [ "${isvalid}" == "1" ]; then
FIELD=($(${CAT} ${5}))
# fill up with randoms if the length won't fit the dimension parameters
if [ "${#FIELD[#]}" != "$((${FWIDTH}*${FHEIGHT}))" ]; then
${ECHO} "I: Padding matrix with random values."
# fill up field with randoms if its too short
for((i=${#FIELD[#]}; i<${FWIDTH}*${FHEIGHT}; i=$((${i}+1)))); do
cell="${CELLALIVEMARKER}"
alive=$((${RANDOM}%2))
if [ "x${alive}" == "x1" ]; then
cell="${CELLDEADMARKER}"
fi
FIELD[${#FIELD[#]}]="${cell}"
done
fi
else
# fill random field
for((i=0; i<${FWIDTH}*${FHEIGHT}; i=$((${i}+1)))); do
cell="${CELLALIVEMARKER}"
alive=$((${RANDOM}%2))
if [ "x${alive}" == "x1" ]; then
cell="${CELLDEADMARKER}"
fi
FIELD[${#FIELD[#]}]="${cell}"
done
fi
# evaluate rules and get the next state for the cell
getnextstate() {
local i="${1}" # row
local j="${2}" # col
local neighbours=""
# left upper
if [ "${i}" -eq "0" -a "${j}" -eq "0" ]; then
neighbours="${FIELD[$(((${i}*${FWIDTH})+(${j}+1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}+1)))]}"
# right upper
elif [ "${i}" -eq "0" -a "${j}" -eq "$((${FWIDTH}-1))" ]; then
neighbours="${FIELD[$(((${i}*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+${j}))]}"
# left bottom
elif [ "${i}" -eq "$((${FHEIGHT}-1))" -a "${j}" -eq "0" ]; then
neighbours="~${FIELD[$((((${i}-1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}-1)*${FWIDTH})+(${j}+1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}+1)))]}"
# right bottom
elif [ "${i}" -eq "$((${FHEIGHT}-1))" -a "${j}" -eq "$((${FWIDTH}-1))" ]; then
neighbours="?${FIELD[$((((${i}-1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}-1)*${FWIDTH})+${j}))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}-1)))]}"
# upper
elif [ "${i}" -eq "0" -a "${j}" -gt "0" ]; then
neighbours="-${FIELD[$(((${i}*${FWIDTH})+(${j}-1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}+1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}+1)))]}"
# bottom
elif [ "${i}" -eq "$((${FHEIGHT}-1))" -a "${j}" -gt "0" ]; then
neighbours="=${FIELD[$((((${i}-1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}-1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}-1)*${FWIDTH})+(${j}+1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}-1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}+1)))]}"
# right
elif [ "${i}" -gt "0" -a "${j}" -eq "0" ]; then
neighbours="#${FIELD[$((((${i}-1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}-1)*${FWIDTH})+(${j}+1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}+1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}+1)))]}"
# left
elif [ "${i}" -gt "0" -a "${j}" -eq "$((${FWIDTH}-1))" ]; then
neighbours="_${FIELD[$((((${i}-1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}-1)*${FWIDTH})+${j}))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+${j}))]}"
# center
else
neighbours="#${FIELD[$((((${i}-1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}-1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}-1)*${FWIDTH})+(${j}+1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}-1)))]} ${FIELD[$(((${i}*${FWIDTH})+(${j}+1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}-1)))]} ${FIELD[$((((${i}+1)*${FWIDTH})+${j}))]} ${FIELD[$((((${i}+1)*${FWIDTH})+(${j}+1)))]}"
fi
# count neighbours alive
ncnt=$(${ECHO} ${neighbours} | ${GREP} -o ${CELLALIVEMARKER} | ${WC} -l)
# evaluate rules
local next=""
if [ "${FIELD[$(((${i}*${FWIDTH})+${j}))]}" == "${CELLALIVEMARKER}" ] && [[ "$(${ECHO} ${RULESALIVE[#]})" =~ ${ncnt} ]]; then
next="${CELLALIVEMARKER}"
elif [ "${FIELD[$(((${i}*${FWIDTH})+${j}))]}" == "${CELLDEADMARKER}" ] && [[ "$(${ECHO} ${RULESDEAD[#]})" =~ ${ncnt} ]]; then
next="${CELLALIVEMARKER}"
else
next="${CELLDEADMARKER}"
fi
${ECHO} ${next}
}
firstrun=1
while [ true ]; do
# print lines
FIELD_UPDATE=()
for((i=0; i<${FHEIGHT}; i=$((${i}+1)))); do
line=""
# calculate lines
for((j=0; j<${FWIDTH}; j=$((${j}+1)))); do
if [ "${firstrun}" == "1" ]; then
line="${line}${FIELD[$(((${i}*${FWIDTH})+${j}))]} "
# start calculation just after the first print
elif [ "${firstrun}" == "0" ]; then
line="${line}$(getnextstate ${i} ${j}) "
fi
done
FIELD_UPDATE=($(${ECHO} ${FIELD_UPDATE[#]}) $(${ECHO} ${line}))
${ECHO} ${line}
done
FIELD=(${FIELD_UPDATE[#]})
${SLEEP} 2
# refresh lines in the field
for((i=0; i<${FHEIGHT}; i=$((${i}+1)))); do
# refresh lines
${TPUT} cuu1
${TPUT} el
done
firstrun=0
done
So providing the file init.mtx containing the following matrix
. o . . . . . . . .
. . o . . . . . . .
o o o . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
you are able to create a simple glider (from the upper left to the bottom right)
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . o o
. . . . . . . . o o
using Conway's default rules by running this script as follows:
./gameoflife 10 10 "2 3" "3" init.mtx
Hope this helps.
And btw it was fun to implement this in bash :)

PHPExcel drawing new lines when combining sheets

I'm combining about 20 excel sheets (user uploaded) using PHPExcel into a report. This is done by using this bit of code:
$filename = APP . 'docs' . DS . 'reports' . DS . $Workbooks[0]['Report']['company'] . '.' . $Workbooks[0]['Report']['report_name'] . '.' . $Workbooks[0]['Report']['extension'];
$blacklist = array('Company Organogram');
$MasterFile = $this->PhpExcel->createMasterFile($filename,$company . '.' . $title,$colour);
foreach($Workbooks as $Workbook) :
if(!in_array($Workbook['Report']['report_name'],$blacklist)) {
$file = APP . 'docs' . DS . 'reports' . DS . $Workbook['Report']['company'] . '.' . $Workbook['Report']['report_name'] . '.' . $Workbook['Report']['extension'];
$MasterFile = $this->PhpExcel->addExternalWorksheet($MasterFile,$file,$company . '.' . $title,$colour);
#unlink($file);
}
endforeach;
$this->PhpExcel->saveToDisk(APP . 'docs' . DS . 'reports' . DS . 'Weekly Reports for Week ' . (date('W') + 1) . '.xlsx',$MasterFile);
I'm working with CakePHP, so there is a helper. saveToDisk simply saves the file to the disc after which it is attached and sent to a mailing list.
All the above works fine. But I'm having issues where the combining process draws in extra lines. For instance, this:
becomes this:
How would I fix this? Is there something I should set so it doesn't draw in all the lines?

How to create this Kakuro table?

Hi I am trying to write Kakuro, but little bit different, If there is no only one possible
solution, It will count, how many solutions are able to achieve. My problem is to
create exact table of this shape
X X 16\X 16\X X X 15\X 16\X X X X X
X X\8 . . 7\X X\13 . . X 7\X 12\X X
X 16\17 . . . 29\9 . . 19\15 . . X
X\9 . . 6\23 . . . 11\11 . . . X
X\16 . . . 23\19 . . . . 9\X X X
X X X\22 . . . 19\8 . . . 30\X 6\X
X X 6\X 15\21 . . . . 11\19 . . .
X X\22 . . . 11\21 . . . 4\8 . .
X X\7 . . X\3 . . X\9 . . . X
X X X X X\12 . . X X\12 . . X
X means there is no number
X\number ; number defines sum of numbers on the right side of number
number1\number2; number 1 is sum of numbers below it; number 2 is sum
of numbers on the right side of number
number\X; sum of numbers below it
. empty space for [1-9]
there cannot be 2 same numbers in sum of one number
Max size of Table will be 32x32
I have to use malloc, realloc and struct in C
My Idea is to create struct CELL with char*[5], but it is no effective still to use retyping
Hint: a cell is either:
free for containing any digit between 1 and 9
non-free; then it is a pair of (optional) sums.

Resources