This is something i have been experimenting with for a bit, it took a while just to get it working. I put it here in-case any one can improve it as i made it to use a fix grid size that one has to make before dragging the script in. It can go on forever as it should if the generation cap i put in is removed.
Feel free to use it and improve it, to all those who like conway's game of life.
// tinguely 2017
// check for false group so no further checks made, or stride to avoid making string groups
// so far, about 10 seconds per generation...
key u_key;
integer width = 15;
integer height = 15;
// just use this grid instead of making a new one each time
list cells;
// for searching rows/cols
integer step = width;
//list test_pattern = ["4#5","5#5","3#6","4#6","4#7","4#8"];
list test_pattern = ["3#6","4#6","5#6","4#5","5#4"];
// insert patterns here when cells is built, e.g "r pentomino"
// ##
// ##
// #
//
// (4,5) (5,5)
// (3,6) (4,6)
// (4,7)
// frequently updated lists used for testing cells
list new_cells;
list test_cells;
list rects_blank;
list rects;
list test_cell;// only for get neighbours, one cell element
// for building the empty base_grid
list sqr_empty(){
rects_blank = [];
integer x;
integer y;
for(x = 0; x < width; ++x){
for(y =0; y < height; ++y){
rects_blank = rects_blank + [(string)x+"#"+(string)y+"?"+"FALSE"];
}
}
return rects_blank;
}
// a base grid but with a 'test_pattern' added
list sqr()
{
// both outer loops
rects = [];
integer i;
integer j;
// inner pattern loop
integer a;
integer b = llGetListLength(test_pattern);
//
string rect_str;
integer match;
integer bool_marker;
string rect_coords;
string pattern;
for(i = 0; i < width; ++i){
for(j =0; j < height; ++j){
rect_str = (string)i+"#"+(string)j+"?"+"FALSE";
match = 0;
for(a= 0; a < b; ++a){
bool_marker = llSubStringIndex(rect_str, "?");
rect_coords = llGetSubString(rect_str, 0, bool_marker-1);
pattern = llList2String(test_pattern, a);
if (rect_coords == pattern){
rects = rects+[pattern+"?TRUE"];
match = 1;
}
}
// if match is still 0 here, add as usual
if (match == 0){
rects = rects+[rect_str];
}
}
}
return rects;
}
//helper for get_neighbours
list get_cell(integer x, list c)
{
// plumbing, uses markers in cell string to get values needed
string cell_str = llList2String(c, x);
integer num_marker = llSubStringIndex(cell_str, "#");
string x_coord = llGetSubString(cell_str, 0, num_marker-1); //inc
integer bool_marker = llSubStringIndex(cell_str, "?");
string y_coord = llGetSubString(cell_str, num_marker+1, bool_marker-1); //inc
string bool_str = llGetSubString(cell_str, bool_marker+1, -1); //inc
return [x_coord, y_coord, bool_str];
}
string get_cell_coords(integer x, list c)
{
string cell_str = llList2String(c, x);
integer bool_marker = llSubStringIndex(cell_str, "?");
string coords = llGetSubString(cell_str, 0, bool_marker-1);
return coords;
}
string get_cell_single_coord(integer x, list c, string get_coord)
{
string cell_str = llList2String(c, x);
integer num_marker = llSubStringIndex(cell_str, "#");
string x_coord = llGetSubString(cell_str, 0, num_marker-1); //inc
integer bool_marker = llSubStringIndex(cell_str, "?");
string y_coord = llGetSubString(cell_str, num_marker+1, bool_marker-1); //inc
if (get_coord == "X"){
return x_coord;
}
if (get_coord == "Y"){
return y_coord;
}
else{return "e";} // check for e later
}
string get_cell_bool(integer x, list c)
{
string cell_str = llList2String(c, x);
integer bool_marker = llSubStringIndex(cell_str, "?");
string booly = llGetSubString(cell_str, bool_marker+1,-1);
return booly;
}
// checking true / false on individual cells
integer get_neighbours(integer i)
{
integer alive_neighbours = 0;
test_cell = get_cell(i, cells); // dont want to call get_cell_single_coord() twice here
// more plumbing
integer x = (integer)llList2String(test_cell, 0);
integer y = (integer)llList2String(test_cell, 1);
// now check
if (x > 0 && x < width - 1 && y > 0 && y < height - 1){
//left
if (get_cell_bool(i-1, cells) == "TRUE"){
alive_neighbours += 1;
}
// right
if (get_cell_bool(i+1, cells) == "TRUE"){
alive_neighbours += 1;
}
//top
if (get_cell_bool(i-step, cells) == "TRUE"){
alive_neighbours += 1;
}
//top left
if ( get_cell_bool(i-step-1, cells) == "TRUE"){
alive_neighbours += 1;
}
//top right
if ( get_cell_bool(i-step+1, cells) == "TRUE"){
alive_neighbours += 1;
}
// bottom
if ( get_cell_bool(i+step, cells) == "TRUE"){
alive_neighbours += 1;
}
//bottom left
if (get_cell_bool(i+step-1, cells) == "TRUE"){
alive_neighbours += 1;
}
//bottom right
if (get_cell_bool(i+step+1, cells) == "TRUE"){
alive_neighbours += 1;
}
}
test_cell=[];
return alive_neighbours;
}
// use helper method get_neighbours to change states of each cell
list check_alive_cells()
{
//cant nest lists
test_cells = sqr_empty();
integer i;
integer max = llGetListLength(cells);
string replacement;
for(i = 0; i < max; ++i){
if (get_cell_bool(i, cells) == "FALSE"){
integer alive_neighbours = get_neighbours(i);
if(alive_neighbours == 3){
// set to TRUE
replacement = get_cell_coords(i,test_cells) + "?TRUE";
test_cells = llListReplaceList(test_cells,[replacement],i,i);
replacement="";
}
}
// -----
if (get_cell_bool(i, cells) == "TRUE"){
integer alive_neighbours = get_neighbours(i);
if(alive_neighbours > 3 || alive_neighbours < 2){
replacement = get_cell_coords(i,test_cells) + "?FALSE";;
test_cells = llListReplaceList(test_cells,[replacement],i,i);
replacement="";
}
if(alive_neighbours == 2 || alive_neighbours == 3){
replacement = get_cell_coords(i,test_cells) + "?TRUE";;
test_cells = llListReplaceList(test_cells,[replacement],i,i);
replacement="";
}
}
}
// now change cells
cells = test_cells;
return test_cells; // a snapshot of what was just done
}
// start producing
begin(integer n){
integer gen; // number of evolution steps
integer max = llGetListLength(new_cells);
integer i;
string row;
while(gen < n){
//llOwnerSay( llGetTimestamp() );
// test one generation per touch for now
new_cells = check_alive_cells();
max = llGetListLength(new_cells);
//test with link colours
for(i = 0; i < max; ++i){
//llOwnerSay((string)i + " "+ get_cell_bool(i, new_cells) );
if(get_cell_bool(i, new_cells) == "TRUE" ){
llSetLinkColor(i+1,<0.0,0.0,0.0>,ALL_SIDES);
}
if(get_cell_bool(i, new_cells) == "FALSE" ){
llSetLinkColor(i+1,<1.0,1.0,1.0>,ALL_SIDES);
}
}
llSetText("Game of life:\n***\n Generation: " + (string)gen+"\n***", <1,1,1>, 1.5);
gen += 1;
//llOwnerSay( "memory use: " +(string)llGetUsedMemory() );
//llOwnerSay( "Done..."+(string)gen);
}
}
default
{
state_entry()
{
u_key = llGetOwner();
// set info text
llSetText("", <1,1,1>, 1.5);
// reset all linked prims, link number starts at 1, so 1 to 226
integer a;
integer b = llGetNumberOfPrims();
for(a =0; a < b;++a){llSetLinkColor(a+1,<1.0,1.0,1.0>,ALL_SIDES);}
cells = sqr();
begin(15); // integer generations
}
touch_start(integer total_number)
{
//begin();
if(llDetectedKey(0) == u_key){
llResetScript();
llOwnerSay( "Done...");
}
}
}