#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#include <assert.h>

#include "plan.h"

struct step_s {
  int prestation;
  int predin;
  int moc;
  int ind;
  int poststation;
  int postdin;
};

void
print_walk (int size, const struct step_s *walk)
{
  int i;
  int lastline;

  lastline = -1;
  for ( i=0 ; i<size ; i++ )
    {
      if ( walk[i].moc < NBMISSIONS
	   && missions[walk[i].moc].line != lastline )
	{
	  if ( lastline >= 0 )
	    printf ("\n");
	  printf ("%s: %s, %s",
		  lines[missions[walk[i].moc].line],
		  stations[walk[i].prestation].name,
		  stations[walk[i].poststation].name);
	  lastline = missions[walk[i].moc].line;
	}
      else if ( walk[i].moc < NBMISSIONS )
	{
	  printf (", %s", stations[walk[i].poststation].name);
	}
    }
  printf ("\n");
}

#define SAMEMISSION 2
#define OTHERMISSION 11

int
score_walk (int size, const struct step_s *walk)
{
  int score;
  int i;

  assert (size>0);
  score = 0;
  for ( i=0 ; i<size ; i++ )
    {
      if ( i>0 )
	{
	  assert (walk[i].prestation == walk[i-1].poststation);
	  if ( walk[i].moc < NBMISSIONS )
	    {
	      if ( walk[i].predin == walk[i-1].postdin )
		score += SAMEMISSION;
	      else
		score += OTHERMISSION;
	    }
	}
      else
	{
	  if ( walk[i].moc < NBMISSIONS )
	    score += OTHERMISSION;
	}
      assert (walk[i].predin < directions[walk[i].prestation].dirsize);
      assert (walk[i].moc == directions[walk[i].prestation].dir[walk[i].predin].moc);
      assert (walk[i].ind == directions[walk[i].prestation].dir[walk[i].predin].ind);
      assert (walk[i].moc == directions[walk[i].poststation].dir[walk[i].postdin].moc);
      if ( walk[i].moc < NBMISSIONS )
	{
	  assert (walk[i].ind < missions[walk[i].moc].misssize);
	  assert (walk[i].prestation == missions[walk[i].moc].miss[walk[i].ind].sta);
	  assert (walk[i].predin == missions[walk[i].moc].miss[walk[i].ind].din);
	  assert (walk[i].poststation == missions[walk[i].moc].miss[walk[i].ind+1].sta);
	  assert (walk[i].postdin == missions[walk[i].moc].miss[walk[i].ind+1].din);
	  assert (walk[i].ind+1 == directions[walk[i].poststation].dir[walk[i].postdin].ind);
	}
      else
	{
	  assert (walk[i].ind < connections[walk[i].moc-NBMISSIONS].connsize);
	  assert (walk[i].prestation == connections[walk[i].moc-NBMISSIONS].conn[walk[i].ind].sta);
	  assert (walk[i].predin == connections[walk[i].moc-NBMISSIONS].conn[walk[i].ind].din);
	}
    }
  return score;
}

#define STATIONBONUS 100
#define LINEBONUS 0

int
bonus_walk (int size, const struct step_s *walk)
{
  char statseen[NBSTATIONS];
  char lineseen[NBLINES];
  int i;
  int bonus;

  for ( i=0 ; i<NBSTATIONS ; i++ )
    statseen[i] = 0;
  for ( i=0 ; i<NBLINES ; i++ )
    lineseen[i] = 0;
  bonus = 0;
  for ( i=0 ; i<size ; i++ )
    {
      if ( ! statseen[walk[i].prestation]
	   && (stations[walk[i].prestation].opts&5) == 0 )
	bonus += STATIONBONUS;
      statseen[walk[i].prestation] = 1;
      if ( ! statseen[walk[i].poststation]
	   && (stations[walk[i].poststation].opts&5) == 0 )
	bonus += STATIONBONUS;
      statseen[walk[i].poststation] = 1;
    }
  for ( i=0 ; i<size ; i++ )
    {
      if ( walk[i].moc < NBMISSIONS )
	{
	  if ( ! lineseen[missions[walk[i].moc].line]
	       && lines[missions[walk[i].moc].line][0]=='L' )
	    bonus += LINEBONUS;
	  lineseen[missions[walk[i].moc].line] = 1;
	}
    }
  return bonus;
}

struct blurb_s {
  int seen; /* Whether a solution has been found to the constraint. */
  int din;  /* Direction INdex of arrival at constraint (true value). */
  int prestation; /* Previous station (part of previous constraint). */
  int predin; /* Previous DIN (part of previous constraint), -1 if no DIN constraint. */
  int truepredin; /* True value of previous DIN (never -1). */
  int score; /* Best score satisfying this constraint. */
  int moc;  /* Mission or connection arriving at constraint. */
  int ind;  /* Index in mission of connection (of _previous_ station). */
};

/* Solutions to constraints: with, and without direction constraint. */
struct blurb_s fastmap[NBSTATIONS][MAXDIRSIZE];
struct blurb_s shortfastmap[NBSTATIONS];

void
fill_fastmap (int istation)
{
  int iteration;
  int i, j;
  char change;

  for ( i=0 ; i<NBSTATIONS ; i++ )
    {
      shortfastmap[i].seen = 0;
      for ( j=0 ; j<MAXDIRSIZE ; j++ )
	fastmap[i][j].seen = 0;
    }
  shortfastmap[istation].seen = 1;
  shortfastmap[istation].din = 0;
  shortfastmap[istation].prestation = -1;
  shortfastmap[istation].predin = -1;
  shortfastmap[istation].truepredin = -1;
  shortfastmap[istation].score = 0;
  shortfastmap[istation].moc = -1;
  shortfastmap[istation].ind = -1;
  iteration = 0;
  do
    {
      change = 0;
      for ( i=0 ; i<NBSTATIONS ; i++ )
	if ( shortfastmap[i].seen )
	  {
	    for ( j=0 ; j<directions[i].dirsize ; j++ )
	      {
		int m;
		int stat;
		int din;
		int temptscore;

		m = directions[i].dir[j].moc;
		if ( m < NBMISSIONS )
		  {
		    if ( directions[i].dir[j].ind
			 == missions[m].misssize-1 )
		      continue;
		    if ( fastmap[i][j].seen )
		      {
			stat = missions[m].miss[directions[i].dir[j].ind+1].sta;
			din = missions[m].miss[directions[i].dir[j].ind+1].din;
			temptscore = fastmap[i][j].score+SAMEMISSION;
			if ( ! fastmap[stat][din].seen
			     || fastmap[stat][din].score > temptscore )
			  {
			    change = 1;
			    fastmap[stat][din].seen = 1;
			    fastmap[stat][din].din = din;
			    fastmap[stat][din].prestation = i;
			    fastmap[stat][din].predin = j;
			    fastmap[stat][din].truepredin = j;
			    fastmap[stat][din].score = temptscore;
			    fastmap[stat][din].moc = m;
			    fastmap[stat][din].ind = directions[i].dir[j].ind;
			  }
			if ( ! shortfastmap[stat].seen
			     || shortfastmap[stat].score > temptscore )
			  {
			    change = 1;
			    shortfastmap[stat].seen = 1;
			    shortfastmap[stat].din = din;
			    shortfastmap[stat].prestation = i;
			    shortfastmap[stat].predin = j;
			    shortfastmap[stat].truepredin = j;
			    shortfastmap[stat].score = temptscore;
			    shortfastmap[stat].moc = m;
			    shortfastmap[stat].ind = directions[i].dir[j].ind;
			  }
		      }
		    stat = missions[m].miss[directions[i].dir[j].ind+1].sta;
		    din = missions[m].miss[directions[i].dir[j].ind+1].din;
		    temptscore = shortfastmap[i].score+OTHERMISSION;
		    if ( ! fastmap[stat][din].seen
			 || fastmap[stat][din].score > temptscore )
		      {
			change = 1;
			fastmap[stat][din].seen = 1;
			fastmap[stat][din].din = din;
			fastmap[stat][din].prestation = i;
			fastmap[stat][din].predin = -1;
			fastmap[stat][din].truepredin = j;
			fastmap[stat][din].score = temptscore;
			fastmap[stat][din].moc = m;
			fastmap[stat][din].ind = directions[i].dir[j].ind;
		      }
		    if ( ! shortfastmap[stat].seen
			 || shortfastmap[stat].score > temptscore )
		      {
			change = 1;
			shortfastmap[stat].seen = 1;
			shortfastmap[stat].din = din;
			shortfastmap[stat].prestation = i;
			shortfastmap[stat].predin = -1;
			shortfastmap[stat].truepredin = j;
			shortfastmap[stat].score = temptscore;
			shortfastmap[stat].moc = m;
			shortfastmap[stat].ind = directions[i].dir[j].ind;
		      }
		  }
		else
		  {
		    int k;

		    for ( k=0 ; k<connections[m-NBMISSIONS].connsize ; k++ )
		      {
			stat = connections[m-NBMISSIONS].conn[k].sta;
			din = connections[m-NBMISSIONS].conn[k].din;
			temptscore = shortfastmap[i].score;
			if ( ! shortfastmap[stat].seen
			     || shortfastmap[stat].score > temptscore )
			  {
			    change = 1;
			    shortfastmap[stat].seen = 1;
			    shortfastmap[stat].din = din;
			    shortfastmap[stat].prestation = i;
			    shortfastmap[stat].predin = -1;
			    shortfastmap[stat].truepredin = j;
			    shortfastmap[stat].score = temptscore;
			    shortfastmap[stat].moc = m;
			    shortfastmap[stat].ind = directions[i].dir[j].ind;
			  }
		      }
		  }
	      }
	  }
      iteration++;
    }
  while ( change );
}

void
show_fastmap (void)
{
  int i;
  int maxscore;
  int barscore;
  int minscore;

  maxscore = -1;
  for ( i=0 ; i<NBSTATIONS ; i++ )
    {
      if ( shortfastmap[i].seen && shortfastmap[i].score > maxscore )
	maxscore = shortfastmap[i].score;
    }
  barscore = -1;
  while ( barscore < maxscore )
    {
      char fr;

      minscore = maxscore;
      for ( i=0 ; i<NBSTATIONS ; i++ )
	{
	  if ( shortfastmap[i].seen && shortfastmap[i].score < minscore
	       && shortfastmap[i].score > barscore )
	    minscore = shortfastmap[i].score;
	}
      printf ("%d: ", minscore);
      fr = 1;
      for ( i=0 ; i<NBSTATIONS ; i++ )
	{
	  if ( shortfastmap[i].seen && shortfastmap[i].score == minscore )
	    {
	      if ( ! fr )
		printf (", ");
	      printf ("%s", stations[i].name);
	      fr = 0;
	    }
	}
      printf ("\n");
      barscore = minscore;
    }
}

void
make_fastest_walk (int fstation, int maxsize, struct step_s *walk, int *size)
{
  int i;
  int station, din, prestation, predin;

  i = 0;
  station = fstation;
  din = -1;
  while ( 1 )
    {
      if ( din >= 0 )
	{
	  prestation = fastmap[station][din].prestation;
	  predin = fastmap[station][din].predin;
	}
      else
	{
	  prestation = shortfastmap[station].prestation;
	  predin = shortfastmap[station].predin;
	}
      if ( prestation < 0 )
	break;
      station = prestation;
      din = predin;
      i++;
    }
  *size = i;
  station = fstation;
  din = -1;
  for ( i-- ; i>=0 ; i-- )
    {
      if ( din >= 0 )
	{
	  prestation = fastmap[station][din].prestation;
	  predin = fastmap[station][din].predin;
	}
      else
	{
	  prestation = shortfastmap[station].prestation;
	  predin = shortfastmap[station].predin;
	}
      if ( i<maxsize )
	{
	  walk[i].prestation = prestation;
	  if ( din >= 0 )
	    {
	      walk[i].predin = fastmap[station][din].truepredin;
	      walk[i].moc = fastmap[station][din].moc;
	      walk[i].ind = fastmap[station][din].ind;
	      walk[i].postdin = fastmap[station][din].din;
	    }
	  else
	    {
	      walk[i].predin = shortfastmap[station].truepredin;
	      walk[i].moc = shortfastmap[station].moc;
	      walk[i].ind = shortfastmap[station].ind;
	      walk[i].postdin = shortfastmap[station].din;
	    }
	  walk[i].poststation = station;
	}
      station = prestation;
      din = predin;
    }
}

#define MAXWALKSIZE 1000
#define MUTAPROB_NUM 1
#define MUTAPROB_DEN 15
#define CROSSPROB_NUM 1
#define CROSSPROB_DEN 10

void
mutate_walk (int *size_in_out, struct step_s *walk)
{
  int size;
  int i;

  size = *size_in_out;
  switch ( random()%4 )
    {
    case 0:
      if ( size > 1 )
	size--;
      break;
    case 1:
      if ( size > 1 )
	{
	  size--;
	  for ( i=0 ; i<size ; i++ )
	    walk[i] = walk[i+1];
	}
      break;
    case 2:
      if ( size < MAXWALKSIZE )
	{
	  int station;
	  int din;

	  station = walk[size-1].poststation;
	  do {
	    din = random()%(directions[station].dirsize);
	  } while ( directions[station].dir[din].moc < NBMISSIONS
		    && ( directions[station].dir[din].ind
			 == missions[directions[station].dir[din].moc].misssize-1 ) );
	  walk[size].prestation = station;
	  walk[size].predin = din;
	  walk[size].moc = directions[station].dir[din].moc;
	  walk[size].ind = directions[station].dir[din].ind;
	  if ( directions[station].dir[din].moc < NBMISSIONS )
	    {
	      walk[size].poststation = missions[walk[size].moc].miss[walk[size].ind+1].sta;
	      walk[size].postdin = missions[walk[size].moc].miss[walk[size].ind+1].din;
	    }
	  else
	    {
	      int newind;

	      newind = random()%(connections[walk[size].moc-NBMISSIONS].connsize);
	      walk[size].poststation = connections[walk[size].moc-NBMISSIONS].conn[newind].sta;
	      walk[size].postdin = connections[walk[size].moc-NBMISSIONS].conn[newind].din;
	    }
	  size++;
	}
      break;
    case 3:
      if ( size < MAXWALKSIZE )
	{
	  int station;
	  int din;

	  for ( i=size ; i>0 ; i-- )
	    walk[i] = walk[i-1];
	  station = walk[1].prestation;
	  do {
	    din = random()%(directions[station].dirsize);
	  } while ( directions[station].dir[din].moc < NBMISSIONS
		    && directions[station].dir[din].ind == 0 );
	  walk[0].poststation = station;
	  walk[0].postdin = din;
	  walk[0].moc = directions[station].dir[din].moc;
	  if ( directions[station].dir[din].moc < NBMISSIONS )
	    {
	      walk[0].ind = directions[station].dir[din].ind-1;
	      walk[0].prestation = missions[walk[0].moc].miss[walk[0].ind].sta;
	      walk[0].predin = missions[walk[0].moc].miss[walk[0].ind].din;
	    }
	  else
	    {
	      int newind;

	      newind = random()%(connections[walk[0].moc-NBMISSIONS].connsize);
	      walk[0].ind = newind;
	      walk[0].prestation = connections[walk[0].moc-NBMISSIONS].conn[newind].sta;
	      walk[0].predin = connections[walk[0].moc-NBMISSIONS].conn[newind].din;
	    }
	  size++;
	}
      break;
    }
  *size_in_out = size;
}


void
cross_walks (int *size1_in_out, struct step_s *walk1,
	     int *size2_in_out, struct step_s *walk2)
{
  int size1, size2;
  int sizea, sizeb;
  struct step_s tmps;
  char visited[NBSTATIONS];
  int crosscnt, v1cnt, v2cnt;
  int i;
  int station;
  int cut1, cut2;

  size1 = *size1_in_out;
  size2 = *size2_in_out;
  if ( size1 < 2 )
    return;
  if ( size2 < 2 )
    return;
  for ( i=0 ; i<NBSTATIONS ; i++ )
    visited[i] = 0;
  for ( i=1 ; i<size1 ; i++ )
    visited[walk1[i].prestation] |= 1;
  crosscnt = 0;
  for ( i=1 ; i<size2 ; i++ )
    {
      if ( visited[walk2[i].prestation] == 1 )
	crosscnt++;
      visited[walk2[i].prestation] |= 2;
    }
  if ( ! crosscnt )
    return;
  station = -1;
  for ( i=0 ; i<NBSTATIONS ; i++ )
    {
      if ( visited[i] == 3 && random()%(crosscnt--) == 0 )
	{
	  station = i;
	  break;
	}
    }
  assert (station>=0);
  v1cnt = 0;
  for ( i=1 ; i<size1 ; i++ )
    if ( walk1[i].prestation == station )
      v1cnt++;
  cut1 = 0;
  for ( i=1 ; i<size1 ; i++ )
    if ( walk1[i].prestation == station && random()%(v1cnt--) == 0 )
      {
	cut1 = i;
	break;
      }
  assert (cut1>0);
  v2cnt = 0;
  for ( i=1 ; i<size2 ; i++ )
    if ( walk2[i].prestation == station )
      v2cnt++;
  cut2 = 0;
  for ( i=1 ; i<size2 ; i++ )
    if ( walk2[i].prestation == station && random()%(v2cnt--) == 0 )
      {
	cut2 = i;
	break;
      }
  assert (cut2>0);
  sizea = size2+cut1-cut2;
  if ( sizea > MAXWALKSIZE )
    sizea = MAXWALKSIZE;
  sizeb = size1+cut2-cut1;
  if ( sizeb > MAXWALKSIZE )
    sizeb = MAXWALKSIZE;
  for ( i=0 ; cut1+i<sizea || cut2+i<sizeb ; i++ )
    {
      if ( cut2+i < sizeb )
	tmps = walk1[cut1+i];
      if ( cut1+i < sizea )
	walk1[cut1+i] = walk2[cut2+i];
      if ( cut2+i < sizeb )
	walk2[cut2+i] = tmps;
    }
  *size1_in_out = sizea;
  *size2_in_out = sizeb;
}

#define HALFPOPSIZE 20
#define POPSIZE (2*HALFPOPSIZE)
#define REMAINPOPSIZE 5

struct fighter_s {
  int size1;
  struct step_s walk1[MAXWALKSIZE];
  int size2;
  struct step_s walk2[MAXWALKSIZE];
  int score1, bonus1, mscore1;
  int score2, bonus2, mscore2;
  int v;
  int score, bonus, mscore;
} fighters[POPSIZE];

void
init_pop (void)
{
  int i;
  int istation, fstation;

  for ( i=0 ; i<HALFPOPSIZE ; i++ )
    {
      istation = random()%NBSTATIONS;
      do
	fstation = random()%NBSTATIONS;
      while ( fstation == istation );
      fill_fastmap (istation);
      make_fastest_walk (fstation, MAXWALKSIZE,
			 fighters[i].walk1,
			 &fighters[i].size1);
      istation = random()%NBSTATIONS;
      do
	fstation = random()%NBSTATIONS;
      while ( fstation == istation );
      fill_fastmap (istation);
      make_fastest_walk (fstation, MAXWALKSIZE,
			 fighters[i].walk2,
			 &fighters[i].size2);
    }
}

void
mutate_pop (void)
{
  int i;

  for ( i=0 ; i<HALFPOPSIZE ; i++ )
    {
      if ( random()%MUTAPROB_DEN < MUTAPROB_NUM )
	mutate_walk (&fighters[i].size1, fighters[i].walk1);
      if ( random()%MUTAPROB_DEN < MUTAPROB_NUM )
	mutate_walk (&fighters[i].size2, fighters[i].walk2);
      if ( random()%CROSSPROB_DEN < CROSSPROB_NUM )
	cross_walks (&fighters[i].size1, fighters[i].walk1,
		     &fighters[i].size2, fighters[i].walk2);
    }
}

void
reproduce_pop (void)
{
  int i;
  int j;

  for ( i=0 ; i<HALFPOPSIZE ; i++ )
    {
      if ( random()%2 )
	{
	  fighters[i+HALFPOPSIZE].size1 = fighters[i].size1;
	  memcpy (fighters[i+HALFPOPSIZE].walk1, fighters[i].walk1,
		  fighters[i].size1*sizeof(struct step_s));
	}
      else
	{
	  fighters[i+HALFPOPSIZE].size1 = fighters[i].size2;
	  memcpy (fighters[i+HALFPOPSIZE].walk1, fighters[i].walk2,
		  fighters[i].size2*sizeof(struct step_s));
	}
      do
	j = random()%HALFPOPSIZE;
      while ( j == i );
      if ( random()%2 )
	{
	  fighters[i+HALFPOPSIZE].size2 = fighters[j].size1;
	  memcpy (fighters[i+HALFPOPSIZE].walk2, fighters[j].walk1,
		  fighters[j].size1*sizeof(struct step_s));
	}
      else
	{
	  fighters[i+HALFPOPSIZE].size2 = fighters[j].size2;
	  memcpy (fighters[i+HALFPOPSIZE].walk2, fighters[j].walk2,
		  fighters[j].size2*sizeof(struct step_s));
	}
    }
}

void
score_pop (void)
{
  int i;

  for ( i=0 ; i<POPSIZE ; i++ )
    {
      fighters[i].score1 = score_walk (fighters[i].size1, fighters[i].walk1);
      fighters[i].score2 = score_walk (fighters[i].size2, fighters[i].walk2);
      fighters[i].bonus1 = bonus_walk (fighters[i].size1, fighters[i].walk1);
      fighters[i].bonus2 = bonus_walk (fighters[i].size2, fighters[i].walk2);
      fighters[i].mscore1 = fighters[i].bonus1 - fighters[i].score1;
      fighters[i].mscore2 = fighters[i].bonus2 - fighters[i].score2;
      if ( fighters[i].mscore1 > fighters[i].mscore2 )
	{
	  fighters[i].v = 1;
	  fighters[i].score = fighters[i].score1;
	  fighters[i].bonus = fighters[i].bonus1;
	  fighters[i].mscore = fighters[i].mscore1;
	}
      else
	{
	  fighters[i].v = 2;
	  fighters[i].score = fighters[i].score2;
	  fighters[i].bonus = fighters[i].bonus2;
	  fighters[i].mscore = fighters[i].mscore2;
	}
    }
}

void
classify_pop (void)
{
  int i;
  int bestmscore, worstmscore;
  int cutmscore;
  int bestcutmscore;
  int cutcnt, icutcnt;
  int sel;
  int n;
  int class[HALFPOPSIZE];
  char selected[POPSIZE];
  struct fighter_s temp[HALFPOPSIZE];

  bestmscore = 0;
  for ( i=0 ; i<POPSIZE ; i++ )
    if ( i==0 || fighters[i].mscore > bestmscore )
      bestmscore = fighters[i].mscore;
  worstmscore = 0;
  for ( i=0 ; i<POPSIZE ; i++ )
    if ( i==0 || fighters[i].mscore < worstmscore )
      worstmscore = fighters[i].mscore;
  for ( i=0 ; i<POPSIZE ; i++ )
    selected[i] = 0;
  cutmscore = bestmscore+1;
  n = 0;
  while ( n<HALFPOPSIZE )
    {
      bestcutmscore = worstmscore;
      for ( i=0 ; i<POPSIZE ; i++ )
	if ( fighters[i].mscore > bestcutmscore
	     && fighters[i].mscore < cutmscore )
	  bestcutmscore = fighters[i].mscore;
      icutcnt = 0;
      for ( i=0 ; i<POPSIZE ; i++ )
	if ( fighters[i].mscore == bestcutmscore )
	  icutcnt++;
      while ( n<HALFPOPSIZE && icutcnt )
	{
	  sel = -1;
	  cutcnt = icutcnt--;
	  for ( i=0 ; i<POPSIZE ; i++ )
	    if ( fighters[i].mscore == bestcutmscore && ! selected[i]
		 && random()%(cutcnt--)==0 )
	      {
		sel = i;
		break;
	      }
	  assert (sel >= 0);
	  selected[sel] = 1;
	  class[n++] = sel;
	}
      cutmscore = bestcutmscore;
    }
  for ( i=0 ; i<HALFPOPSIZE ; i++ )
    temp[i] = fighters[class[i]];
  for ( i=0 ; i<HALFPOPSIZE ; i++ )
    fighters[i] = temp[i];
}

void
revitalize_pop (void)
{
  int i;
  int istation, fstation;

  for ( i=REMAINPOPSIZE ; i<HALFPOPSIZE ; i++ )
    {
      istation = random()%NBSTATIONS;
      do
	fstation = random()%NBSTATIONS;
      while ( fstation == istation );
      fill_fastmap (istation);
      make_fastest_walk (fstation, MAXWALKSIZE,
			 fighters[i].walk1,
			 &fighters[i].size1);
      istation = random()%NBSTATIONS;
      do
	fstation = random()%NBSTATIONS;
      while ( fstation == istation );
      fill_fastmap (istation);
      make_fastest_walk (fstation, MAXWALKSIZE,
			 fighters[i].walk2,
			 &fighters[i].size2);
    }
}

int
main (void)
{
  int generation;

  srandom (time (NULL));
  generation = 0;
  init_pop ();
  while ( 1 )
    {
      mutate_pop ();
      reproduce_pop ();
      score_pop ();
      classify_pop ();
      if ( generation%100 == 0 )
	{
	  printf ("generation %d: MSCORE = (%d) - (%d) = %d\n",
		  generation,
		  fighters[0].bonus, fighters[0].score,
		  fighters[0].mscore);
	  if ( generation%1000 == 0 )
	    {
	      if ( fighters[0].v == 1 )
		print_walk (fighters[0].size1, fighters[0].walk1);
	      else
		print_walk (fighters[0].size2, fighters[0].walk2);
	    }
	}
      if ( generation%10 == 0 )
	revitalize_pop ();
      generation++;
    }
  return 0;
}
