Helped needed for writing to files.

BlueSnoodDude

New member
Joined
Dec 6, 2020
Messages
5
So I'm working on a project to make random level designs for games in Monkey X.
The method I'm using is creating an external .txt document which contains values and looks something like the following:

22222222222222222222
27777777777777777772
27777777777777777772
27777777777777777772
27777777727777777772
27777777777777777772
27777771777777777772
27777777777777777772
27777777777277777772
27777777777777777772
27727777777777777772
27777777777777777772
27777777777277777772
27777777777777777772
22222222222222222222

This will then read into Monkey X and it will translate each of these numbers to an allotted sprite.
This all works just fine.

However, I wish for it to randomly generate these files and I have an algorithm designed to make randomly generated files of this structure.
The issue is its not writing correctly, I don't quite know the issue but I assume that its down to it not putting the values in the correct format (as shown above) to be read.


Is anyone able to see the issue:
1607266987484.png


1607267022531.png
That is the syntax error I'm having, it says "array index out of range" so I'm assuming that the new randomly generated file isn't formatted correctly.



I'm stumped. I'd be grateful if anyone knows of any solutions. :)
 

BlueSnoodDude

New member
Joined
Dec 6, 2020
Messages
5
I should probably add, I created Method Write() after Method Load() so I know that method load is working correctly due to it loading a demo .txt file I created.
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
813
Arrays are zero based. There for your for loops are actually counting 15 and 20 items, you are trying to access the array with data_item[y][x..x+1] when data_item[y][x] is all you would need.
 

BlueSnoodDude

New member
Joined
Dec 6, 2020
Messages
5
Arrays are zero based. There for your for loops are actually counting 15 and 20 items, you are trying to access the array with data_item[y][x..x+1] when data_item[y][x] is all you would need.
This didn't appear to solve the issue. I now have "Character index out of range" after changing [x..x+1] to just [x]
 

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
2,988
1608140099609.png


Shouldn't that be

code_language.cerberus:
level_file.WriteString("~n")

according to how you split the file into lines again?

1608140224818.png
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
813
I've just knocked up a test program using the code from the image supplied. Line endings are not the issue. It would help to know how the predefined level file that works is being used is constructed.

Is it a pure human readable text, or encode integer with newline termination. If it's the latter, then the data needs to be read in exactly as was written. Plus I take it that the tiles array is predefined and filled out ready for use?
 
Last edited:

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
813
I you are trying to produce the layout exactly like the one you have in your first post, then this is how you should do it.

code_language.cerberus:
Method Write:Void()
        Local item:Int
        Local level_file:FileStream
   
        level_file = FileStream.Open("cerberus://data/one.txt", "w")

         For Local j:=0 Until 14
             For Local i:=0 Until 19
                 item = Rnd(8)
                 level_file.WriteString(String.FromChar(item))
             Next
             level_file.WriteString("~n")
         Next
         level_file.Close()
    End

Edit: Don't forget you will not need [x..x+1] and make sure the the data you write out matches the array you will be loading into.
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
695
What if you change the two "Until"'s at the top into "To"?
"Until" stops 1 step before "to" stops. So you write less data than you are reading I think?
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
813
Here's an actual working example.
code_language.cerberus:
Strict

Import mojo
Import brl.filestream

Function Main:Int()
    New MojoApp
    Return 0
End

Class MojoApp Extends App

    Field tiles:Int[][]

    Method OnCreate:Int()
        SetUpdateRate 0
 
        ' Initialise the tiles array ready to take the file data
        ' Normal arrays would be coded as tiles[row][column] as it make life easier to deal with arrays, which are basically arrays within arrays.
        ' But as the data is going to To tiles[column][row], then the array needs to reflect this.
        tiles=tiles.Resize(20)                    ' Resize the total number of columns that should be used
        For Local i:=0 Until tiles.Length()
            tiles[i] = tiles[i].Resize(16)        ' For each column, resize how many rows there are.
        Next
 
        ' Printing the length of the tiles variable will only show the total number of rows.
        ' To get the number of rows, you have to specify the column index.
        Print "Array dimentions: "+ tiles.Length()+"x"+tiles[0].Length()
 
        Write()
        Load()
 
        Return 0
    End

    Method OnUpdate:Int()
        If KeyHit(KEY_ESCAPE) Then EndApp
        Return 0
    End

    Method OnRender:Int()
        Cls
 
        ' Display the level
        For Local y:Int = 0 Until 15
            For Local x:Int = 0 Until 20
                 DrawText(tiles[x][y], x*13, y*12)
            Next
        Next
 
        Return 0
    End

    Method Write:Void()
        Local item:Int
        Local level_file:FileStream
        Local level_data:String
 
        level_file = FileStream.Open("cerberus://data/one.txt", "w")

         ' Write out the data exactly as you are going to read it back.
         For Local row:=0 To 14
             For Local col:=0 To 19
                 item = Rnd(8)    ' NOTE: The compiler should be smart enough to work out that the number needed has to cast to a integer
                 level_file.WriteString(String.FromChar(item))    ' Convert the integer number into a character
             Next
     
             level_file.WriteString("~n") ' termination of columns
         Next
 
         level_file.Close()
    End

    Method Load:Void()
        Local level_file:FileStream
        Local level_data:String
        Local data_item:String[]
 
        level_file = FileStream.Open("cerberus://data/one.txt", "r")
        level_data = level_file.ReadString()
        level_file.Close
 
        data_item = level_data.Split("~n")
 
        For Local y:Int = 0 To 14
            For Local x:Int = 0 To 19
                 tiles[x][y]=Int(data_item[y][x])
            Next
        Next
    End

End
Take note that if you open the file one.txt in any editor, Then the text will not make any sense because the character codes will be in the range of 0 to 8. If you want them in human readable form, then you have to add 48 to the value as you write to the file and subtract 48 as you read them back in, or use:
Int(String.FromChar(data_item[y][x]))
to read the data back to a integer.
 
Last edited:

BlueSnoodDude

New member
Joined
Dec 6, 2020
Messages
5
Yeah (sorry for absence over Xmas break), the current file its reading has been hardcoded by me, however the general idea was that the program would write this file, then later it could be read back. I already have the code working for reading the hardcoded files (it reads them and then based on the number it reads it draws a sprite in that place.


Its basically an over glorified maze game - where instead of a maze it divides the screen into a grid and then places sprites down where numbers appear in the grid.
 
Top Bottom