Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Array elements crashing program [SOLVED]
#1
I'm trying to write a simple path finding algorithm, and I've run into a problem with cbot arrays that I can't seem to work around:

I'm trying to create a 2d array representing the map at a 1m scale, so the array is nominally 808 by 808 elements.

If I try to initialize all the elements to some default value, Colobot GE slows to a crawl and I eventually have to kill the process.

Since Colobot appears to support sparse arrays, it seemed like a good idea to initialize only those array elements that the simple pathfinder actually needed to access (typically just a few hundred). The problem with THAT is that I can't find any way at all to test if an array element has been initialized.

Consider the following simple example program:

Code:
extern void object::artest()
{
    errmode(0); //This suppresses the "Variable not Initialized" error message, but doesn't stop the script from halting
    
    message( "Hello World" );
    int foo[]; // sizeof(foo) == 0
    
    foo[10] = 42; // sizeof(foo) == 11
    
    if( foo[0] == 0 ) {
        message( "This never happens" );
    }
    else {
        message( "This also never happens" );
    }
    
    message( "You won't see this message" );
}

So "sizeof(foo)" is no help.

"if( foo[0] == null )" fails to compile

EDIT:

While messing about with something unrelated, I stumbled upon a  solution using CBot's largely undocumented try-catch syntax. The following program seems to run as expected:

Code:
extern void object::artest()
{
  errmode(0); //This suppresses the "Variable not Initialized" error message, but doesn't stop the script from halting

  message( "Hello World" );
  int foo[]; // sizeof(foo) == 0

  foo[10] = 42; // sizeof(foo) == 11

  for( int i = 0; i < sizeof(foo); i++ ) {
    int v = SafeRead( foo, i );
    message( "foo[" + i + "] = " + v );
  }

  message( "Program finished" );
}

int object::SafeRead( int[] ar, int n ) {
    int defaultvalue = -99;
    int rv;
    
    try {
        rv = ar[n];
    }
    catch( CBotErrNotInit ) {
        message( "SafeRead() Caught Not-Initialized Error, returning default", DisplayError );
        return defaultvalue;
    }
    catch( CBotErrOutArray ) {
        message( "SafeRead() Caught Out-of-Bounds Error, returning default", DisplayError );
        return defaultvalue;
    }
    
    return rv;
}


My SafeRead() function isn't as generic as I'd like, but it should be trivial to adapt for use in most situations where something like this is needed.
#2
Code:
extern void object::Lib(){
    float time = abstime();
    travel();
    time = abstime() - time;
    message(time);
}

public void object::travel(){
    int X = 161;
    int Y = 161;
    
    float map [X][Y];
    
    for ( int x = 0; x < X; x++){
        for ( int y = 0; y < Y; y++){
            map[x][y] = topo(new point (x,y));
            //message("Punkt "+x+","+y+" ma wysokosc "+map[x][y]);
        }
    }
}

This is code I quickly made to simulate creation of 2D array representation of game map. It took exactly 76.1195s.
Good luck with your path-finding algorithm. Tongue
#3
Yes, a representation at 1-pixel (5m) resolution the map is easier to deal with (n.b. your code would run much faster if you add ipf(5000) to the top of your travel() function).

If the only thing the pathfinder had to deal with was sloped terrain then this would probably work perfectly, but in real levels it needs to be able to navigate around buildings, decorative objects, other bots, etc., and these aren't generally aligned to the 5x5 grid. Honestly, after experimenting with it a bit on the "Radar and Traps" challenge levels I've concluded that my 1m resolution grid is still not good enough.

I'm still interested in a way to safely detect uninitialized values, but I will probably end up writing a more free-form heap based pathfinder instead of the grid-based A* I've been working on.
#4
You can go lazy way and use code like in exercise about avoiding mines, to avoid objects dynamically. Not perfect, but thats probably why modern games use navmeshes, and Colobot don't have navmeshes.
#5
I want my program to be able to solve the MazesOnMars levels and reliably reach objects surrounded by ruins (e.g. Titanium and PowerCells in the Tropica "On the Offensive" mission). I'm afraid that any algorithm that can't tell the difference between a path and a dead end just isn't going to cut it.

Also, I'm not sure that navmeshes would be all that useful in Colobot: Buildings are more-or-less permanent obstacles once built, but a pre-computed navmesh can't reliably predict where the player will decide to build them. This means that if Colobot was going to use navmeshes, it would need a dynamic navmesh generator. Not impossible, but it looks like it would be quite a lot of work for relatively little benefit. I imagine that any CPU cycles you saved by using the navmesh would likely be spent 10 times over when creating or updating it.

At the moment I'm reading up on Theta*, I think if I use that with a 5m grid and some obstacle avoidance, then I may have the basis of a good goto() replacement. I just need to add a few tweaks to properly allow for the use of waypoints that aren't in the center of a grid square.

All of this is of course getting totally off the original topic, but I'm going to assume for the moment that there simply is no way to test whether a variable has been initialized in Cbot. I may add a feature request at some point.


Forum Jump:


Users browsing this thread: 6 Guest(s)