2D Array

Sunflower

  • Posts: 591
Update:
The most recent version can be found as 2D Array Test (it's called so because... well, I'm not sure if *everything* works properly yet, especially the iOS part). It uses Global Custom Blocks, so now you don't have to attach it anywhere! If someone would like to check it out, please do it, though if you work on iOS you need to replace some code header with another one in array-creating function.

---

Having seen the same question over and over, I decided to make a set of functions for those who need to use 2D Arrays sometimes.

You can find them as Scene Behavior, under "2D Array".Yes, this one with Tic-Tac-Toe-ish icon. Hopefully those blocks are intuitive enough, especially for those who are experienced with lists. Once you attach the behavior, you can never look at it again; just use the set of custom blocks made specially for you in whichever behavior you like!

Note that:
 - it was made for 2D Arrays which have fixed size from the beginning. Actually I could make resizing already existing them as well, but I'll refrain from that until someone explicitly asks me to (and explains why it's important in their game), since it's quite a bit of additional work.
 - you should always attach "2D Array" Behavior to the scenes wherever you use it!
 - technically 2D Array is a list and you *can* use list-related functions for it, but it's definitely not recommended! If you feel you need to use them, check the structure of 2D Array in behavior itself first, and pay attention to the 3-items long header at the beginning (0th item being the width, 1st being height and 2nd an "empty" item defined by creator)!
Oh, and you shouldn't use 2D Array related functions to normal lists, either. I can't even imagine what horrors would happen should someone do it!

So yes, any questions? Any bugs encountered? I haven't really tested it too much (just checked if basic functions are working), so if someone could try it out (and when encountering a bug, make sure that it's my system to blame), I'd be grateful. ^ ^'

« Last Edit: May 12, 2012, 01:32:09 am by Sunflower »

captaincomic

  • *
  • Posts: 6109
I just took a peek, I'm sure many people will find this very useful ;)
I'm just wondering, couldn't the blocks all be global custom blocks, then you would not need to attach the behavior anywhere.

Sunflower

  • Posts: 591
Uh, now that you mention it, I probably could, but I'm not sure what would happen to the array creator, which uses a list attribute. And since people would need to attach it for creator, anyway, I didn't see the reason to make other block global, either. Actually, having some blocks work and others don't could make things quite confusing for user. O.o'

(though maybe it's just misunderstanding on my side >.<)

captaincomic

  • *
  • Posts: 6109
I'm not sure, but I think it would work even for the array creator block.

Sadly it's not possible to change a block from a custom block to a global custom block easily :-\ I guess it would be a lot of work to make all the blocks anew.

MyChairHasALooIn

  • Posts: 310
Sunflower, let's make beautiful game babies together, you just solved a major problem for me :)

Silux

  • Posts: 438
Added to my "things to absulutely check" list!
That will be very useful when making array of objects!
Currently working at:
Starwarrior 2097(my main project)
How to make successful games in Kongregate and the world(article)

Sunflower

  • Posts: 591
Alright, could anybody check the "2D Array Test" behavior I've just put on Forge? This one was made in 2.0 and while it's not really that different than original one, it's made of Global Custom blocks, so now it should work even without attaching the behavior to the scene!

The greatest drawback is that in array creating block I needed to put some code initializing certain variable there, and it's different for Flash and iOS, so if you're working on iOS, you need to pick the other code. But hey, it's not that bad considering that you don't have to include in every single scene where you want to use it, is it? ;)

Leaufai

  • Posts: 327
Your 2D Array behavior (I assume 2D Array of May 27th is the most up-to-date) sounds great. I'm a bit confused as to how I'm supposed to use it. Perhaps you could do a step-by-step on how I would use your for my situation? I would very much appreciate it. I think it's a pretty standard use of the standard 2D so it might also act as a sort mini-tutorial for other people who have some troubles with your behavior.

Anyway, this is my situation: I have this word game in which I need to rapidly check whether a word is in the dictionary or not. Even splitting up the words by first letter still means the game has to go through thousands of entries per letter. A 2D array would be a godsend if I understand the concept correctly. Since it's a list inside a list, I could sort the words by the first two letters (AA, AB, AC, AD, etc.) meaning instead of looking through a few thousands entries it only needs to look through a couple of hundred or dozen. That would speed up the game tremendously.

What I don't understand is:

1. How do I set up the list? Can a 2D array be imported using the text import feature or do I have to create the list on game load and how would I do that?
2. How do I look up a word in one of the columns?

See attachment to see how I imagine it'd be organized.

Thanks in advance.

Sunflower

  • Posts: 591
Uhm... actually, no, it doesn't work exactly like that. It's more like a grid structure, with fixed width and height, rather than a list of lists. O.o'

However, what about making scene behavior with two hidden list attributes: "Dictionary" and "Index", text attributes "Prefix" and "Suffix" and number attribute "List ID"? And then make a custom block adding an entry to dictionary:
Code: [Select]
add [Entry] to dictionary    //Entry is a text-type field
  set Prefix to [[Entry] in all upper case]
  set Suffix to [ part of [Prefix] start: [2] end: [[Prefix] length] ]
  set Prefix to [ part of [Prefix] start: [0] end: [2] ]
  set List ID to [number of items in [Index]]
  repeat [number of items in [Index]]
    if <[get item # [current loop count] from Index] = [Prefix]>
      set List ID to [current loop count]
      exit loop
 
  if <[List ID] = [number of items in [Index]]>
    add [Prefix] to [Index]
    add [create new list] to [Dictionary]
  add [Suffix] to [get item # [List ID] from [Dictionary]]
And here's some block for checking whether there's such entry in dictionary! As a bonus, you know!
Code: [Select]
[Entry] is in dictionary?
  //pretty much copy paste of the previous block with a little exception at the end
  set Prefix to [[Entry] in all upper case]
  set Suffix to [ part of [Prefix] start: [2] end: [[Prefix] length] ]
  set Prefix to [ part of [Prefix] start: [0] end: [2] ]
  set List ID to [number of items in [Index]]
  repeat [number of items in [Index]]
    if <[get item # [current loop count] from Index] = [Prefix]>
      set List ID to [current loop count]
      exit loop
 
  if <[List ID] = [number of items in [Index]]>
    return <false>
  otherwise
    return <[get item # [List ID] from [Dictionary] contains [Suffix]]>
I hope this helps? O.o'

Also, you could add another list attribute, non-hidden one, called "Default List", and then do something like that in "when created":
Code: [Select]
for each item in [Default List]
  add [item] to dictionary
 //note that it's THE CUSTOM BLOCK, not "add [item] to [List called Dictionary]" one!

Leaufai

  • Posts: 327
Thank you for replying so quickly.

I managed to get your custom blocks working with the rest of my game. Had to use a Game Attribute for the DefaultList thing as a normal list with 100,000+ words would make saving impossible on my laptop. The time it takes to check words hasn't noticeably decreased, but I imagine that has more to do with my computer's ability to calculate things more quickly than a iPhone could (which is where I needed the speed gain for, especially the 1st gen iPhones aren't as quick). It's also more manageable as it used to be a multi-page behavior before. When working on my laptop that behavior  was almost uneditable due to the many blocks.

One problem that I'm still facing is that the game now takes a long time to fade in. After the loading bar and the Stencyl splash the screen just turns black for a few seconds before it finally fades in. From the Flash player to the fading in it took around 5 seconds. Guessing that the game having to move the 100,000+ words from the DefaultList through the custom blocks into the new list had something to do with it, I disabled the When Created part. That reduced the loading time from 5 to 2 seconds, which is comparable to how fast it loaded with my previous system.

Five seconds is too long and I'd also like to have most of the loading of that massive dictionary list to happen in my first scene (aka the menu screen), with the list being available to later scenes. That way I don't have long loading times each time I enter a scene where I need the dictionary list.
How would I do go about doing that, while still keeping the 'first two letters' list sortation (which speeds up the dictionary word check part) thing that your custom blocks do? No doubt I'll have to add the behavior to the game's first scene and use Game Attributes to ensure the list's persistence in further scenes, but other than that I'm at a loss. Any help would be appreciated.

Sunflower

  • Posts: 591
Oh, actually, I've got an idea! ^^'
You just need to have a dictionary, right?
So, what if you make it *beforehand*?
I mean, if you have it already sorted, all you need to do is to have such input data:
Code: [Select]
000: AA+
001: H HED
//it makes AAH, AAHED, AA
002: AB+
003: A ACA
//it makes ABA, ACA, AB
004: AC
005: ACIA ACIAS ADEME
//it makes ACACIA, ACACIAS, ACADEME; without AC, because there's no plus sign
...
AAA: AT+
AAB: LAS, MOSPHERE, TACK,
//ATLAS, ATMOSPHERE, ATTACK, AT
...
CCC: CA
CCD: LIGRAPHY RT ST T
//CALIGRAPHY, CART, CAST, CAT; no CA, because there's no plus sign

Which would work this way:
 - items at the even positions (0, 2, 4, 6, ...) would be added to Index
 - items at the odd positions would be split into lists which would be added to Dictionary
 - if item at the even position has length of three (which I marked with plus sign), an empty string would be added to the recent list

This wouldn't require the adder Custom Block, apparently, and since you'll probably use the same data all the time, it should be safe to use already sorted list.
Here's what you'd add in creation code instead:
Code: [Select]
set List ID to [0]
while <[List ID] < [number of items in [Default List]]>
  add [ split [ get item # [[List ID * 2]+1] from [Default List]] into words] to [Dictionary]
  set Prefix to [ get item # [List ID * 2] from [Default List] ]
  if < [ [Prefix] length ] = 2>
    add [ Prefix ] to [ Index ]
  otherwise
    add [ part of [Prefix] start: [0] end: [2] ] to [Index]
    add [] to [get item # [List ID] from [Dictionary]]
"split something into words" should work quite fast; I've repeated 6000 times split for text counting 2000 words, which would make over 12 million words. It means that if you want to split about 100,000 words, it should take about 0.02 seconds (on my computer, at least, I don't know what about other devices); a frame lasts not much less than that.

So yes, maybe try using the dictionary already sorted in such way I presented at the beginning? ^^'
(the other thing would be to sort it, but I suppose that doesn't have to be made in Stencyl; rather in some language which allows to handle input/output files O.o')

Oh, and since Stencyl doesn't handle the lists in the most fortunate way, and I haven't found a way to clear lists so far, I suggest doing something like that:
 - keep the actual list in a text file, with each item in its line, however long that line would be
 - load that file to the behavior
 - if the list changed and you want to update the behavior Default List attribute, remove the behavior and add again; the list will be cleared! ^_^

Leaufai

  • Posts: 327
I sort of get what it all does on a basic level, but I haven't managed to get it to work. Attached is a screenshot of the behavior and a text file which has all words starting with an A on a single line. As I didn't understand how I would format it exactly like you did, I just formatted it like this:
Code: [Select]
aa;aah;aahed;aahing;aahs;aal;aalii;aaliis;
In the screenshot the Created part has a couple of empty fields. The first three used to have the DefaultList attribute, but as it made saving the game take very long I removed it. The fourth, the one with the red icon housed nothing as your code has it nothing there either. As a result it doesn't work. I tried putting some stuff I thought might go in there but they don't make it work either.

I realize me doing the DefaultList different might not make it work in the first place, but that didn't even matter since the rest didn't work properly either. Hopefully you can spot where it went wrong, how it should be formatted, etc.

I also have an idea on how to do it, but I don't know enough about lists to put it together or know if it'll work/possible. What I propose is to have the game only look between certain items in the dictionary. If that's possible I could have an index list that links the first letter or the first two letters to certain item limits. AA might be item #1-100. The game would then only look between those items for a match with the entry.


Sunflower

  • Posts: 591
Make the "Default List" a behavior attribute, not the Global one; this way it won't take so much time to save!

Also, if it doesn't allow you to use empty field in list adder, then maybe use "add [[] as text] to etc."?I think that it should work. If it still doesn't then I don't know, maybe try putting
add [code: [""]] to etc.

Also, that list of yours:
aa;aah;aahed;aahing;aahs;aal;aalii;aaliis;
would be formatted like this:
"aa+"
"h hed hing hs l lii liis"
It would treat such words as correct:
aa + h = aah
aa + hed = aahed
aa + hing = aahing
aa + hs = aahs
aa + l = aal
aa + lii = aalii
aa + liis = aaliis
aa <- because the first item is "aa+" rather than "aa", aa is treated as word too!

« Last Edit: August 08, 2012, 05:19:18 am by Sunflower »

Leaufai

  • Posts: 327
Did exactly what you did but the game took ages to load/fade in and when I tried to check one of the words that were in DefaultList the game froze. There's probably some way to make this work, but for now I'll go back to my cumbersome every-word-is-in-a-different list approach as I have other more pressing stuff to add/fix and this feature, while not efficient, works. Maybe I'll redesign that system to be less gargantuan using the things I learned about custom blocks from you. Either way, thanks for helping me; you were great! I especially can't believe how quick you responded each time.

tetsu0sh0

  • Posts: 49
Hi sunflower!
First off lemme extend my personal thanks for creating such a wonderful tool.
Secondly I would like to know how i go about using it?

I want to create 20x20 2D array with each index containing a list.

I notice your global block called "Create new 2D array with width_Height_ default item_"
How do you use it if it returns a value?

« Last Edit: August 28, 2012, 05:55:24 am by tetsu0sh0 »