/* universe.cc 1.8 95/12/23 03:11:20 */


// xspacewarp by Greg Walker (gow@math.orst.edu)

// This is free software. Non-profit redistribution and/or modification
// is allowed and welcome.


// the routines for creating a random universe and destroying it.


#include <iostream.h>
#include <stdlib.h>		// rand(), exit()
#include "common.hh"
#include "params.hh"
#include "globals.hh"
#include "c_block.hh"
#include "c_sector.hh"

#include "c_endever.hh"
#include "c_base.hh"
#include "c_jovian.hh"
#include "c_star.hh"
#include "c_blackhole.hh"

static Base *bases;
static Blackhole *blackholes;
static Jovian *jovians;
static Star *stars;


// return a (uniform) random number in the range   mean +/- var.

inline int random(int mean, int var)
{
  return (mean + (2 * (rand()%2) - 1) * (rand() % (var+1)));
}


// this is called in echoarea.cc in endinput()

void make_universe(int skill)
{
  int urow, ucol, i, j;
  int nbases, nblackholes, njovians, nstars;
  int mean, var;

  // determine the number of bases in the universe

  mean = evallinear(skill, MINSKILL, app_data.min_average_base_pop,
		    MAXSKILL, app_data.max_average_base_pop);
  var = evallinear(skill, MINSKILL, app_data.min_variation_base_pop,
		   MAXSKILL, app_data.max_variation_base_pop);
  nbases = random(mean, var);

  // determine the number of blackholes in the universe

  mean = evallinear(skill, MINSKILL, app_data.min_average_blackhole_pop,
		    MAXSKILL, app_data.max_average_blackhole_pop);
  var = evallinear(skill, MINSKILL, app_data.min_variation_blackhole_pop,
		   MAXSKILL, app_data.max_variation_blackhole_pop);
  nblackholes = random(mean, var);

  // determine the number of jovians in the universe

  mean = evallinear(skill, MINSKILL, app_data.min_average_jovian_pop,
		    MAXSKILL, app_data.max_average_jovian_pop);
  var = evallinear(skill, MINSKILL, app_data.min_variation_jovian_pop,
		   MAXSKILL, app_data.max_variation_jovian_pop);
  njovians = random(mean, var);

  // determine the number of stars in the universe

  mean = evallinear(skill, MINSKILL, app_data.min_average_star_pop,
		    MAXSKILL, app_data.max_average_star_pop);
  var = evallinear(skill, MINSKILL, app_data.min_variation_star_pop,
		   MAXSKILL, app_data.max_variation_star_pop);
  nstars = random(mean, var);

  bases = new Base[nbases];
  blackholes = new Blackhole[nblackholes];
  jovians = new Jovian[njovians];
  stars = new Star[nstars];

  if (!bases || !blackholes || !jovians || !stars)
  {
    cerr << "xspacewarp: make_universe: insufficient memory." << endl;
    exit(1);
  }

  Base::setpop(nbases);
  Jovian::setpop(njovians);
  Jovian::setleapable(0);
  Jovian::setraidable(0);

  // assign id numbers to jovians

  for (i = 0; i < njovians; i++)
     jovians[i].setid(i);

  // place endever randomly (class Sector handles rand placement inside sector)

  urow = 1 + rand() % UROWS;
  ucol = 1 + rand() % UCOLS;
  endever.seturow(urow);
  endever.setucol(ucol);
  universe[urow-1][ucol-1].add_endever();

  // place bases randomly

  for (i = 0; i < nbases; i++)
  {
    do
    {
      urow = 1 + rand() % UROWS;
      ucol = 1 + rand() % UCOLS;
      bases[i].seturow(urow);
      bases[i].setucol(ucol);
    }
    while (!universe[urow-1][ucol-1].add_base(bases[i]));
  }

  // place blackholes randomly

  for (i = 0; i < nblackholes; i++)
  {
    do
    {
      urow = 1 + rand() % UROWS;
      ucol = 1 + rand() % UCOLS;
      blackholes[i].seturow(urow);
      blackholes[i].setucol(ucol);
    }
    while (!universe[urow-1][ucol-1].add_blackhole(blackholes[i]));
  }

  // place jovians randomly. must place the jovians after the
  // bases and the endever. this is so the "leapable" variable
  // can be set properly.

  for (i = 0; i < njovians; i++)
  {
    do
    {
      urow = 1 + rand() % UROWS;
      ucol = 1 + rand() % UCOLS;
      jovians[i].seturow(urow);
      jovians[i].setucol(ucol);
    }
    while (!universe[urow-1][ucol-1].add_jovian(&jovians[i]));
  }


  // place stars randomly

  for (i = 0; i < nstars; i++)
  {
    do
    {
      urow = 1 + rand() % UROWS;
      ucol = 1 + rand() % UCOLS;
      stars[i].seturow(urow);
      stars[i].setucol(ucol);
    }
    while (!universe[urow-1][ucol-1].add_star(&stars[i]));
  }


  // randomly set masks

  for (i = 0; i < UROWS; i++)
  {
    for (j = 0; j < UCOLS; j++)
    {
      if (rand()%100 <= PROBMASK)
      {
	universe[i][j].setmask();
      }
    }
  }
}


// de-allocate objects created above and reset sectors and endever.

void erase_universe(void)
{
  for (int i = 0; i < UROWS; i++)
  {
    for (int j = 0; j < UCOLS; j++)
        universe[i][j].erase();	// de-allocate Jovian_recs and Star_recs
  }
  endever.erase();

  delete []bases;
  delete []blackholes;
  delete []jovians;
  delete []stars;
}

// end
