
package edu.hws.GA;

import java.awt.*;
import java.awt.event.*;

class GACanvas extends Panel implements ActionListener, Runnable {

   private GAFrame owner;
   private MenuItem stopGo;
   private RadioGroupMenu speedMenu;
   private RadioGroupMenu plantBirth, plantCount, plantRegrowth,
                          populationM, eaterBirth, mutationProbability,
                          crossoverProbability;
                          
   private static Color green = new Color(0,180,0);
                          
   private Image OSC;
   private Graphics OSG;
   private int width,height;
   
   private int population;
   private int defaultPlantCt;
   private double m_prob;
   private double c_prob;
   
   private Thread runner;
   private static final int GO=0, PAUSE=1, RESTART=2;
   private int status;
   
   ReportWin rWin;
   
   private static final int turnLeft=0, turnRight=1, forward=2, back=3;
   private static final int seeWall=0, seeEater=1, seeSpace=2, seePlant=3;
   private static final int 
      aWall = 9999,
      daysPerYear = 250,
      sourceCt = 20;

   
   int rows, cols, cellSize;
   int centerRow, centerCol;
   int[][] cellContents;

   Eater[] eater, neweater;
   int eaterCt;

   int totalScore;
   int highscore;
   double avgScore;
   double bestAvg;

   int[][] plant = new int[501][2];
   int[][] plantSource = new int[21][2];
   int actualPlantCt;

   int year, day;

   long lastIdle;
   
   private boolean draw = true;
   
   private static class Eater {
         int row, col;
         int score;
         Chromosome gene = new Chromosome();
         int currentState;
         int facing;
      }
      
   private static class Chromosome {
      byte[][] newState = new byte[16][4];
      byte[][] whatToDo = new byte[16][4];
      void randomize() {
         for (int i = 0; i < 16; i++) {
            for (int j = seeWall; j <= seePlant; j++) {
                newState[i][j] = (byte)(Math.random()*16);
                whatToDo[i][j] = (byte)(Math.random()*4);
            }
         }
      }
      void crossWith(Chromosome c) {
         int crossPoint = (int)(Math.random()*128);
         byte temp;
         int ct = 0;
         for (int i = 0; i < 16; i++) {
            for (int j = 0; j < 4; j++) {
               if (ct > crossPoint) {
                  temp  = newState[i][j];
                  newState[i][j] = c.newState[i][j];
                  c.newState[i][j] = temp;
               }
               ct++;
               if (ct > crossPoint) {
                  temp  = whatToDo[i][j];
                  whatToDo[i][j] = c.whatToDo[i][j];
                  c.whatToDo[i][j] = temp;
               }
               ct++;
            }
         }
      }
      Chromosome copy() {
         Chromosome c = new Chromosome();
         for (int i = 0; i < 16; i++) {
            for (int j = 0; j < 4; j++) {
               c.whatToDo[i][j] = whatToDo[i][j];
               c.newState[i][j] = newState[i][j];
            }
         }
         return c;
      }
   }
   
   GACanvas(GAFrame owner) {
      this.owner = owner;
      setBackground(Color.white);
      setFont(new Font("Monospaced", Font.PLAIN, 12));
   }
   
   synchronized public void paint(Graphics g) {
      if (OSC == null) {
         g.setColor(Color.white);
         g.fillRect(0,0,getSize().width,getSize().height);
      }
      else {
         g.drawImage(OSC,0,0,this);
      }
   }
   
   public void update(Graphics g) {
      paint(g);
   }
   
   synchronized public void start() {
      width = getSize().width;
      height = getSize().height;
      OSC = createImage(width,height);
      OSG = OSC.getGraphics();
      OSG.setColor(Color.white);
      OSG.fillRect(0,0,width,height);
      OSG.setColor(Color.black);
      OSG.drawLine(0,height-19,width,height-19);
      cellSize = width / 60;
      cols = 60;
      rows = (height-20) / cellSize;
      cellContents = new int[rows+2][cols+2];
      centerRow = rows / 2;
      centerCol = cols / 2;
      for (int i = 0; i < rows+2; i++) {
         cellContents[i][0] = aWall;
         cellContents[i][cols + 1] = aWall;
      }
      for (int j = 0; j < cols+2; j++) {
         cellContents[0][j] = aWall;
         cellContents[rows + 1][j] = aWall;
      }
      eater = new Eater[150];
      for (int i = 0; i < 150; i++)
         eater[i] = new Eater();
      neweater = new Eater[150];
      for (int i = 0; i < 150; i++)
         neweater[i] = new Eater();
      runner = new Thread(this);
      status = RESTART;
      runner.start();
   }
   
   synchronized public void stop() {
      if (runner != null && runner.isAlive())
         runner.stop();
   }
   
   MenuBar getMenuBar() {
   
      MenuBar menubar = new MenuBar();

      Menu controlMenu = new Menu("Control");
      controlMenu.addActionListener(this);
      stopGo = new MenuItem("Pause", new MenuShortcut('P'));
      controlMenu.add(stopGo);
      controlMenu.add("Start From Scratch");
      controlMenu.add("End the World");
      menubar.add(controlMenu);
      
      speedMenu = new RadioGroupMenu("Speed",
          new String[] { "Fastest (Stats only)", "Fast", "Moderate", "Slow", "Slower" }, 1 ) {
             public void itemStateChanged(ItemEvent evt) {
                super.itemStateChanged(evt);
                synchronized(GACanvas.this) {
                   if (draw && getSelectedIndex() == 0) {
                      draw = false;
                      rWin.toFront();
                      if (OSG != null) {
                         OSG.setColor(Color.white);
                         OSG.fillRect(0,0,width,height-20);
                         OSG.fillRect(0,height-18,width/3,height-18);
                         repaint();
                      }
                   }
                   else if (!draw && getSelectedIndex() > 0) {
                      draw = true;
                      owner.toFront();
                      if (OSG != null)
                         redrawAll(OSG);
                   }
                   GACanvas.this.notify();
                }
             }
          };
      menubar.add(speedMenu);
      
      plantBirth = new RadioGroupMenu("Plants Grow",
          new String[] { "In Rows", "In Clumps", "At Random", "Along the Bottom", "Along the Edges" }, 1);
          
      plantCount = new RadioGroupMenu("Number Of Plants",
          new String[] { "50", "100", "150", "250", "500" }, 3);

      plantRegrowth = new RadioGroupMenu("When a Plant is Eaten",
          new String[] { "It grows back somewhere", "It grows back nearby", "It's Gone" }, 0);

      populationM = new RadioGroupMenu("Approximate Population",
          new String[] { "10", "20", "25", "30", "40", "50", "75", "100" }, 2);

      eaterBirth = new RadioGroupMenu("Eaters are Born",
          new String[] { "At the Center", "In a Corner", "At Random Location", "At Parent's Location" }, 2);

      mutationProbability = new RadioGroupMenu("Mutation Probability",
          new String[] { "Zero", "0.25%", "0.5%", "1%", "2%", "3%", "5%", "10%" }, 3);

      crossoverProbability = new RadioGroupMenu("Crossover Probability",
          new String[] { "Zero", "10%", "25%", "50%", "75%", "100%" }, 4);

      Menu designMenu = new Menu("WorldDesign");
      designMenu.add(plantBirth);
      designMenu.add(plantCount);
      designMenu.add(plantRegrowth);
      designMenu.add(populationM);
      designMenu.add(eaterBirth);
      designMenu.add(mutationProbability);
      designMenu.add(crossoverProbability);
      menubar.add(designMenu);
      
      return menubar;
      
   } // end getMenuBar();
   
   public Dimension getPreferredSize() {
      return new Dimension(600,470);
   }
   
   synchronized public void actionPerformed(ActionEvent evt) {
      String cmd = evt.getActionCommand();
      System.out.println(cmd);
      if (cmd.equals("Pause")) {
         status = PAUSE;
         stopGo.setLabel("Go");
         notify();
      }
      else if (cmd.equals("Go")) {
         status = GO;
         stopGo.setLabel("Pause");
         notify();
      }
      else if (cmd.equals("Start From Scratch")) {
         status = RESTART;
         stopGo.setLabel("Pause");
         notify();
      }
      else if (cmd.equals("End the World")) {
         owner.close();
      }
   }
   
   public void run() {
      while(true) {
         synchronized(this) {
            while (status == PAUSE) {
               try {
                  wait();
               }
               catch (InterruptedException e) {
               }
            }
            if (status == RESTART) {
               year = 1;
               day = 1;
               rWin.clear();
               newPopulation();
               status = GO;
            }
         }
         if (status == GO) {
            int delay = 0;
            int speedIndex = speedMenu.getSelectedIndex();
            if (day > 250) {
               doEndOFYear();
               if (speedIndex == 0) {
                  delay = 20;
                  Graphics g = getGraphics();
                  showYearlyStats(g);
                  g.dispose();
               }
               year++;
               day = 1;
            }
            else {
               doDay();
               showDay(OSG);
               day++;
               switch (speedIndex) {
                  case 1: delay = 10; break;
                  case 2: delay = 200; break;
                  case 3: delay = 400; break;
                  case 4: delay = 1000; break;
               }
            }
            if (speedIndex > 0)
               repaint();
            synchronized(this) {
               if (delay > 0 && status == GO) {
                  try {
                     wait(delay);
                  }
                  catch(InterruptedException e) {
                  }
               }
            }
         }
      }
   }
   
   private void redrawAll(Graphics g) {
      g.setColor(Color.red);
      for (int i = 0; i < eaterCt; i++)
         DrawEater(eater[i].facing, eater[i].row, eater[i].col);
      g.setColor(green);
      for (int i = 0; i < actualPlantCt; i++)
         DrawPlant(OSG,plant[i][0],plant[i][1]);
   }
   
   private void getPopulation() {
      switch (populationM.getSelectedIndex()) {
         case 0: population = 10; break;
         case 1: population = 20; break;
         case 2: population = 25; break;
         case 3: population = 30; break;
         case 4: population = 40; break;
         case 5: population = 50; break;
         case 6: population = 75; break;
         case 7: population = 100; break;
      }
   }
   
   private void getDefaultPlantCount() {
      switch (plantCount.getSelectedIndex()) {
         case 0: defaultPlantCt = 50; break;
         case 1: defaultPlantCt = 100; break;
         case 2: defaultPlantCt = 150; break;
         case 3: defaultPlantCt = 250; break;
         case 4: defaultPlantCt = 500; break;
      }
   }
   
   private void getCrossoverProb() {
      switch (crossoverProbability.getSelectedIndex()) {
         case 0: c_prob = 0; break;
         case 1: c_prob = 0.1; break;
         case 2: c_prob = 0.25; break;
         case 3: c_prob = 0.5; break;
         case 4: c_prob = 0.75; break;
         case 5: c_prob = 1; break;
      }
   }
   
   private void getMutationProb() {
      switch (mutationProbability.getSelectedIndex()) {
         case 0: m_prob = 0; break;
         case 1: m_prob = 0.0025; break;
         case 2: m_prob = 0.005; break;
         case 3: m_prob = 0.01; break;
         case 4: m_prob = 0.02; break;
         case 5: m_prob = 0.03; break;
         case 6: m_prob = 0.05; break;
         case 7: m_prob = 0.1; break;
      }
   }
   
private int[] FindSpace () {
      int row, col;
      do {
         row = (int)(Math.random()*rows) + 1;
         col = (int)(Math.random()*cols) + 1;
      } while (cellContents[row][col] != 0);
      return new int[] { row, col };
}

private int[] FindSource() {
      int row, col;
      int plants_item = plantBirth.getSelectedIndex();
      if (plants_item < 4) {
         do {
            row = (int)(Math.random()*rows) + 1;
            col = (int)(Math.random()*cols) + 1;
         } while (cellContents[row][col] != 0);
      }
      else {
            do {
               int n = (int)(Math.random() * (2 * (rows + cols)));
               if (n < rows) {
                     row = (int)(Math.random()*rows) + 1;
                     col = 1;
               }
               else if( n < 2 * rows) {
                     row = (int)(Math.random()*rows) + 1;
                     col = cols;
               }
               else if (n < 2 * rows + cols) {
                     row = 1;
                     col = (int)(Math.random()*cols) + 1;
               }
               else {
                     row = rows;
                     col = (int)(Math.random()*cols) + 1;
               }
            } while (cellContents[row][col] != 0);
      }
      return new int[] { row, col };
   }

private int[] FindSpaceNear (int row, int col) {
      int r, c, dx, dy, ct;
      ct = 0;
      while (ct < 20) {
         if (cellContents[row][col] == 0)
            return new int[] { row, col };
         else {
               ct = ct + 1;
               switch ((int)(Math.random()*4)) {
                  case 0: 
                     if (row > 1)
                        row = row - 1;
                     break;
                  case 1: 
                     if (row < rows)
                        row = row + 1;
                     break;
                  case 2: 
                     if (col > 1)
                        col = col - 1;
                     break;
                  default: 
                     if (col < cols)
                        col = col + 1;
               }
          }
      }
      r = row;
      c = col;
      while (cellContents[r][c] != 0) {
         do {
            dx = (int)(Math.random()*3) - 1;
            dy = (int)(Math.random()*3) - 1;
         } while ((dx == 0) && (dy == 0));
         while (!((cellContents[r][c] == 0) || (cellContents[r][c] == aWall))) {
            r = r + dx;
            c = c + dy;
         }
         if (cellContents[r][c] == aWall) {
               r = row;
               c = col;
         }
      }
      return new int[] { r, c };
   }
   
   
   synchronized private void newPopulation() {
      getPopulation();
      getDefaultPlantCount();
      for (int i = 1; i <= rows; i++)
         for (int j = 1; j <= cols; j++)
            cellContents[i][j] = 0;
      for (int i = 1; i <= population; i++) {
         eater[i].score = 1;
         eater[i].gene.randomize();
         eater[i].currentState = 0;
         eater[i].facing = (int)(Math.random()*4);
         PutNewEater(i, false);
      }
      totalScore = population;
      eaterCt = population;
      bestAvg = 0;
      OSG.setColor(Color.white);
      OSG.fillRect(0,0,width,height-20);
      for (int i = 1; i <= 20; i++)
         plantSource[i] = FindSource();
      for (int i = 1; i <= defaultPlantCt; i++)
         PutNewPlant(i);
      actualPlantCt = defaultPlantCt;
   }
   
   synchronized private void doDay() {
      for (int eaterNum = 1; eaterNum <= eaterCt; eaterNum ++) {
         int row = eater[eaterNum].row;
         int col = eater[eaterNum].col;
         int facing = eater[eaterNum].facing;
         switch (eater[eaterNum].facing) {
            case 0: 
               col = col + 1;
               break;
            case 1: 
               row = row - 1;
               break;
            case 2: 
               col = col - 1;
               break;
            case 3: 
               row = row + 1;
               break;
         }
         int b = cellContents[row][col];
         int v;
         if (b == 0) 
            v = seeSpace;
         else if (b < 0)
            v = seePlant;
         else if (b == aWall)
            v = seeWall;
         else
            v = seeEater;
         int s = eater[eaterNum].currentState;
         byte newState = eater[eaterNum].gene.newState[s][v];
         byte whatToDo = eater[eaterNum].gene.whatToDo[s][v];
         eater[eaterNum].currentState = newState;
         int newRow = eater[eaterNum].row, newCol = eater[eaterNum].col;
         switch (whatToDo) {
            case 0: 
               facing--;
               if (facing < 0)
                  facing = 3;
               break;
           case 1:
               facing++;
               if (facing > 3)
                  facing = 0;
               break;
           case 2:
               newRow = row;  // already have the right value for moving forward, from above
               newCol = col; 
               if (cellContents[newRow][newCol] > 0) 
                  continue;
               break;
           case 3: {
              col = eater[eaterNum].col;
              row = eater[eaterNum].row;
              switch (eater[eaterNum].facing) {
                 case 0: 
                    col = col - 1;
                    break;
                 case 1: 
                    row = row + 1;
                    break;
                 case 2: 
                    col = col + 1;
                    break;
                 case 3: 
                    row = row - 1;
                    break;
               }
               newRow = row;
               newCol = col;
               if (cellContents[newRow][newCol] > 0) 
                  continue;
             }
             break;
         }
         MoveEater(eaterNum,facing,newRow,newCol);
      }
   }
   
   synchronized private void doEndOFYear() {
      OSG.setColor(Color.white);
      for (int i = 1; i <= actualPlantCt; i++) {
         DrawPlant(OSG,plant[i][0],plant[i][1]);
         cellContents[plant[i][0]][plant[i][1]] = 0;
      }
      breed();
      getDefaultPlantCount();
      actualPlantCt = defaultPlantCt;
      for (int i = 1; i <= actualPlantCt; i++)
         PutNewPlant(i);
      showYearlyStats(OSG);
      rWin.doReport(year,avgScore,highscore);
   }
   
   synchronized private void showYearlyStats(Graphics g) {
      g.setColor(Color.white);
      g.fillRect(width/3,height-18,width,18);
      g.setColor(Color.black);
      double avg = ( ((int)(avgScore*100)) / 100.0 );
      g.drawString("Year " + year + " Avg. Score = " + avg + ", High Score = " + highscore,
                           width/3, height-4);
   }
   
   synchronized private void showDay(Graphics g) {
      if (day == 0 || ! draw)
         return;
      g.setColor(Color.white);
      g.fillRect(0,height-18,width/3,18);
      g.setColor(Color.black);
      g.drawString("Year " + year + ", Day " + day,5,height-4);
   }
   
private void  DrawPlant (Graphics g, int row, int col) {
      g.drawOval((col - 1) * cellSize + 1, (row - 1) * cellSize + 1, cellSize - 3, cellSize - 3);
   }

private void  PutNewPlant (int loc) {
      int row, col, n, d;
      int[] location;
      switch (plantBirth.getSelectedIndex()) {
         case 0:  {
               if (Math.random() < 0.5)
                  d = 1;
               else
                  d = -1;
               do {
                  n = (int)(Math.random()*20) + 1;
                  row = plantSource[n][0];
                  col = plantSource[n][1];
                  while ((col > 0) && (col <= cols) && (cellContents[row][col] != 0))
                     col = col + d;
               } while (! ((col > 0) && (col <= cols) && (cellContents[row][col] == 0)) );
               location = new int[] { row, col };
               if (Math.random() < 0.05)
                  plantSource[n] = FindSource();
               break;
            }
         case 1:
         case 4: {
               n = (int)(Math.random()*20) + 1;
               row = plantSource[n][0];
               col = plantSource[n][1];
               location = FindSpaceNear(row, col);
               if (Math.random() < 0.05)
                  plantSource[n] = FindSource();
                break;
            }
         case 2:  {
              location = FindSpace();
              break;
            }
         default:  {
               col = (int)(Math.random()*cols) + 1;
               row = rows;
               location = FindSpaceNear(row,col);
            }
      }
      plant[loc] = location;
      cellContents[location[0]][location[1]] = -loc;
      if (draw) {
         OSG.setColor(green);
         DrawPlant(OSG,location[0],location[1]);
      }
   }


private void  RemovePlant (int plantNum) {
      int r, c;
      int speed_item = speedMenu.getSelectedIndex();
      int birthplace_item = plantRegrowth.getSelectedIndex();
      if (draw) {
         OSG.setColor(Color.white);
         DrawPlant(OSG,plant[plantNum][0], plant[plantNum][1]);
      }
      if (birthplace_item == 0)
         PutNewPlant(plantNum);
      else if (birthplace_item == 1)  {
            r = plant[plantNum][0];
            c = plant[plantNum][1];
            int[] loc = FindSpaceNear(r, c);
            plant[plantNum] = loc;
            cellContents[loc[0]][loc[1]] = -plantNum;
         }
      else {
            r = plant[actualPlantCt][0];
            c = plant[actualPlantCt][1];
            cellContents[r][c] = -plantNum;
            plant[plantNum] = plant[actualPlantCt];
            actualPlantCt = actualPlantCt - 1;
         }
      if (draw && birthplace_item != 2)  {
            OSG.setColor(green);
            DrawPlant(OSG,plant[plantNum][0], plant[plantNum][1]);
         }
   }

private void  DrawEater (int facing, int row, int col) {
      int left, right, top, bottom;
      int h, v;
      left = (col - 1) * cellSize + 1;
      top =  (row - 1) * cellSize + 1;
      right = left + cellSize - 2;
      bottom = top + cellSize - 2;
      h = (left + right) / 2;
      v = (top + bottom) / 2;
      switch (facing) {
         case 0:  {
               OSG.drawLine(left,top,left,bottom-1);
               OSG.drawLine(left,v,right-1,v);
               break;
            }
         case 1:  {
               OSG.drawLine(left,bottom-1,right-1,bottom-1);
               OSG.drawLine(h,top,h,bottom-1);
               break;
            }
         case 2:  {
               OSG.drawLine(right-1,top,right-1,bottom-1);
               OSG.drawLine(left,v,right-1,v);
               break;
            }
         case 3:  {
               OSG.drawLine(left,top,right-1,top);
               OSG.drawLine(h,top,h,bottom-1);
               break;
            }
      }
   }

private void  MoveEater (int num, int facing, int newrow, int newcol) {
      int row, col;
      row = eater[num].row;
      col = eater[num].col;
      cellContents[row][col] = 0;
      if (draw) {
         OSG.setColor(Color.white);
         DrawEater(eater[num].facing,row,col);
      }
      eater[num].row = newrow;
      eater[num].col = newcol;
      eater[num].facing = facing;
      if (cellContents[newrow][newcol] < 0)  {
            eater[num].score = eater[num].score + 1;
            totalScore = totalScore + 1;
            RemovePlant(-cellContents[newrow][newcol]);
         }
      cellContents[newrow][newcol] = num;
      if (draw) {
         OSG.setColor(Color.red);
         DrawEater(facing,newrow,newcol);
      }
   }



private void  PutNewEater (int loc, boolean brandNew) { // loc = location in eater array
      int row, col;
      int[] location;
      switch (eaterBirth.getSelectedIndex()) {
         case 0:  {
               row = centerRow + ((int)(Math.random()*12) - 7);
               col = centerCol + ((int)(Math.random()*12) - 7);
               location = FindSpaceNear(row, col);
               break;
            }
         case 1:  {
               row = (int)(Math.random()*12) + 1;
               col = (int)(Math.random()*12) + 1;
               location = FindSpaceNear(row, col);
               break;
            }
         case 2: {
               location = FindSpace();
               break;
            }
         default: { 
            if (brandNew)
               location = FindSpace();
            else {
                  row = eater[loc].row;
                  col = eater[loc].col;
                  location = FindSpaceNear(row, col);
               }
         }
      }
      cellContents[location[0]][location[1]] = loc;
      eater[loc].row = location[0];
      eater[loc].col = location[1];
      eater[loc].facing = (int)(Math.random()*4);
      if (draw) {
         OSG.setColor(Color.red);
         DrawEater(eater[loc].facing, location[0], location[1]);
      }
   }

private void breed() {
      int i, j, l, r, t, a, b;
      int s;
      int d;
      Eater[] temp;
      int newCt;
      double fitness;
      double f;
      int[] choose = new int[151];
      int usedCt;
      highscore = 0;
      OSG.setColor(Color.white);
      for (i = 1; i <= eaterCt; i++) {
            if (eater[i].score > highscore)
               highscore = eater[i].score;
            if (draw)
               DrawEater(eater[i].facing, eater[i].row, eater[i].col);
            cellContents[eater[i].row][eater[i].col] = 0;
         }
      avgScore = (double)totalScore / eaterCt;
      totalScore = 0;
      newCt = 0;
      getPopulation();
      f = (1 / avgScore) * ((double)population / eaterCt);
      do {
         for (i = 1; i <= eaterCt; i++) {
               fitness = eater[i].score * f;
               while ((fitness >= 1) && (newCt < 150)) {
                     fitness = fitness - 1;
                     newCt = newCt + 1;
                     neweater[newCt].row = eater[i].row;
                     neweater[newCt].col = eater[i].col;
                     neweater[newCt].gene = eater[i].gene.copy();
                     neweater[newCt].score = 1;
                     neweater[newCt].facing = (int)(Math.random()*4);
                     neweater[newCt].currentState = 0;
                  }
               if (Math.random() < fitness  && newCt < 150) {
                     newCt = newCt + 1;
                     neweater[newCt].row = eater[i].row;
                     neweater[newCt].col = eater[i].col;
                     neweater[newCt].gene = eater[i].gene.copy();
                     neweater[newCt].score = 1;
                     neweater[newCt].facing = (int)(Math.random()*4);
                     neweater[newCt].currentState = 0;
               }
           }
      } while (newCt == 0);
      temp = eater;
      eater = neweater;
      neweater = temp;
      eaterCt = newCt;
      totalScore = eaterCt;
      getMutationProb();
      if (m_prob > 0) {
            for (i = 1; i <= eaterCt; i++)
               for (s = 0; s < 16; s++)
                  for (d = seeWall; d <= seePlant; d++) {
                    if (Math.random() < m_prob)
                        eater[i].gene.newState[s][d] = (byte)(Math.random()*16);
                    if (Math.random() < m_prob)
                        eater[i].gene.whatToDo[s][d] = (byte)(Math.random()*4);
                  }
         }
      getCrossoverProb();
      if (c_prob > 0) {
            for (i = 1; i <= eaterCt; i++)
               choose[i] = i;
            usedCt = eaterCt;
            int stop = eaterCt - (int)(eaterCt*c_prob);
            if (stop < 1)
               stop = 1;
            while (usedCt > stop) {
                  r = (int)(Math.random()*usedCt) + 1;
                  a = choose[r];
                  choose[r] = choose[usedCt];
                  usedCt = usedCt - 1;
                  r = (int)(Math.random()*usedCt) + 1;
                  b = choose[r];
                  choose[r] = choose[usedCt];
                  usedCt = usedCt - 1;
                  eater[a].gene.crossWith(eater[b].gene);
               }
         }
      for (i = 1; i <= eaterCt; i++)
            PutNewEater(i, false);
   }
            
}
