Boulder Dash Forum Forum Index Boulder Dash Forum
The only Boulder Dash discussion board in English language!
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Random filling a map in C#

 
Post new topic   Reply to topic    Boulder Dash Forum Forum Index -> Tools, Fanstuff
View previous topic :: View next topic  
Author Message
rjm
Member


Joined: 29 Mar 2009
Posts: 16
Location: United Kingdom

PostPosted: Sun Mar 29, 2009 3:09 pm    Post subject: Random filling a map in C# Reply with quote

Hello,

I've been working on a Boulder Dash based game for my kids to play when I came across some references to the BDCFF. After reading through that, I recoded my protoype to import and use caves in this format (0.32 by Tim Stridmann). This works pretty well, and so far I'm happy with the progress.

However, there's one area where it falls over flat which is the RandomFill option to randomly fill a map with various contents. My implementation of this is pretty dreadful and while it gave me pleasing results for what I wanted prior to working from the BDCFF spec, its very very wrong at producing levels imported from it. Line, Raster, etc all fine. RandomFill... horrible Smile.

Checking another post on this forum about RandomFill (BDCFF - RandSeed and RandomFill), I checked the references to a random number generator and also a random fill implementation in Pascal.

The only problem is I can't program in C or Pascal - nor can I read German Smile

Has anyone tried writing the random number generator and fill function in C# and if so can any one offer any advice?

I have downloaded the GDash source to poke about it, but this is written in C and I don't have the foggiest where to even look for the random functionality, let alone how to convert it.

Any help or advice would be greatfully received!

Thanks;
Richard Moss
Back to top
View user's profile Send private message Visit poster's website
Arno
Site Admin


Joined: 17 Mar 2007
Posts: 1695
Location: netherlands

PostPosted: Sat Apr 04, 2009 3:11 pm    Post subject: Reply with quote

Hi rjm,

All I know is that there exists a website where you can view the procedure code, as it is written in C. I've used almost the same procedure in my BDCFF-->MAPS converter, which is C++.

Just wondering: isn't it possible for you to translate this code to C#, if you know what the C code does? I'm not an advanced programmer, but I understood that most "higher level" programming languages are very similar.

Probably, you have already found the C procedure, but if it may help, I can share the C++ procedure that I used in my conversion tool.
_________________
---- Boulder Dash Fansite ----
Back to top
View user's profile Send private message Send e-mail Visit poster's website
rjm
Member


Joined: 29 Mar 2009
Posts: 16
Location: United Kingdom

PostPosted: Sat Apr 04, 2009 4:08 pm    Post subject: Reply with quote

Arno,

Thanks for the response. I haven't found the code you refer to, unless I've missed it in the various pages I've been looking in, so if you can link it then that would be a great help.

I used C quite a few years back so although I'm not even remotely competent in it, I can more or less read it. Hopefully it'll give me a clue at the very least Smile

Thanks!;
Richard moss
Back to top
View user's profile Send private message Visit poster's website
Arno
Site Admin


Joined: 17 Mar 2007
Posts: 1695
Location: netherlands

PostPosted: Sun Apr 05, 2009 4:09 pm    Post subject: Reply with quote

Hi Richard,

I include here the C++ code that I'm using in my BDCFF-->MAPS converter. It uses 2 functions, of which the second fills a cave completely with the random items, specified in the BDCFF file.

I've added a few comments to explain what certain parts of the code actually do. Hope this helps you out!

Code:

void NextRandom(int *RandSeed1, int *RandSeed2) // Random generator used on C64
{  short TempRand1;
   short TempRand2;
   short carry;
   short result;
   assert(((*RandSeed1 >= 0x00) && (*RandSeed1 <= 0xFF)));
   assert(((*RandSeed2 >= 0x00) && (*RandSeed2 <= 0xFF)));
   TempRand1 = (*RandSeed1 & 0x0001) * 0x0080;
   TempRand2 = (*RandSeed2 >> 1) & 0x007F;
   result = (*RandSeed2) + (*RandSeed2 & 0x0001) * 0x0080;
   carry = (result > 0x00FF);
   result = result & 0x00FF;
   result = result + carry + 0x13;
   carry = (result > 0x00FF);
   *RandSeed2 = result & 0x00FF;
   result = *RandSeed1 + carry + TempRand1;
   carry = (result > 0x00FF);
   result = result & 0x00FF;
   result = result + carry + TempRand2;
   *RandSeed1 = result & 0x00FF;
   assert(((*RandSeed1 >= 0x00) && (*RandSeed1 <= 0xFF)));
   assert(((*RandSeed2 >= 0x00) && (*RandSeed2 <= 0xFF)));
}

void random_fill(int cave_nr, int level_nr)
{  int item;
   int number_rand_items=0;
   
   // Count the number of random items (max 4):
   for (int k=0; k<4; k++)
   {  if (random_fill_probs[k] <= 255) number_rand_items++;
   }
   
   // Initialize the values of both random seeds:
   RandSeed1 = 0;
   RandSeed2 = rand_seed[level_nr]; // This is the seed-value from the BDCFF file!
   
   // Fill the top line with steelwalls:
   for (int j=0; j<40; j++)
      put_item(cave_nr, level_nr, item_from_name("STEELWALL"), 0, j);
   // The function put_item places a certain item at a certain place. It has 5 parameters:
   // cave number, level number, item id, vertical position (0 to 21), horizontal position (0 to 39).

   // Fill the rest of the cave (start with the 2nd line):
   for (int i=1; i<22; i++)
   {  for (int j=0; j<40; j++)
      {  item = item_from_name("DIRT"); // Default item is dirt!
         NextRandom(&RandSeed1, &RandSeed2); // Draw a random number between 0 and 255.
         // Determine which item should be placed:
         for (int k=0; k<number_rand_items; k++)
         {  if (RandSeed1 < random_fill_probs[k])
            {  item = random_fill_items[k];
            }
         }
         // Place the item, but make an exception when we are on the border,
         // (both for caves and intermissions) then a steelwall must be placed.
         if ( (!intermission[cave_nr] && i>=1 && i<=20 && j>=1 && j<=38) ||
              ( intermission[cave_nr] && i>=1 && i<=10 && j>=1 && j<=18)    )
            put_item(cave_nr, level_nr, item, i, j);
         else put_item(cave_nr, level_nr, item_from_name("STEELWALL"), i, j);
      }
   }
}

_________________
---- Boulder Dash Fansite ----
Back to top
View user's profile Send private message Send e-mail Visit poster's website
rjm
Member


Joined: 29 Mar 2009
Posts: 16
Location: United Kingdom

PostPosted: Sun Apr 05, 2009 6:42 pm    Post subject: Reply with quote

Arno,

Thanks for posting this. It's almost identical to C# syntax (the only difference so far is you say "*RandSeed1" and I say "ref RandSeed1") and so very readable.

Predictably, the problems are in the operator usage and casting in the NextRandom function which should keep me busy for a while trying to figure out Smile

Regards;
Richard Moss
Back to top
View user's profile Send private message Visit poster's website
rjm
Member


Joined: 29 Mar 2009
Posts: 16
Location: United Kingdom

PostPosted: Sun Apr 05, 2009 7:07 pm    Post subject: Reply with quote

Arno,

Well, it took less than than I thought - I'm not sure if my logic is entirely correct in regards to the > but... it works! Now the object coded bdcff maps I'm loading precisely match your screenshots Smile

Thanks very much for your help - I'm pretty pleased, as the implementation I had come up with made many BD1 caves unsolvable as areas were blocked etc Shocked

Just in case anyone else needs it, this is the C# version. Obviously your fill map routines will differ according to how you implement your own level types.

Code:
    public static void NextRandom(ref int RandSeed1, ref int RandSeed2) // Random generator used on C64
    {
      short TempRand1;
      short TempRand2;
      short carry;
      short result;
      TempRand1 = (short)((RandSeed1 & 0x0001) * 0x0080);
      TempRand2 = (short)((RandSeed2 >> 1) & 0x007F);
      result = (short)((RandSeed2) + (RandSeed2 & 0x0001) * 0x0080);
      carry = (short)((result > 0x00FF) ? 1 : 0);
      result = (short)(result & 0x00FF);
      result = (short)(result + carry + 0x13);
      carry = (short)((result > 0x00FF) ? 1 : 0);
      RandSeed2 = result & 0x00FF;
      result = (short)(RandSeed1 + carry + TempRand1);
      carry = (short)((result > 0x00FF) ? 1 : 0);
      result = (short)(result & 0x00FF);
      result = (short)(result + carry + TempRand2);
      RandSeed1 = result & 0x00FF;
    }

    public static void random_fill(Level level, int[] probability, TileType[] items)
    {
      TileType item;
      int RandSeed1;
      int RandSeed2;

      // Initialize the values of both random seeds:
      RandSeed1 = 0;
      RandSeed2 = level.RandomSeed; // This is the seed-value from the BDCFF file!

      // Fill the top line with steelwalls:
      for (int j = 0; j < 40; j++)
        level.Tiles[j, 0].Type = TileType.SteelWall;
     
      // Fill the rest of the cave
      for (int i = 1; i < level.Height; i++)
      {
        for (int j = 0; j < level.Width; j++)
        {
          item = TileType.Dirt; // Default item is dirt!
          NextRandom(ref RandSeed1, ref RandSeed2); // Draw a random number between 0 and 255.

          // Determine which item should be placed:
          for (int k = 0; k < items.Length; k++)
          {
            if (RandSeed1 < probability[k])
              item = items[k];
          }

          // Place the item, but make an exception when we are on the border, then a steelwall must be placed.
          if (i > 0 && i < level.Height - 1 && j > 0 && j < level.Width - 1)
            level.Tiles[j, i].Type = item;
          else
            level.Tiles[j, i].Type = TileType.SteelWall;
        }
      }
    }


Once again, thanks for the help!

Regards;
Richard Moss
Back to top
View user's profile Send private message Visit poster's website
Arno
Site Admin


Joined: 17 Mar 2007
Posts: 1695
Location: netherlands

PostPosted: Mon Apr 06, 2009 5:44 pm    Post subject: Reply with quote

rjm wrote:
Well, it took less than than I thought - I'm not sure if my logic is entirely correct in regards to the > but... it works! Now the object coded bdcff maps I'm loading precisely match your screenshots Smile

Congratulations! Very Happy And when you've finished your remake, please release it for us to try! Wink
_________________
---- Boulder Dash Fansite ----
Back to top
View user's profile Send private message Send e-mail Visit poster's website
rjm
Member


Joined: 29 Mar 2009
Posts: 16
Location: United Kingdom

PostPosted: Tue Apr 07, 2009 4:38 pm    Post subject: Reply with quote

Arno wrote:
Congratulations! Very Happy And when you've finished your remake, please release it for us to try! Wink


It'll be a while yet - currently all the elements are in place and working but some bits need more polish Smile Plus it's currently only in GDI, next task is to learn DirectX and have the engine run in that.

But when it's ready I'll certainly drop a line Smile
Back to top
View user's profile Send private message Visit poster's website
Antonio
Member


Joined: 06 Aug 2010
Posts: 20

PostPosted: Fri Aug 06, 2010 2:45 pm    Post subject: Reply with quote

Thanks Arno and Richard for posting that source-code, it was a big help for me.
I've 'translated' it to Java, (because my upcoming BD-remake will be in Java Smile,
and I shall post it here in case someone is interested :

Code:
  private static int globalRandSeed1;
  private static int globalRandSeed2;
 
  public static void randomFill(String[][] level, int seed, ArrayList<Integer> probabilities, ArrayList<String> items)
  {
    String item;
    int randSeed1 = 0;
    int randSeed2 = seed; // This is the seed-value from the BDCFF file.

    // Fill the top line with walls:
    for (int i = 0; i < 40; i++)
      level[0][i] = "W";
   
    // Fill the rest of the cave.
    for (int r = 1; r < level.length; r++)
    {
      for (int c = 0; c < level[0].length; c++)
      {
        item = "E"; // Default item ('earth').
        NextRandom(randSeed1, randSeed2); // Draw a random number between 0 and 255.
        randSeed1 = globalRandSeed1;       
        randSeed2 = globalRandSeed2;       
       
        // Determine which item should be placed :
        for (int k = 0 ; k < items.size() ; k++)
        {
          if (globalRandSeed1 < probabilities.get(k))
            item = items.get(k);
        }
       
        // Place the item, but make an exception when we are on the border, then a wall must be placed.
        if (r > 0 && r < level.length-1    &&   c > 0 && c < level[0].length-1)
          level[r][c] = item;
        else
          level[r][c] = "W";
      }
    }
  }
 
  private static void NextRandom(int randSeed1, int randSeed2) // Random generator used on C64
  {
    short carry;
    short result;
   
    short tempRand1 = (short)((randSeed1 & 0x0001) * 0x0080);
    short tempRand2 = (short)((randSeed2 >> 1) & 0x007F);
   
    result = (short)((randSeed2) + (randSeed2 & 0x0001) * 0x0080);
    carry = (short)((result > 0x00FF) ? 1 : 0);
    result = (short)(result & 0x00FF);
    result = (short)(result + carry + 0x13);
    carry = (short)((result > 0x00FF) ? 1 : 0);   
    globalRandSeed2 = result & 0x00FF;
    result = (short)(randSeed1 + carry + tempRand1);
    carry = (short)((result > 0x00FF) ? 1 : 0);
    result = (short)(result & 0x00FF);
    result = (short)(result + carry + tempRand2);
    globalRandSeed1 = result & 0x00FF;
  }
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Boulder Dash Forum Forum Index -> Tools, Fanstuff All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group