Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Script keeps getting slower

BloodyRain Rang
Registered User
Join date: 23 Jun 2008
Posts: 3
11-19-2008 04:33
I'm working on a game machine, its made of 52 prims, 3 for the base and the remaining 49 are buttons aligned as 7 x 7 field.

The game system is that these buttons get colored with 1 of 6 colors and you click one button and click then the button above, below, left or right of that one to swap them.

If you get 3 or more in a row or column then these get black, should be refilled and then you get your points.

Not to mention that i don't have a good function to detect complex combos like:

this gets to this
OOXO -> OOXO -> OOOO
OOXO -> OOXO -> OOOO
XXOX -> XXXO -> XXOO
OOXO -> OOXO -> OOOO

but thats not my main problem. It is the problem that after a specific time of turns the thing gets slower and slower until it freezes.

If someone thinks that i have long lists, you're wrong.

It only contains 3 Lists, 1 6 Entrys long (colors) and 2 array lists with 7 entrys (link id's of the buttons and the other has the colors)

and only the color list gets changed the whole time. The script seems to get slower after around 50k reads of button colors or maybe 2k colorchanges. I dunno.

I would now like to hear someideas about what i can take a look where i maybe can look for bad code constructions or what ever, im open for all ideas.
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
11-19-2008 04:42
In a case like this it would be impossible to troubleshoot just from description. You will need to post the code for us to be of any help.
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
BloodyRain Rang
Registered User
Join date: 23 Jun 2008
Posts: 3
11-19-2008 05:15
I already thought that this would be the case, well although i didnt want to post the code but i want to get this thing running.

The only thing that is missing here are the script in the buttons but that only tells this one via linkmessage which one got pressed. This comes with num = 20 with the msg as button name.



float dcol = 0.3;
float lcol = 1.0;

vector blank_color = <0.9,0.9,0.9>;
vector color_1 = <lcol,dcol,dcol>;
vector color_2 = <dcol,dcol,lcol>;
vector color_3 = <lcol,lcol,dcol>;
vector color_4 = <dcol,lcol,dcol>;
vector color_5 = <lcol,dcol,lcol>;
vector color_6 = <dcol,lcol,lcol>;

list colors = [color_1,color_2,color_3,color_4,color_5,color_6];

list button_ids;
list button_colors;

string selected = "";

key player;
integer score;

integer checks;
integer fills;
integer getids;
integer getcols;
integer setcols;
integer getfree;
integer swaps;



SetScoreCells(){
integer prims = llGetNumberOfPrims();
integer i; string name; integer s;

for(i = 1; i <= prims; i++){
name = llGetLinkName(i);
if(llGetSubString(name,0,4) == "Score";){
s = (integer)llGetSubString(name,5,5);
llMessageLinked(i, 204004, llList2CSV([-100, 8-s]), "''''";);
}
}
}

integer GetButtonID(integer x, integer y){
getids+=1;
string btns = llList2String(button_ids,x-1);
return llList2Integer(llCSV2List(btns),y-1);
}

integer GetButtonID2(string ID){
return GetButtonID((integer)llGetSubString(ID,0,0),(integer)llGetSubString(ID,1,1));
}

vector GetButtonColor(integer x, integer y){
getcols+=1;
string cols = llList2String(button_colors,y-1);
return (vector)llList2String(llParseString2List(cols,[";"],[]),x-1);
}

vector GetButtonColor2(string ID){
return GetButtonColor((integer)llGetSubString(ID,0,0),(integer)llGetSubString(ID,1,1));
}

SwapColors(string ID1, string ID2){
swaps+=1;
integer x1 = (integer)llGetSubString(ID1,0,0);
integer y1 = (integer)llGetSubString(ID1,1,1);
integer x2 = (integer)llGetSubString(ID2,0,0);
integer y2 = (integer)llGetSubString(ID2,1,1);
list l1 = llParseString2List(llList2String(button_colors,y1-1),[";"],[]);
list l2 = llParseString2List(llList2String(button_colors,y2-1),[";"],[]);
list nl1; list nl2;
vector col1; vector col2;
if(((x1 == x2-1 || x1 == x2+1) && y1 == y2) || ((y1 == y2-1 || y1 == y2+1) && x1 == x2)){
//if(y1 >= y2-1 && y1 <= y2+1){
col1 = GetButtonColor2(ID1);
col2 = GetButtonColor2(ID2);
SetButtonColor(x1,y1,col2);
SetButtonColor(x2,y2,col1);
//if(y1 == y2){
//nl1 = llListReplaceList(l1,[col2],x1-1,x1-1);
//nl1 = llListReplaceList((nl1 = [])+nl1,[col1],x2-1,x2-1);
//button_colors = llListReplaceList((button_colors = []) + button_colors,[llDumpList2String(nl1,";";)],y1-1,y1-1);
//}else{
//nl1 = llListReplaceList(l1,[col2],x1-1,x1-1);
//nl2 = llListReplaceList(l2,[col1],x2-1,x2-1);
//button_colors = llListReplaceList((button_colors = []) + button_colors,[llDumpList2String(nl1,";";)],y1-1,y1-1);
//button_colors = llListReplaceList((button_colors = []) + button_colors,[llDumpList2String(nl2,";";)],y2-1,y2-1);
//}
string id_1 = (string)GetButtonID2(ID1);
string id_2 = (string)GetButtonID2(ID2);

llSetLinkColor((integer)id_1,col2,0);
llSetLinkColor((integer)id_2,col1,0);
//ReColor();
llMessageLinked(GetButtonID2(id_1),11,"disable","";);
llMessageLinked(GetButtonID2(id_2),11,"disable","";);
//}
}
}

SetButtonColor(integer x, integer y, vector color){
setcols+=1;
list l1 = llParseString2List(llList2String(button_colors,y-1),[";"],[]);
//llOwnerSay((string)l1);
l1 = llListReplaceList((l1 = []) + l1, [color], x-1,x-1);
//llOwnerSay((string)l1);
button_colors = llListReplaceList((button_colors=[])+button_colors,[llDumpList2String(l1,";";)],y-1,y-1);
//ReColor();
//nl1 = llListReplaceList(l1,[col2],x1-1,x1-1);
//nl1 = llListReplaceList((nl1 = [])+nl1,[col1],x2-1,x-1);
//button_colors = llListReplaceList((button_colors = []) + button_colors,[llDumpList2String(nl1,";";)],y1-1,y1-1);
llSetLinkColor(GetButtonID(x,y),color,0);
}

ReColor(){
integer x;
integer y;
for(y = 1; y < 8; y++){
for(x = 1; x < 8; x++){
llSetLinkColor(GetButtonID(x,y),GetButtonColor(x,y),0);
}
}
}

ShuffleBoard(){
button_colors = [];
integer x; integer y;
string cols;
for(y = 1; y < 8; y++){
cols = "";
for(x = 1; x < 8; x++){
vector col = llList2Vector(colors,(integer)llFrand(5));
cols += (string)col + ";";
llSetLinkColor(GetButtonID(x,y),col,0);
}
button_colors += [cols];
}
CheckColors();
//SetButtonColor(4,4,<1,1,1>;);
}

vector GetFreeColor(list cols){
getfree+=1;
integer i; integer i2;
vector c;
list avail = [] + colors;
for(i=0;i<llGetListLength(cols);i++){
c = llList2Vector(cols,i);
if(c == <0,0,0>;){
cols = llDeleteSubList(cols,i,i);
i--;
}else{
i2 = llListFindList(avail,[c]);
if(i2 > -1){
avail = llDeleteSubList(avail,i2,i2);
}
}
}
return llList2Vector(avail,0);
}

CheckColors(){
integer x; integer y; vector col;
vector col_u; vector col_d; vector col_l; vector col_r;
for(y = 1; y < 8; y++){
for(x = 1; x < 8; x++){
col = GetButtonColor(x,y);
if(y > 1){col_u = GetButtonColor(x,y-1);}
if(y < 7){col_d = GetButtonColor(x,y+1);}
if(x > 1){col_l = GetButtonColor(x-1,y);}
if(x < 7){col_r = GetButtonColor(x+1,y);}
if((col == col_u && col == col_d) || (col == col_l && col == col_r)){
SetButtonColor(x,y,GetFreeColor([col,col_u,col_d,col_l,col_r]));
}
}
}
}

Check4Three(){
integer x; integer y; vector col; integer setted; integer cols_detc;
vector col_u; vector col_d; vector col_l; vector col_r; integer i;
do{
checks += 1;
for(y = 1; y < 8; y++){
for(x = 1; x < 8; x++){
col_l = <0,0,0>;
col_r = col_l;
col_u = col_l;
col_d = col_l;
setted = 0;
col = GetButtonColor(x,y);
if(y > 1){col_u = GetButtonColor(x,y-1);}
if(y < 7){col_d = GetButtonColor(x,y+1);}
if(x > 1){col_l = GetButtonColor(x-1,y);}
if(x < 7){col_r = GetButtonColor(x+1,y);}
if((col == col_u && col == col_d) && col != <0,0,0>;){
cols_detc = 1;
for(i=y-1;i>0;i--){
if(GetButtonColor(x,i) == col){cols_detc+=1;SetButtonColor(x,i,<0,0,0>;);}
else{i=0;}
}
for(i=y+1;i<8;i++){
if(GetButtonColor(x,i) == col){cols_detc+=1;SetButtonColor(x,i,<0,0,0>;);}
else{i=8;}
}
//SetButtonColor(x,y-1,<0,0,0>;);
//SetButtonColor(x,y+1,<0,0,0>;);
if(cols_detc > 2){
score += cols_detc * cols_detc;
setted = 1;
}
}
if((col == col_l && col == col_r) && col != <0,0,0>;){
cols_detc = 1;
for(i=x-1;i>0;i--){
if(GetButtonColor(i,y) == col){cols_detc+=1;SetButtonColor(i,y,<0,0,0>;);}
else{i=0;}
}
for(i=x+1;i<8;i++){
if(GetButtonColor(i,y) == col){cols_detc+=1;SetButtonColor(i,y,<0,0,0>;);}
else{i=8;}
}
//SetButtonColor(x-1,y,<0,0,0>;);
//SetButtonColor(x+1,y,<0,0,0>;);
if(cols_detc > 2){
score += cols_detc * cols_detc;
setted = 1;
}
}
if(setted == 1){SetButtonColor(x,y,<0,0,0>;);}
}
}
}while(Refill() == 1);
ShowScore();
}

integer Refill(){
integer x; integer y; integer i; vector col; integer filled = 0;

for(y = 1; y < 8; y++){
for(x = 1; x < 8; x++){
col = GetButtonColor(x,y);
if(col == <0,0,0>;){
filled = 1;
if(y == 1){SetButtonColor(x,y,llList2Vector(colors,llRound(llFrand(5))));}
else{SetButtonColor(x,y,GetButtonColor(x,y-1)); SetButtonColor(x,y-1,<0,0,0>;);}
}
}
}
fills += 1;
return filled;
//if(filled == 1){Refill();Check4Three();}
}

ShowScore(){
llSetText("Checks: " + (string)fills + " - Fills: " + (string)fills + " - GetCols: " + (string)getcols + " - SetCols: " + (string)setcols + " - Swaps: " + (string)swaps + " - GetIDs: " + (string)getids + " - GetFree: " + (string)getfree,<1,1,1>,1);
string s = (string)score;
integer space = 8 - llStringLength(s);
for(space = space; space > 0; space--){
s = "0" + s;
}
llMessageLinked(LINK_ALL_OTHERS,-100,s,"";);
}



default
{
state_entry()
{
fills = 0;
checks = 0;
SetScoreCells();
ShowScore();
integer l_name; list buttons;
integer i; integer prims = llGetNumberOfPrims();
for(i = 0; i <= prims; i++){
l_name = (integer)llGetLinkName(i);
if(l_name >= 11 && l_name <= 77){
buttons += [(string)(l_name) + "_" + (string)i];
}
}
integer x; integer y;
for(x = 1; x < 8; x++){
string button_row;
for(y = 1; y < 8; y++){
for(i = 0; i < llGetListLength(buttons); i++){
string btn = llList2String(buttons,i);
if(((x*10)+y) == (integer)llGetSubString(btn,0,1)){
button_row += llGetSubString(btn,3,-1)+",";
}
}
}
button_ids += [button_row];
}
//llSetLinkColor(GetButtonID(1,1),<1.0,0.0,0.0>,0);
//llSetLinkColor(GetButtonID(7,1),<1.0,1.0,0.0>,0);
//llSetLinkColor(GetButtonID(1,7),<1.0,0.0,1.0>,0);
ReColor();
llMessageLinked(LINK_ALL_OTHERS,9,"cpu prim",(string)llGetLinkNumber());
}

link_message(integer s_num, integer num, string msg, key id){
//if(num == 11){
//llOwnerSay("num: "+(string)num);
//llOwnerSay("msg: "+msg);
//llOwnerSay("id: "+(string)id);
//}
if(num == 20){
if(selected == "";){
selected = msg;
llMessageLinked(GetButtonID2(msg),11,"select","";);
}else{
SwapColors(msg,selected);
llMessageLinked(GetButtonID2(msg),11,"disable","";);
llMessageLinked(GetButtonID2(selected),11,"disable","";);
Check4Three();
selected = "";
}
}
}

touch_start(integer num){
ShuffleBoard();
}

on_rez(integer param){llResetScript();}
}
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
11-19-2008 14:34
Have'nt finished going through the code but your nested "for's" popped out at me. This is kind of a mean trick to pull on the simulator when all you really need to do is this:

CODE

ReColor(){
integer x = 1;
integer y;
for (y = 1; y < 8; y++) {
x++;
llSetLinkColor(GetButtonID(x, y), GetButtonColor(x, y), 0);
}
}


Or even better since they are the same value anyways:

CODE

ReColor(){
integer y;
for (y = 1; y < 8; y++) {
llSetLinkColor(GetButtonID(y, y), GetButtonColor(y, y), 0);
}
}
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
11-19-2008 14:42
Actually I am kind of surprised t works through one complete cycle.

For's are 3 layers deep inside a do-while with conditional if/else tests intertwined.

You have to remember that recursion is always bad. Do's, Fors & While's can be thought of as controlled recursion in one sense and operate just fine by themselves but things can get pretty nasty real fast when you start stacking recursive functions on top of each other. Try getting a piece of paper and working out step by step what is happening in Check4Three() for instance. I guarantee that you will quickly get lost.

I wish I would have been able to point out a quick fix but as far as I can see, you actually need to do some refactoring instead.
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Wouter Hobble
Registered User
Join date: 25 Mar 2008
Posts: 21
11-20-2008 03:55
I am guessing that there is memory leaking going on. I would debug using http://wiki.secondlife.com/wiki/LlGetFreeMemory every so often.

What you could do is reset the script when the usage of memory goes beyond a certain point.

Also, have you compiled this in Mono or LSL, that may make a difference too.

Although I do agree that nesting loops is not the best way to go, the script should be releasing memory after the loops run and therefore the performance should not slowly get worse, just be bad to start with.

Good luck!
Escort DeFarge
Together
Join date: 18 Nov 2004
Posts: 681
11-20-2008 08:16
I think you've got lost in your own code. Which is a familiar feeling to us all and really means a design solution not a hack of what you have...

I have two suggestions both of which mean a major code refactor/rewrite:

1) Save yourself (and us) nearly 50 scripts by detecting buttons with llDetectedLinkNumber() instead of scripting each one.

2) Use a display cache to remember what colors buttons are displaying then use an optimized "render" function to update the display when required in one unified way.

I haven't done all your work for you - but the script below does pretty much everything you need and illustrates how much easier color swaps and "check for three" become when you operate on contiguous lists. You'll need to follow a prim naming convention (see the script). You can delete all the scripts in your buttons and just work with this single script in the root.

hth,
/esc

Compiled to LSL this script is more than acceptably fast, in Mono it's near-instantaneous.

CODE
//
float dcol = 0.3;
float lcol = 1.0;

vector blank_color = <0.9, 0.9, 0.9>;
vector color_1 = <lcol,dcol,dcol>;
vector color_2 = <dcol,dcol,lcol>;
vector color_3 = <lcol,lcol,dcol>;
vector color_4 = <dcol,lcol,dcol>;
vector color_5 = <lcol,dcol,lcol>;
vector color_6 = <dcol,lcol,lcol>;

list colors = [color_1,color_2,color_3,color_4,color_5,color_6];

list button_ids;
list button_colors;
list displayed_colors;

integer selected;

//
integer ROWS = 7;
integer COLS = 7;
//
initialize_board() {
// init id list to zeros
button_ids = [];
integer index;
integer length = ROWS * COLS;
for (index = 0; index < length; index++) {
button_ids += 0;
}

// find button prims and store their link ids
integer num_prims = llGetNumberOfPrims();
for (index = 1; index <= num_prims; index++) {
// Assuming a prim naming convention of e.g. "Button <col>, <row>"
list name_parts = llParseString2List(llGetLinkName(index), [" ", ","], []);
if (llGetListLength(name_parts) == 3 && llToUpper(llList2String(name_parts, 0)) == "BUTTON") {
integer col = llList2Integer(name_parts, 1) - 1; // convert to natural index
integer row = llList2Integer(name_parts, 2) - 1; // convert to natural index
// check these are valid coords and if so, store the link number
if (col >= 0 && col < COLS && row >= 0 && row < ROWS) {
integer button_index = row * COLS + col;
button_ids = llListReplaceList(button_ids, [index], button_index, button_index);
} else {
llOwnerSay("Invalid button definition: " + llGetLinkName(index));
}
}
}

// check there's a button registered for every position
for (index = 0; index < length; index++) {
integer id = llList2Integer(button_ids, index);
if (id == 0) {
llOwnerSay("No button for COL " + (string)(id % COLS) + ", ROW " + (string)(id / COLS));
}
}
shuffle_board();
}

// when compiled to mono - this is pretty mucn instantaneous
render() {
integer i;
integer board_length = llGetListLength(button_ids);
for (i = 0; i < board_length; i++) {
integer color = llList2Integer(button_colors, i);
integer displayed = llList2Integer(displayed_colors, i);
if (displayed != color) {
llSetLinkColor(llList2Integer(button_ids, i), llList2Vector(colors, color), ALL_SIDES);
}
}
displayed_colors = button_colors; // update cache
}

//
shuffle_board() {
button_colors = []; // clear
displayed_colors = [];
integer i;
integer num_colors = llGetListLength(colors);
integer board_length = llGetListLength(button_ids);
for (i = 0; i < board_length; i++) {
button_colors += (integer)llFrand(num_colors);
displayed_colors += -1; // clear display cache
}
render();
}

//
swap_colors(integer id1, integer id2) {
integer col1 = llList2Integer(button_colors, id1);
integer col2 = llList2Integer(button_colors, id2);
button_colors = llListReplaceList(button_colors, [col2], id1, id1);
button_colors = llListReplaceList(button_colors, [col1], id2, id2);
render();
}

//
integer is_same_color(integer id1, integer id2, integer id3) {
integer color1 = llList2Integer(button_colors, id1);
integer color2 = llList2Integer(button_colors, id2);
integer color3 = llList2Integer(button_colors, id3);
if (color1 == color2 && color1 == color3) {
return TRUE;
} else {
return FALSE;
}
}

//
integer check_for_threes() {
integer num_threes = 0;
integer row;
integer col;
//
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
integer button_index = row * COLS + col;
// check horizontal
if (col > 0 && col < COLS - 1) {
num_threes += is_same_color(button_index - 1, button_index, button_index + 1);
}
// check vertical
if (row > 0 && row < ROWS - 1) {
num_threes += is_same_color(button_index - COLS, button_index, button_index + COLS);
}
}
}
return num_threes;
}

//
default {
state_entry() {
initialize_board();
}

// Note prim naming conventions!
touch_start (integer num) {
integer linknum = llDetectedLinkNumber(0);
string name = llToUpper(llGetLinkName(linknum));
if (name == "NEW GAME") {
shuffle_board();
// reset_score
} else if (name == "SCORE") {
// do nothing - or whatever
} else if (linknum == llGetLinkNumber()) {
// me - do nothing
} else {
integer button = llListFindList(button_ids, [linknum]);
if (button != -1) {
if (selected == -1) {
selected = button;
} else {
swap_colors(button, selected);
selected = -1;
integer num_threes = check_for_threes();
// update score
llOwnerSay("[debug] Number of threes is " + (string)num_threes);
}
}
}
}

on_rez(integer param) {
llResetScript();
}
}
_____________________
http://slurl.com/secondlife/Together
BloodyRain Rang
Registered User
Join date: 23 Jun 2008
Posts: 3
11-20-2008 13:25
Thanks a lot Escort, I'll try this out. I already thought about using llDetectedLinkNumber but my first try didn't work, also i wanted to use integers for the colors instead of the vectors that are not csv'able.

About mono and the memory, i compiled it in mono from the beginning and i already thought about the llGetFreeMemory and it said the whole time more than 30k.

I'll come back and tell my experiences with the new script when im done testing it.
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-21-2008 12:26
I have to agree w/ escort on the use of prim numbers, you'll save yourself headaches in the long run.

I did pick out one line that MAY be the original culprit, though I haven't had time to check it inworld or completely parse the changes

CODE


SetButtonColor(integer x, integer y, vector color){
gIntSetcols+=1;
list l1 = llParseString2List(llList2String(gLstButton_colors,y-1),[";"],[]);
l1 = llListReplaceList((l1 = []) + l1, [color], x-1,x-1);
gLstButton_colors = llListReplaceList((gLstButton_colors=[])+gLstButton_colors,[llDumpList2String(l1,";")],y-1,y-1);
llSetLinkColor(GetButtonID(x,y),color,0);
}

second to the last line you rebuild button_colors, (names changed so I could quickly search all the globals used)... exactly how big is that list becoming? if it continues expanding it might explain the slowdown (list functions being inherently slow, the bigger the slower, even if it doesn't hit the memory cap)

another concern is the use of CSV functions, since it adds a layer of complexity that you probably don't need internally on the script (though it makes debugs easier to read/write)

I also can't remember LSL's behavior for certain, but you should be aware of it other languages; it's a bad idea to name your variables the same as is used in another section of code due to possibilities of overloading (or overwriting) in sub functions.

as for a good way to check 3in-a-row, you might try a bitmasking function, per color (you have 6 or 7 I can see), which can possibly be sped up by treating the individual colors as a bitmask set as well. I think this will ultimately be faster than checking neighbors, as you can process several at once (too bad we have no real arrays) if you use 3 bits per tile (that's 8 possible colors), you can squeeze a row of 10 in an integer, packed into a list the height of your board, horizontal comparisons would run on a single list item, vertical comparison would run on 3 list items at once.

you might also check into which types of prim changes cause a full prim update vs a mini update, I can't remember if color changes are full or not, but IIRC texture offsets aren't, so a gridded texture might make the game less sim/network intensive if so. (2x3 texture grid with a transparency switch maybe?)
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -