Personal tools
You are here: Home Computer and Information Technology Artificial Intelligence Scavenger-Create-World.pl

Scavenger-Create-World.pl

Document Actions
  • Send this
  • Print this
  • Bookmarks

Click here to get the file

Size 10.7 kB - File type text/x-perl

File contents

#!/usr/bin/perl

use strict;

# configure below here

my $world_width    = 30;       # number of cells wide to make the world
my $world_height   = 30;       # number of cells high to make the world
my $world_left     = -15000;   # x-coordinate of the left column of the world
my $world_bottom   = -15000;   # y-coordinate of the bottom row of the world
my $num_continents = 30;       # number of techtonic plates to create
my $min_size       = 3;        # minimum radius of a techtonic plate
my $max_size       = 10;       # maximum radius of a techtonic plate
my $percent_plain  = .70;      # percent of plates that are plain like
my $percent_mud    = .20;      # percent of plates that are muddy  (The rest are rocky)
my $cliff_height   = 500;      # Neighbor cells with this altitude difference have a cliff/wall interface
my $max_objects    = 5;        # maximum number of objects in a cell
my $object_chance_power = 10;  # higher numbers make objects more rare
my $object_file    = "objects_2007";  # name of the object file
my $seed           = time();   # random number seed
# configure above here

my @objects = &ReadObjects($object_file);

my @world = &MakeWorld($world_height, $world_width);
my $first_id = 1;
srand($seed);

foreach my $count (1..$num_continents)
{
  my $radius    = int (rand() * ($max_size - $min_size + 1)) + $min_size;
  my $elevation = (rand() * 2000) - 1000;
  my $variation = rand() * $cliff_height*9/10;
  my $left      = int(rand() * ($world_width - 2*$radius));
  my $bottom    = int(rand() * ($world_height - 2*$radius));
  my $iface     = rand();
  if($iface < $percent_plain)
    {
      $iface = 'plain';
    }
  elsif($iface < ($percent_plain + $percent_mud))
    {
      $iface = 'mud';
    }
  else
    {
      $iface = 'rocks';
    }
  my @c1 = &Continent($radius, $elevation, $variation, $iface, $first_id);
  $first_id += ( 2*$radius + 1)*( 2*$radius + 1);

  &AddContinent(\@world, \@c1, $left, $bottom, $world_left, $world_bottom);
}

&LinkCells(\@world);
&FindCliffs(\@world, $cliff_height);
&CheckWorld(\@world);
&PlaceObjects(\@world, \@objects, $max_objects, $object_chance_power);

&DisplayCells(\@world);

sub ReadObjects
{
    my ($filename) = @_;
    my $fh;
    my @objects;
    my $line;
    
    open($fh, "< $filename") or die "open: $filename: $!";
    $line = <$fh>; # throw away the header line
    while($line = <$fh>)
    {
	chomp($line);
	push(@objects, $line);
    }
    close($fh);
    return @objects;
}


sub PlaceObjects
{
  my ($cells, $objects, $max_objects, $chance_power) = @_;
  my $w       = @{$cells};
  my $h       = @{${$cells}[0]};
  my $x;
  my $y;
  my $obj_id = 1;

  for($x = 0; $x < $w; $x++)
    {
      for($y = 0; $y < $h; $y++)
        {
	    if($cells->[$x]->[$y])
	    {
		my $c1 = $cells->[$x]->[$y];
		my $cell_id = $c1->{id};
		my $chance = rand();
		$chance = $chance ** $chance_power;
		my $num_objects = $chance * $max_objects;
		foreach my $n (1..$num_objects)
		{
		    my $i = int(rand() * @{$objects});
		    my $obj = $objects->[$i];
		    $obj =~ s/OBJ[0-9]+\s+[0-9]+/OBJ${obj_id} ${cell_id}/;
		    $obj =~ s/\s+/ /g;
		    $obj_id ++;
		    push(@{$c1->{objs}}, $obj);
		}
            }
        }
    }
  
}

sub CheckWorld
{
  my ($cells) = @_;
  my $w       = @{$cells};
  my $h       = @{${$cells}[0]};
  my $x;
  my $y;

  for($x = 0; $x < $w; $x++)
    {
      for($y = 0; $y < $h; $y++)
        {
          my @d1 = qw/N S E W/;
          my @d2 = qw/S N W E/;
          my @xn = ($x, $x, $x+1, $x-1);
          my @yn = ($y+1, $y-1, $y, $y);
          my $i;
          for($i = 0; $i < @xn; $i++)
            {
              if($xn[$i] >= 0 && $xn[$i] < $w &&
                 $yn[$i] >= 0 && $yn[$i] < $h &&
                 $cells->[$x]->[$y] &&
                 $cells->[$xn[$i]]->[$yn[$i]])
                {
                  my $c1 = $cells->[$x]->[$y];
                  my $c2 = $cells->[$xn[$i]]->[$yn[$i]];
		  if($c1->{$d1[$i].'i'} != $c2->{$d2[$i].'i'})
		  {
		      printf STDERR ("ERROR %s %s\n",
				     $c1->{$d1[$i].'i'},
				     $c2->{$d2[$i].'i'}
				     );
		  }
                }
            }
        }
    }
  
}


sub DisplayCells
{
  my ($world) = @_;

  my $crow;
  my $cell;

  print '
#          title damage energy traversable is_fall
Interface: plain      0      0           1       0
Interface: rocks      1      0           1       0
Interface: mud        0      1           1       0
Interface: wall      10      1           0       0
Interface: cliff      0      0           1       1
';

  my $base = 0;
  foreach $crow (@{$world})
    {
      foreach $cell (@{$crow})
        {
          if($cell)
            {
              if(($base == 0) ||
                 (rand() < .01))
                {
                  $base = $cell->{id};
                }
              printf("Cell: %4d %9.2f %9.2f %9.2f %4d %4d %4d %4d %6s %6s %6s %6s\n",
                     $cell->{id},
                     $cell->{x},
                     $cell->{y},
                     $cell->{z},
                     $cell->{N},
                     $cell->{S},
                     $cell->{E},
                     $cell->{W},
                     $cell->{Ni},
                     $cell->{Si},
                     $cell->{Ei},
                     $cell->{Wi},
                     );
	      foreach my $obj (@{$cell->{objs}})
	      {
		  print $obj, "\n";
	      }
            }
        }
    }

  print "Base: $base\n";

}


sub AddContinent
{
  my ($world, $continent, $x_orig, $y_orig, $world_left, $world_bottom) = @_;
  
  my $w       = @{$continent};
  my $h       = @{${$continent}[0]};
  my $x;
  my $y;

  for($x = 0; $x < $w; $x++)
    {
      for($y = 0; $y < $h; $y++)
        {
          my $wx = $x_orig + $x;
          my $wy = $y_orig + $y;
          if($continent->[$x]->[$y] != 0)
            {
              if($world->[$wx]->[$wy] != 0)
                { # merge cells
                  $world->[$wx]->[$wy]->{z} += $continent->[$x]->[$y]->{z};
                  $world->[$wx]->[$wy]->{z} /= 1.5;

                  my @d1 = qw/N S E W/;
                  foreach my $d (@d1)
                    {
                      if(rand() < .5)
                        {
                          my $key = $d.'i';
                          $world->[$wx]->[$wy]->{$key} = $continent->[$x]->[$y]->{$key};
                        }
                    }
                  if($world->[$wx]->[$wy]->{z} > 1000)
                    {
                      $world->[$wx]->[$wy]->{z} = 1000;
                    }
                }
              else
                { # set new cell
                  $world->[$wx]->[$wy] = $continent->[$x]->[$y];
                }
              if($world->[$wx]->[$wy] != 0)
                {
                  $world->[$wx]->[$wy]->{x} = $wx * 1000 + $world_left;
                  $world->[$wx]->[$wy]->{y} = $wy * 1000 + $world_bottom;
                }
            }
        }
    }
}

sub MakeWorld
{
  my ($w, $h) = @_;
  my @cells;

  my ($x, $y);
  
  for($x = 0; $x <= $w; $x ++)
    {
      $cells[$x] = [];
      
      for($y = 0; $y <= $h; $y ++)
        {
          $cells[$x]->[$y] = 0;
        }
    }

  return @cells;
}


sub FindCliffs
{
  my ($cells, $cliff_height) = @_;
  my $w       = @{$cells};
  my $h       = @{${$cells}[0]};
  my $x;
  my $y;

  for($x = 0; $x < $w; $x++)
    {
      for($y = 0; $y < $h; $y++)
        {
          my @d1 = qw/N S E W/;
          my @d2 = qw/S N W E/;
          my @xn = ($x, $x, $x+1, $x-1);
          my @yn = ($y+1, $y-1, $y, $y);
          my $i;
          for($i = 0; $i < @xn; $i++)
            {
              if($xn[$i] >= 0 && $xn[$i] < $w &&
                 $yn[$i] >= 0 && $yn[$i] < $h &&
                 $cells->[$x]->[$y] &&
                 $cells->[$xn[$i]]->[$yn[$i]])
                {
                  my $c1 = $cells->[$x]->[$y];
                  my $c2 = $cells->[$xn[$i]]->[$yn[$i]];
                  if(abs($c1->{z} - $c2->{z}) > $cliff_height)
                    {
                      if($c1->{z} > $c2->{z})
                        {
                          $c1->{$d1[$i].'i'} = 'cliff';
                          $c2->{$d2[$i].'i'} = 'wall';
                        }
                      else
                        {
                          $c1->{$d1[$i].'i'} = 'wall';
                          $c2->{$d2[$i].'i'} = 'cliff';
                        }
                    }
                }
              if(($xn[$i] < 0 || $xn[$i] >= $w ||
                  $yn[$i] < 0 || $yn[$i] >= $h ||
                  $cells->[$xn[$i]]->[$yn[$i]] == 0) &&
                 $cells->[$x]->[$y])
                { # exterior wall
                  my $c1 = $cells->[$x]->[$y];
                  $c1->{$d1[$i].'i'} = 'wall';
                }
            }
        }
    }
  
}
sub LinkCells
{
  my ($cells) = @_;
  my $w       = @{$cells};
  my $h       = @{${$cells}[0]};
  my $x;
  my $y;

  for($x = 0; $x < $w; $x++)
    {
      for($y = 0; $y < $h; $y++)
        {
          my @d1 = qw/N S E W/;
          my @d2 = qw/S N W E/;
          my @xn = ($x, $x, $x+1, $x-1);
          my @yn = ($y+1, $y-1, $y, $y);
          my $i;
          for($i = 0; $i < @xn; $i++)
            {
              if($xn[$i] >= 0 && $xn[$i] < $w &&
                 $yn[$i] >= 0 && $yn[$i] < $h &&
                 $cells->[$x]->[$y] &&
                 $cells->[$xn[$i]]->[$yn[$i]])
                {
                  my $c1 = $cells->[$x]->[$y];
                  my $c2 = $cells->[$xn[$i]]->[$yn[$i]];
                  $c1->{$d1[$i]} = $c2->{id};
                  $c2->{$d2[$i]} = $c1->{id};
		  
                  $c2->{$d2[$i].'i'} = $c1->{$d1[$i].'i'};
                }
            }
        }
    }
  
}

sub Continent
{
  my ($radius, $base, $hills, $iface, $cell_id) = @_;

  my ($x, $y, $z);
  my ($x_count, $y_count, $z);
  my @cells;
  
  $z = $base;
  
  for($x = -$radius, $x_count = 0; $x <= $radius; $x ++, $x_count ++)
    {
      $cells[$x_count] = [];
      
      for($y = -$radius, $y_count = 0; $y <= $radius; $y ++, $y_count ++)
        {
          my $r = sqrt($x*$x + $y*$y);
          my $d = $r/$radius;
          if(($d <= 1.) || (rand() > (2.0 - $d)))
            { # make a cell
              my $c = { "id" => $cell_id,
                        "x" => $x*1000,
                        "y" => $y*1000,
                        "z" => $z + rand() * $hills,
                        "N" => 0,
                        "S" => 0,
                        "E" => 0,
                        "W" => 0,
                        "Ni" => $iface,
                        "Si" => $iface,
                        "Ei" => $iface,
                        "Wi" => $iface,
			"objs" => [],
                      };
              $cells[$x_count]->[$y_count] = $c;
              $cell_id ++;
            }
          else
            {
              $cells[$x_count]->[$y_count] = 0;
            }
          
        }
    }
  return @cells;
}
Copyright 2008, by the Contributing Authors. Cite/attribute Resource. jones. (2007, November 29). Scavenger-Create-World.pl. Retrieved May 20, 2012, from Dixie State College of Utah Web site: http://dixie.educommons.net/computer-and-information-technology/artificial-intelligence/Scavenger-Create-World.pl. This work is licensed under a Creative Commons License. Creative Commons License