2D Arrays
Monkey Forums/Monkey Programming/2D Arrays
| ||
I need some help with 2D arrays. I know how to convert to a 1d and I have read the existing topics here. I would like to know how to get this right so that I understand it. I want to declare the array and then set the number of elements with provided parameters at runtime. This is a level class for a 2d roguelike. Thanks!Class Level Field LevelWidth:Int Field LevelHeight:Int Field Tiles:Int[][] Field i:Int,j:Int Field walls:GameImage Method Generate:Void(Width:Int,Height:Int) LevelWidth=Width LevelHeight=Height Tiles=[New Int[Width],New Int[Height]] walls=game.images.Find("walls") For i=0 To LevelWidth-1 For j=0 To LevelHeight-1 Tiles[i][j]=Solid Next Next End Method Draw:Void() For i=0 to 19 Step 32 For j=0 to 14 Step 32 walls.Draw(i,j,,,,Solid) Next Next End End |
| ||
I know you said you've read the existing topics, but this issue was covered in this thread: http://monkeycoder.co.nz/Community/posts.php?topic=748. |
| ||
That topic isn't clear to me. None of the examples have it declared at top and sized in the code. A simple example is all that I would like. What I have looks like it should work to me, but it doesn't. |
| ||
the problem with your code is this lineTiles=[New Int[Width],New Int[Height]] It creates an array of arrays with two members, one a single dimensional array Width big, the second a single dimensional array Height big. What you want is Height objects Width big. Seeing as you don't know Height in advance you can't go Tiles=[New Int[Width],New Int[Width],New Int[Width],New Int[Width],New Int[Width],New Int[Width] ....] So you need to use a loop to create the array. |
| ||
Yes, that is what I want. I started using Blitz 2d 10 years ago and have used Max since it was in Beta. I am just not exactly getting the syntax in Monkey. Can I please get an example where the array is declared earlier and then sized once the dimensions are known? I have experimented with it many different ways and wasted a bunch of time that could be better spent on programming. I have read the other topic multiple times. Thanks for the help. |
| ||
Okay, but I'm just going to end up repeating what was already written. It doesn't matter where the variable name and type is declared. Here's a single dimensional Array:Function Main() Local Tiles:Int[] Tiles = New Int[10] Print Tiles.Length ' prints "10" End That declares Tiles to be an array of Ints and then initialises it with an array of length ten. You could also declare it directly: Local Tiles:Int[] = [0,0,0,0,0,0,0,0,0,0] Now, multidimensional arrays in Monkey follow the "Array of Arrays" model so, if you want a two-dimensional array that contains Ints, then you are going to be declaring an Array of Arrays of Ints. Function Main() Local Tiles:Int[][] Tiles = [New Int[2],New Int[3],New Int[4]] Tiles[2][3] = 99 Print Tiles.Length '3 Print Tiles[0].Length '2 Print Tiles[1].Length '3 Print Tiles[2].Length '4 Print Tiles[2][3] '99 End Note that the arrays can be "ragged", i.e. the rows do not have to be the same length. So, coming back to your code above. You seem to have made a common error in your declaration: Tiles=[New Int[Width],New Int[Height]] I imagine that you think this is doing something like: Tiles = Int[Width][Height] ...and declaring a Width x Height array of Ints. If you read your declaration though, you'll see that you're actually declaring an array with two elements: one array of Ints of length Width and one array of Ints of length Height. In other words, your array only has two rows. If you want a Width x Height array then you need to declare each row as an array of the appropriate length. In the thread I pointed you to, there are at least two given code examples of how to do this with variable array sizes. |
| ||
If you're still struggling:Function AllocateArray:Int[][]( i:Int, j:Int) Local arr:Int[][] = New Int[i][] For Local ind = 0 Until i arr[ind] = New Int[j] Next Return arr End Function Main() Local Tiles:Int[][] Tiles = AllocateArray(3,4) Tiles[2][3] = 99 Print Tiles.Length '3 Print Tiles[0].Length '4 Print Tiles[1].Length '4 Print Tiles[2].Length '4 Print Tiles[2][3] '99 End |
| ||
That is much more clear, thank you. I wasn't clear on when new was needed either. Much appreciated. |
| ||
Yeah but can I do a: Local arr:Int[][] = New Int[5][5] For Local y = 0 to 4 For Local x = 0 to 4 arr[x][y] = 1 Next Next ? |
| ||
... |
| ||
I guess you cannot do it in one step like that. You need to create an array of arrays in step 1 (involving one call to New), and then create the subarrays inside the big array in step 2 (involving as many calls to New as there are subarrays), as in muddy_shoes' example. |
| ||
I'm trying to do the whole two dimensional array thing as explained above. However, I need an 2d array of class instances instead of a 2d array of ints. I have tried modifying the function, but I get null access errors trying to access the elements later in code...Global FIELD_X:int = 5 Global FIELD_Y:int = 7 local grid:Dice[][] grid=AllocateArray(FIELD_X,FIELD_Y) 'Randomize the grid Local x:Int Local y:Int For x=0 To FIELD_X-1 For y=0 To FIELD_Y-1 grid[x][y].value=Rnd(1,6) ' I get a null access error here Next Next Class Dice Field posX:Float Field posY:Float Field value:Int Method New() posX=0 posY=0 value=0 End End Function AllocateArray:Dice[][]( i:Int, j:Int) Local arr:Dice[][] = New Dice[i][] For Local ind = 0 Until i arr[ind] = New Dice[j] Next Return arr End Any ideas? |
| ||
@jd Don't you have to 'new' the Class? |
| ||
Amon is right, loop through the whole array and 'New" the references (each element) |
| ||
Isn't that what the AllocateArray function is doing ? |
| ||
I'll try looping through the array after the AllocateArray function is called and trying the "new" suggestion |
| ||
The AllocateArray function above allocates the array. It doesn't initialise the contents. For objects, the array just holds object references so you have to create your objects and insert the reference for there to be a valid reference in a given array position. By the way, with generics I now prefer this: [monkeycode] Class ArrayUtil<T> Function CreateArray:T[][](rows:Int,cols:Int) Local a:T[][] = New T[rows][] For Local i:Int = 0 Until rows a[i] = New T[cols] End Return a End End [/monkeycode] Which can be used to create any array type, e.g: [monkeycode] Local diceArr:Dice[][] = ArrayUtil<Dice>.CreateArray(25, 50) [/monkeycode] |
| ||
I like that! Gonna save that code; thanks muddy! |
| ||
For the Diddy users out there, Diddy also has a CreateArray method in it's Array Class: http://code.google.com/p/diddy/source/browse/trunk/src/diddy/arrays.monkey |
| ||
I think this should help you out, jd! I used your code and made a working example.Strict Import mojo Function Main:Int() New ArrayCTest Return 0 End Function Class ArrayCTest Extends App Global FIELD_X:int = 5 Global FIELD_Y:int = 7 Global grid:Dice[][] Method OnCreate:Int() SetUpdateRate(60) grid = AllocateArray(FIELD_X, FIELD_Y) For Local x:int = 0 To FIELD_X - 1 For Local y:Int = 0 To FIELD_Y - 1 grid[x][y] = New Dice Next Next For Local x:Int = 0 To FIELD_X - 1 For Local y:Int = 0 To FIELD_Y - 1 grid[x][y].value = Rnd(1, 6) Next Next Return 0 End Method Method OnUpdate:Int() Return 0 End Method Method OnRender:Int() Cls For Local x:Int = 0 To FIELD_X - 1 For Local y:Int = 0 To FIELD_Y - 1 If grid[x][y].value > 0 And grid[x][y].value < 7 DrawText(grid[x][y].value, x * 20, y * 20) EndIf Next Next Return 0 End Method End Class Class Dice Field posX:Float Field posY:Float Field value:Int Method New() posX=0 posY=0 value=0 End End Function AllocateArray:Dice[][]( i:Int, j:Int) Local arr:Dice[][] = New Dice[i][] For Local ind:Int = 0 Until i arr[ind] = New Dice[j] Next Return arr End |