Windows [SOLVED] Help: I can't solve an array iteration

Hello!

I have been stuck on a 2D array iteration for 6 hours now, I'd love some assistance.
I am successfully reading in data from a text file--the data is:

GUN1|2|30|120|1|-1|10|20|1|0|2|0|30|3|0|-4|
GUN2|6|15|45|1|-4|10|5|1|8|3|45|15|3|0|-4|
GUN3|11|30|120|1|5|5|3|1|13|0|100|30|3|0|-4|
GUN4|7|30|120|3|9|4|4|1|17|0|110|30|3|0|-4|
GUN5|10|8|120|1|-17|10|5|4|14|0|130|8|3|0|-4|
GUN6|8|5|15|10|-40|20|15|1|18|0|200|5|3|0|-4|
GUN7|9|20|200|2|-3|20|15|1|18|0|200|20|7|0|-4|
GUN8|9|200|1000|2|5|10|15|1|18|0|100|200|7|0|-4|

The code below takes each value in between the "|" and stores it in a 2D array, val [i, j].

Code:
var file, str, str_pos, str_temp, val, num, i, j, test;
file = file_text_open_read("guns.txt");

if (file != -1)  // if the file exists...
{
  str_pos  = 1;
  str_temp = "";
  j = 1;

  for (i = 1; i < 9; i++)  // for as many weapons that exist...
  {
  str = file_text_read_string(file);  // read a line into str
  //show_message(str);  // check what we got
  file_text_readln(file);  // skip to next line
  
  for (j = 1; j < 17; j++)  // for as many properties as each gun has...  
  {
  while (str_pos < string_length(str))  // while we are not at the end of the string...  
  {
  while (string_char_at(str, str_pos) != "|")  // while we have not reached a "|" at said position...
  {
  str_temp += string_char_at(str, str_pos);  // our temporary string gets a new character added to it, from said position
  str_pos += 1;  // increment the position in the string
  }
  
  // ...We reached a "|" so store what we have so far as a value in the array...
  if (j == 1)  // if the first iteration is the weapon description, must store as text value
  {
  val[i, j] = string(str_temp);  // store it as a text value, not a real number
  str_pos  += 1;  // increment the string position, taking as past the "|"
  str_temp = "";  // clear the temp variable, ready for fresh input
  }
  else  
  if (j > 1)  // j must not be 1, so we're on to the real numbers
  {
  val[i, j] = real(str_temp);  // store it as a real number
  str_pos  += 1;  // increment the string position, taking as past the "|"
  str_temp = "";  // clear the temp variable, ready for fresh input
  }
  
  //test = "TEST" + string(i) + " " + string(j);
  //show_message(test);
  j++;
  }  
  }
  }
}

The first series goes in ok, i.e. val[1, x] all the way to val[1, 16]. But the next series, val[2, x] does not.
The reason, as far as I can tell, is that I am incrementing the j value twice--once at the beginning of the for loop and once again within the for loop. I know it's wrong, but I can't figure out how to keep track of the for loop counter AND the array position at the same time, in this case.

The end result, if you were to type the values 'manually' into Gamemaker code is this, but for all 8 guns;

Code:
gun[i,1]  = 'GUN1';
gun[i,2]  = 2;
gun[i,3]  = 30;
gun[i,4]  = 120;
.
gun[i,16] = -4;
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Curious that you have a str_pos variable, while there's a built-in function called string_pos that does just about what you were trying to do. Code can be written like this:
Code:
var file = file_text_open_read("guns.txt"), val;
if (file < 0) exit; // no file
var i = 1;
while (!file_text_eof(file)) {
   var s = file_text_read_string(file);
   file_text_readln(file);
   for (var k = 1; k < 17; k++) {
      var p = string_pos("|", s): // find the char # of "|" in the string
      var v = string_copy(s, 1, p - 1); // set `v` to all that's before the "|"
      s = string_copy(s, p + 1, string_length(s) - p); // clip the string to be what's after the "|"
      if (k != 1) {
          val[i, k] = real(v); // for non-first values convert them to number
      } else val[i, k] = v; // no need for string(), it's already a string
   }
   i += 1;
} // while (!file_text_eof(file))
return val;
Do note, also, that arrays in GameMaker start from element 0, so your array technically has an extra free cell at the start of each column/row. Depending on how you deal with things, this may or may not become a problem at some point.
 
P

ParodyKnaveBob

Guest
Howdy, Mr. Nathan,

Sorry you're having so much trouble. Glad you're so close, though. $:^ ]

My assistance is meager, at least right this moment. I just wanted to clean up a tad so everyone (including myself and you for that matter) can follow the path a bit more simply. I'll try to return later to do more if no one else has stepped in. (That said, Yellow probably already solved this with his mouse hand tied behind his back. I, too, wonder about your array's non-zero index beginnings...)

Code:
var file, str, str_pos, str_temp, val, num, i, j, test;
file = file_text_open_read("guns.txt");

if (file != -1)  // if the file exists...
{
  str_pos  = 1;
  str_temp = "";
  j = 1;

  for (i = 1; i < 9; i++)  // for as many weapons that exist...
  {
    str = file_text_read_string(file);  // read a line into str
    //show_message(str);  // check what we got
    file_text_readln(file);  // skip to next line

    for (j = 1; j < 17; j++)  // for as many properties as each gun has...
    {
      while (str_pos < string_length(str))  // while we are not at the end of the string...
      {
        while (string_char_at(str, str_pos) != "|")  // while we have not reached a "|" at said position...
        {
          str_temp += string_char_at(str, str_pos);  // our temporary string gets a new character added to it, from said position
          ++str_pos;  // increment the position in the string
        }

        // ...We reached a "|" so store what we have so far as a value in the array...
        if (j == 1)  // if the first iteration is the weapon description, must store as text value
        {
          val[i, j] = string(str_temp);  // store it as a text value, not a real number
          ++str_pos;  // increment the string position, taking us past the "|"
          str_temp = "";  // clear the temp variable, ready for fresh input
        }
        else if (j > 1)  // j must not be 1, so we're on to the real numbers
        {
          val[i, j] = real(str_temp);  // store it as a real number
          ++str_pos;  // increment the string position, taking as past the "|"
          str_temp = "";  // clear the temp variable, ready for fresh input
        }

        //test = "TEST" + string(i) + " " + string(j);
        //show_message(test);
        j++;
      }
    }
  }
}

Regards,
Bob


Okay, I looked through, and as I suspected, your for(j) loop isn't doing much for you anyway. Ironically, what it does do for your j, you're missing out on other variables: resetting between loops. $:^ ]

I suggest you add a breakpoint at the very top of this script (or action?), run this in the debugger (F6), set one window-tab-thingy to Local Variables, and step through the code line by line. It should all become clear soon enough. (You'll probably also see how/why your while(j){j++} loop does all the work for your for(j) code.)

Also, just a couple quick tips I noticed: You surely don't need to wrap str_temp in string(), right? $:^ ] And, if(j==1){}else if(j>1){} really doesn't need the second if since you start at 1 and go up anyway: if(j==1){}else{} should suffice.

I hope this helps,
Bob $:^ J
 
Last edited by a moderator:
Hi YellowAfterLife,
Straight up---thanks a million! It now works perfectly--that's some spiffy code there.
Point taken on the string wrapper and unnecessary if for j == 1, ParodyKnaveBob.

I had a hunch before posting that people would point the finger at the array start point being 1 and not 0. :rolleyes:
In this case, it's on purpose, but thanks for looking out for me there too!

Finally, I'd just like to say, that every time I come here I am overwhelmed with the generosity of people. It's a really great thing.
Cheers,
Nathan.
 
Top