home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / enxle1f6 / src / games / battle / server / serverboard / serverboard.java < prev    next >
Encoding:
Java Source  |  1996-08-14  |  16.0 KB  |  594 lines

  1. /*
  2.  * @(#)ServerBoard.java
  3.  */
  4. package games.Battle.server.ServerBoard;
  5.  
  6. import java.awt.*;
  7. import java.util.*;
  8. import java.lang.*;
  9.  
  10. import games.Battle.shared.sys.*;
  11. import games.Battle.server.GeoMorph.*;
  12.  
  13. /**
  14.  * ServerBoard extends the board to keep track of things that the server
  15.  * side wants to know about the game board.
  16.  *
  17.  * @version 1.00
  18.  * @author Jay Steele
  19.  * @author Alex Nicolaou
  20.  */
  21.  
  22. public class ServerBoard extends Board {
  23.     /**
  24.      * the log file to record interesting events and some debug output.
  25.      */
  26.     Logger logfile;
  27.  
  28.     /** 
  29.      * the referee responsible for watching this game.
  30.      */
  31.     GameReferee referee;
  32.  
  33.     /**
  34.      * a random number machine for this class
  35.      */
  36.     static Random rand = new Random();
  37.  
  38.     /**
  39.      * this is the maximum number of actual troops permitted in
  40.      * a cell at one time.
  41.      */
  42.     public static final int maxTroops = 100;
  43.  
  44.     /**
  45.      * the number of players actually on this board.
  46.      */
  47.     int numPlayers;
  48.     /** 
  49.      * an array of booleans that indicates who is still alive
  50.      */
  51.     boolean[] alive;
  52.     /**
  53.      * an array that indicates who has how many troops to help determine
  54.      * who is still alive
  55.      */
  56.     int[] troops;
  57.  
  58.     /**
  59.      * given a referee and a log file, construct a new game board.
  60.      * @param ref the referee
  61.      * @param logfile the log service
  62.      */
  63.     public ServerBoard(GameReferee ref, Logger logfile) {
  64.         super();
  65.         this.logfile = logfile;
  66.         referee = ref;
  67.  
  68.         troops = new int[Symbols.MAX_PLAYERS];
  69.         alive = new boolean[Symbols.MAX_PLAYERS];
  70.         for (int i = 0; i < alive.length; i++) 
  71.             alive[i] = false;
  72.     }
  73.  
  74.     /**
  75.      * makes a cell for the server board
  76.      */
  77.     public Cell makeCell(int r, int c) {
  78.         return new ServerCell(r, c);
  79.     }
  80.  
  81.     /**
  82.      * a geomorph world generator to ensure nice terrain
  83.      */
  84.     GeoMorph world;
  85.  
  86.     /**
  87.      * produce terrain based on the geomorph tiles. 
  88.      */
  89.     public void makeRandomTerrain() {
  90.         try {
  91.             int maxDim = Math.max(Rules.rows, Rules.cols);
  92.             int numTiles = maxDim / GeoTile.GEO_TILESIZE;
  93.             if (maxDim % GeoTile.GEO_TILESIZE > 0)
  94.                 numTiles++;
  95.  
  96.             world = new GeoMorph("tiles/tile", numTiles);
  97.  
  98.             for (int r=0; r<Rules.rows; r++) {
  99.                 for (int c=0; c<Rules.cols; c++) {
  100.                     ServerCell cell = (ServerCell)getCell(r,c);
  101.                     int level = world.terrain(r, c);
  102.                     cell.setTerrain(level);
  103.                 }
  104.             }
  105.  
  106.         }
  107.         catch (Exception e) {
  108.             /* this should never happen */
  109.             logfile.log("ServerBoard::makeRandomTerrain: GeoMorph err");
  110.             for (int r=0; r<Rules.rows; r++) {
  111.                 for (int c=0; c<Rules.cols; c++) {
  112.                     ServerCell cell = (ServerCell)getCell(r,c);
  113.                     int level = Math.abs(rand.nextInt()) % Symbols.NUM_TERRAIN_LEVELS;
  114.                     cell.setTerrain(level);
  115.                 }
  116.             }
  117.         }
  118.     }
  119.  
  120.     /**
  121.      * the amount that the cities produce each turn.
  122.      */
  123.     static final int GROW = 5;
  124.  
  125.     /**
  126.      * given a player number give the player a new city on the map.
  127.      */
  128.     public void placePlayer(int player) {
  129.         if (player >= numPlayers)
  130.             numPlayers = player + 1;
  131.  
  132.         alive[player] = true;
  133.  
  134.         boolean done = false;
  135.         while (!done) {
  136.             Point p = world.getRandomCity();
  137.             int row = p.x;
  138.             int col = p.y;
  139.             ServerCell cell = (ServerCell)getCell(row, col);
  140.             if (cell.getTerrain() > 0 
  141.                 && cell.getOccupancy() == Symbols.UNOCCUPIED)
  142.             {
  143.                 cell.setOccupancy(player);
  144.                 cell.setCity(Rules.maxCitySize);
  145.                 addVisibility(row, col, player);
  146.                 done = true;
  147.             }
  148.         }
  149.     }
  150.  
  151.     /**
  152.      * makes the given cell and the surrounding region to the 
  153.      * horizon visible to the given player
  154.      * @param row the row of the cell to adjust from
  155.      * @param col the column of the cell to adjust from
  156.      * @param player the player who is now in this position
  157.      */
  158.     public void addVisibility(int row, int col, int player) {
  159.         int horizon = Rules.horizon;
  160.         int startr = row - horizon;
  161.         int startc = col - horizon;
  162.         int endr = row + horizon;
  163.         int endc = col + horizon;
  164.         if (startr < 0) startr = 0;
  165.         if (startc < 0) startc = 0;
  166.         if (endr > Rules.rows-1) endr = Rules.rows - 1;
  167.         if (endc > Rules.cols-1) endc = Rules.cols - 1;
  168.         for (int r=startr; r<=endr; r++) {
  169.             for (int c=startc; c<=endc; c++) {
  170.                 ServerCell cell = (ServerCell)getCell(r,c);
  171.                 cell.setVisible(player, true);
  172.             }
  173.         }
  174.     }
  175.  
  176.     /**
  177.      * returns true if the given row,col cell is visible to
  178.      * the given player
  179.      * @param row the row
  180.      * @param col the column
  181.      * @param player the player who is trying to see row, col
  182.      */
  183.     public boolean isVisible(int row, int col, int player) {
  184.         int horizon = Rules.horizon;
  185.         int startr = row - horizon;
  186.         int startc = col - horizon;
  187.         int endr = row + horizon;
  188.         int endc = col + horizon;
  189.         if (startr < 0) startr = 0;
  190.         if (startc < 0) startc = 0;
  191.         if (endr > Rules.rows-1) endr = Rules.rows - 1;
  192.         if (endc > Rules.cols-1) endc = Rules.cols - 1;
  193.         for (int r=startr; r<=endr; r++) {
  194.             for (int c=startc; c<=endc; c++) {
  195.                 ServerCell cell = (ServerCell)getCell(r,c);
  196.                 if (cell.getOccupancy() == player)
  197.                     return true;
  198.             }
  199.         }
  200.         return false;
  201.     }
  202.  
  203.     /**
  204.      * Removes visibility of adjacent cells for player assuming player
  205.      * just lost occupancy of the cell at row, col.
  206.      * row, col can't be occupied by player, or method will not
  207.      * not work properly--i.e. unoccupy it first.
  208.      * @param row the row of the cell that has been vacated
  209.      * @param col the column of the cell that has been vacated
  210.      * @param player the player who is no longer in this cell
  211.      */
  212.     public void removeVisibility(int row, int col, int player) {
  213.  
  214.         // if the player is not alive, we do not remove visibility
  215.         // (that way surrendered players can continue to view the
  216.         // entire board
  217.         if (!alive[player])
  218.             return;
  219.  
  220.         int horizon = Rules.horizon;
  221.         int startr = row - horizon;
  222.         int startc = col - horizon;
  223.         int endr = row + horizon;
  224.         int endc = col + horizon;
  225.         if (startr < 0) startr = 0;
  226.         if (startc < 0) startc = 0;
  227.         if (endr > Rules.rows-1) endr = Rules.rows - 1;
  228.         if (endc > Rules.cols-1) endc = Rules.cols - 1;
  229.         for (int r=startr; r<=endr; r++) {
  230.             for (int c=startc; c<=endc; c++) {
  231.                 ServerCell cell = (ServerCell)getCell(r,c);
  232.                 if (! isVisible(r, c, player))
  233.                     cell.setVisible(player, false);
  234.             }
  235.         }
  236.     }
  237.  
  238.     /**
  239.      * produce debugging output
  240.      */
  241.     public void asciiDump(int player) {
  242.         for (int r=0; r< Rules.rows; r++) {
  243.             for (int c=0; c< Rules.cols; c++) {
  244.                 ServerCell cell = (ServerCell)getCell(r,c);
  245.                 if (! cell.isVisible(player)) {
  246.                     System.out.print("X ");
  247.                 } else {
  248.                     switch (cell.getOccupancy()) {
  249.                         case Symbols.PLAYER0:
  250.                             System.out.print("0 ");
  251.                             break;
  252.                         case Symbols.PLAYER1:
  253.                             System.out.print("1 ");
  254.                             break;
  255.                         case Symbols.PLAYER2:
  256.                             System.out.print("2 ");
  257.                             break;
  258.                         case Symbols.PLAYER3:
  259.                             System.out.print("3 ");
  260.                             break;
  261.                         case Symbols.PLAYER4:
  262.                             System.out.print("4 ");
  263.                             break;
  264.                         case Symbols.UNOCCUPIED:
  265.                             System.out.print(". ");
  266.                             break;
  267.                         case Symbols.INVISIBLE:
  268.                             System.out.print("I ");
  269.                             break;
  270.                         case Symbols.UNMODIFIED:
  271.                             System.out.print("U ");
  272.                             break;
  273.                         default:
  274.                             System.out.print("? ");
  275.                             break;
  276.                     }
  277.                 }
  278.             }
  279.             System.out.println();
  280.         }
  281.     }
  282.  
  283.     /**
  284.      * A static list of cells that can be shuffled quickly to do random
  285.      * board update
  286.      */
  287.     static final int cellList[] = new int[Rules.rows*Rules.cols];
  288.     static {
  289.         for (int i=0; i<Rules.rows*Rules.cols; i++) {
  290.             cellList[i] = i;
  291.         }
  292.     }
  293.  
  294.     /**
  295.      * shuffle the cells in the cellList so that the board updater doesn't
  296.      * introduce artifacts by traversing the cells in some fixed order.
  297.      */
  298.     void shuffle(int list[]) {
  299.         int size = list.length;
  300.         while (size > 0) {
  301.             int index = Math.abs(rand.nextInt()) % size;
  302.             int temp = list[size-1];
  303.             list[size-1] = list[index];
  304.             list[index] = temp;
  305.             size--;
  306.         }
  307.     }
  308.  
  309.     /**
  310.      * update the board to reflect the passage of one unit of xbattle time.
  311.      */
  312.     public void update() {
  313.         for (int i = 0; i < numPlayers; i++)
  314.             troops[i] = 0;
  315.  
  316.         long time = System.currentTimeMillis();
  317.         shuffle(cellList);
  318.         time = howMuchTime(time, "shuffling list");
  319.         clearModified();
  320.         time = howMuchTime(time, "clearmodify");
  321.         for (int i = 0; i < cellList.length; i++) {
  322.             int r = Common.indexToRow(cellList[i]); 
  323.             int c = Common.indexToCol(cellList[i]);
  324.             updateCell(r, c);
  325.             ServerCell cell = (ServerCell)getCell(r,c);
  326.             int occ = cell.getOccupancy();
  327.             if (occ != Symbols.UNOCCUPIED) {
  328.                 troops[occ] += cell.getTroops();
  329.             }
  330.         }
  331.  
  332.         for (int i = 0; i < numPlayers; i++) {
  333.             if (troops[i] == 0 && alive[i] == true) {
  334.                 killPlayer(i);
  335.             }
  336.         }
  337.  
  338.         time = howMuchTime(time, "work of update");
  339.     }
  340.  
  341.     /**
  342.      * kill the player given as an argument. allows the player to watch the
  343.      * whole game board until the game ends.
  344.      * @param player the player who is killed
  345.      */
  346.     public void killPlayer(int player) {
  347.         if (!alive[player])
  348.             return;
  349.         logfile.log("Player "+player+" died.");
  350.         referee.playerDied(player);
  351.         alive[player] = false;
  352.         for (int r=0; r<Rules.rows; r++) {
  353.             for (int c=0; c<Rules.cols; c++) {
  354.                 ServerCell cell = (ServerCell)getCell(r,c);
  355.                 cell.setVisible(player, true);
  356.             }
  357.         }
  358.     }
  359.  
  360.     /**
  361.      * return true if the game has ended - that is only one player remains
  362.      */
  363.     public boolean isGameOver() {
  364.         int numP = 0;
  365.         int lastP = -1;
  366.         for (int i = 0; i < numPlayers; i++)
  367.             if (alive[i]) {
  368.                 numP++;
  369.                 lastP = i;
  370.             }
  371.  
  372.         if (numP <= 1) {
  373.             if (lastP != -1)
  374.                 killPlayer(lastP);
  375.             return true;
  376.         }
  377.  
  378.         return false;
  379.     }
  380.  
  381.     /** 
  382.      * a vector of directions to update.
  383.      */
  384.     static final Vector updateDir = new Vector();
  385.     static {
  386.         for (int i=0; i<4; i++) {
  387.             updateDir.addElement(new Integer(i));
  388.         }
  389.     }
  390.     /**
  391.      *  update a particular cell on the game board.
  392.      */
  393.     public void updateCell(int row, int col) {
  394.         ServerCell cell = (ServerCell)getCell(row, col);
  395.  
  396.         // terrain must not be water
  397.         if (cell.getTerrain() == 0) return;
  398.  
  399.         // if the cell is a city, then grow some troops
  400.         if (cell.getCity() == Rules.maxCitySize) {
  401.             cell.setTroops( cell.getTroops() + GROW );
  402.  
  403.             // bottleneck troop production, if neccessary
  404.             if (cell.getTroops() > Symbols.MAX_SERVER_TROOPS)
  405.                 cell.setTroops(Symbols.MAX_SERVER_TROOPS);
  406.         }
  407.  
  408.         // airborne attacks are resolved first (incoming paratroops/guns)
  409.         int shells = 0;
  410.         for (int i = 0; i < Symbols.MAX_PLAYERS; i++) {
  411.             shells += cell.getShells(i);
  412.         }
  413.         cell.clearArtillery();
  414.         if (shells > 0) {
  415.             // all incoming shells are treated as one group attack
  416.             double percent = shells / (double)cell.getTroops();
  417.  
  418.             int killed = (int)(percent * cell.getTroops());
  419.  
  420.             if (killed > cell.getTroops()) {
  421.                 int oldPlayer = cell.getOccupancy();
  422.                 cell.setOccupancy(Symbols.UNOCCUPIED);
  423.                 cell.setTroops(0);
  424.                 cell.clearPipes();
  425.                 removeVisibility(row, col, oldPlayer);
  426.             }
  427.             else {
  428.                 cell.setTroops(cell.getTroops() - killed);
  429.             }
  430.         }
  431.         for (int i = 0; i < Symbols.MAX_PLAYERS; i++) {
  432.             int troops = cell.getParatroops(i);
  433.             if (troops <= 0)
  434.                 continue;
  435.  
  436.             if (i == cell.getOccupancy()) {
  437.                 troops = (int)(0.9 * troops);
  438.                 if (troops + cell.getTroops() > Symbols.MAX_SERVER_TROOPS)
  439.                     troops = Symbols.MAX_SERVER_TROOPS - cell.getTroops();
  440.                 cell.setTroops(cell.getTroops() + troops);
  441.             }
  442.             else if (cell.getOccupancy() == Symbols.UNOCCUPIED) {
  443.                 cell.setOccupancy(i);
  444.                 cell.setTroops(troops);
  445.                 addVisibility(row, col, cell.getOccupancy());
  446.             }
  447.             else {
  448.                 // cell is owned by an enemy player
  449.                 // hope we confuse his pipes
  450.                 double percent = troops / (double)cell.getTroops();
  451.  
  452.                 double roll = rand.nextGaussian() + 0.3;
  453.  
  454.                 if (roll < percent)
  455.                     cell.clearPipes();
  456.  
  457.                 troops = (int)(0.5 * troops);
  458.  
  459.                 percent = troops / (double)cell.getTroops();
  460.                 int killed = (int)(percent * cell.getTroops()) + 1;
  461.                 if (killed > cell.getTroops()) {
  462.                     int oldPlayer = cell.getOccupancy();
  463.                     cell.setOccupancy(i);
  464.                     cell.setTroops(troops);
  465.                     cell.clearPipes();
  466.                     addVisibility(row, col, i);
  467.                     removeVisibility(row, col, oldPlayer);
  468.                 }
  469.                 else {
  470.                     cell.setTroops(cell.getTroops() - killed);
  471.                 }
  472.             }
  473.         }
  474.         cell.clearParatroops();
  475.  
  476.         // in random order of n, s, e, w -- import troops
  477.         // from neighboring cells
  478.         Vector dir = (Vector)updateDir.clone();
  479.         while (! dir.isEmpty()) {
  480.             int index = Math.abs(rand.nextInt()) % dir.size();
  481.             int d = ((Integer)dir.elementAt(index)).intValue();
  482.             dir.removeElementAt(index);
  483.  
  484.             ServerCell srcCell = null;
  485.             if (d == Symbols.NORTH) {
  486.                 if (row == 0) continue;
  487.                 srcCell = (ServerCell)getCell(row-1, col);
  488.                 if (! srcCell.getPipe(Symbols.SOUTH)) continue;
  489.             } else if (d == Symbols.SOUTH) {
  490.                 if (row == Rules.rows-1) continue;
  491.                 srcCell = (ServerCell)getCell(row+1, col);
  492.                 if (! srcCell.getPipe(Symbols.NORTH)) continue;
  493.             } else if (d == Symbols.WEST) {
  494.                 if (col == 0) continue;
  495.                 srcCell = (ServerCell)getCell(row, col-1);
  496.                 if (! srcCell.getPipe(Symbols.EAST)) continue;
  497.             } else if (d == Symbols.EAST) {
  498.                 if (col == Rules.cols-1) continue;
  499.                 srcCell = (ServerCell)getCell(row, col+1);
  500.                 if (! srcCell.getPipe(Symbols.WEST)) continue;
  501.             }
  502.             if (srcCell != null) {
  503.                 // if we are not currently occupied by the incoming
  504.                 // cell color, then set the occupancy and update the
  505.                 // visibility
  506.                 if (cell.getOccupancy() == Symbols.UNOCCUPIED) {
  507.                     cell.setOccupancy(srcCell.getOccupancy());
  508.                     addVisibility(row, col, cell.getOccupancy());
  509.                 }
  510.  
  511.                 // if the input cell is water (shouldn't be) then abort
  512.                 if (srcCell.getTerrain() == 0) continue;
  513.                 int terrainDiff = srcCell.getTerrain() - cell.getTerrain();
  514.  
  515.                 // the number of troops to transfer
  516.                 int transfer = terrainDiff + 8;
  517.  
  518.                 // make sure our transfer is what the source can give and
  519.                 // the destination can take
  520.                 if (srcCell.getTroops() < transfer)
  521.                     transfer = srcCell.getTroops();
  522.  
  523.                 if (transfer == 0)
  524.                     continue;
  525.  
  526.                 // make the transfer
  527.                 if (cell.getOccupancy() == srcCell.getOccupancy()) {
  528.                     if (transfer + cell.getTroops() > Symbols.MAX_SERVER_TROOPS)
  529.                         transfer = Symbols.MAX_SERVER_TROOPS - cell.getTroops();
  530.  
  531.                     srcCell.setTroops( srcCell.getTroops() - transfer );
  532.                     cell.setTroops( cell.getTroops() + transfer );
  533.                 }
  534.                 else {
  535.                     srcCell.setTroops(srcCell.getTroops() - transfer);
  536.                     // the transferred troops get to join the fighting
  537.                     // troops
  538.                     int attackers = transfer + srcCell.getFighters(d);
  539.  
  540.                     // of the attackers and defenders roughly 
  541.                     //         defenders*attackers / (attackers+defenders) die
  542.                     int total = cell.getTroops() + attackers;
  543.  
  544.                     double randomFactor = rand.nextGaussian();
  545.  
  546.                     int killed = cell.getTroops() * attackers / total + 1;
  547.                     int randKill = (int)(randomFactor * killed);
  548.  
  549.                     int defendersKilled;
  550.                     int attackersKilled;
  551.                     if (randKill < 0) {
  552.                         defendersKilled = killed - randKill;
  553.                         attackersKilled = killed;
  554.                     }
  555.                     else {
  556.                         defendersKilled = killed;
  557.                         attackersKilled = killed + randKill;
  558.                     }
  559.                         
  560.  
  561.                     if (cell.getTroops() <= defendersKilled || 
  562.                         cell.getTroops() <= 0) {
  563.                         int oldPlayer = cell.getOccupancy();
  564.                         cell.setOccupancy(srcCell.getOccupancy());
  565.                         addVisibility(row, col, cell.getOccupancy());
  566.                         removeVisibility(row, col, oldPlayer);
  567.                         cell.clearPipes();
  568.                         int newtroops = attackers - attackersKilled;
  569.                         if (newtroops > 0)
  570.                             cell.setTroops(newtroops);
  571.                         else
  572.                             cell.setTroops(1);
  573.                     }
  574.                     else {
  575.                         cell.setTroops(cell.getTroops() - defendersKilled);
  576.                         srcCell.setFighters(d, attackers - attackersKilled);
  577.                     }
  578.                 }
  579.             }
  580.         }
  581.     }
  582.  
  583.     /**
  584.      * record how much time some action has taken. used to help make sure
  585.      * that the server can consistently meet the time goal of X ms per turn.
  586.      */
  587.     public long howMuchTime(long oldtime, String msg) {
  588.         long time = System.currentTimeMillis();
  589.         // uncomment for more time info
  590.         //logfile.log(msg + ": " + (time - oldtime));
  591.         return time;
  592.     }
  593. }
  594.