APP Game Client-Server Application

Joe

Thành viên VIP
21/1/13
3,024
1,336
113
Hi

I have talked about Working in a Multiple Threading Environment with ExecutorService pool. Today I show you how to work with threads in a Client-Server Environment. To make it easy this blog shows you how a Client/Server-GAME is developed with threads, ExecutorService Pool with synchronized-Keyword.

Game description:

SERVER

The Server (main app: MarineBase.java) starts somewhere on the net (LAN/WAN/WEB) and waits for Players. Each logged-in player gets a counterpart which is identical in content of the Client or Player (i.e. layout, number of ships but in random positions). Dependent on the rank the BattleField is an array of n x n fields and occupied by x ships. The following ranks can be entitled to the users:
Code:
+-------------------+-------------+------------------------------+--------+
| Rank              | BattleField | Number of available Missiles | Ships  |
+-------------------+-------------+------------------------------+--------+
| Recruit           |     5x5     |    22 = (5 x 5) - (5-2)      |   3    |
+-------------------+-------------+------------------------------+--------+
| Sergeant          |     6x6     |    32 = (6 x 6) - (6-2)      |   4    |
+-------------------+-------------+------------------------------+--------+
| Lieutenant        |     7x7     |    44 = (7 x 7) - (7-2)      |   5    |
+-------------------+-------------+------------------------------+--------+
| Captain           |     8x8     |    58 = (8 x 8) - (8-2)      |   6    |
+-------------------+-------------+------------------------------+--------+
| Colonel           |     9x9     |    74 = (9 x 9) - (9-2)      |   7    |
+-------------------+-------------+------------------------------+--------+
| General           |    10x10    |  92 = (10 x 10) - (10-2)     |   8    |
+-------------------+-------------+------------------------------+--------+
| ChiefOfStaff      |    11x11    | 112 = (11 x 11) - (11-2)     |   9    |
+-------------------+-------------+------------------------------+--------+
  • After 10 battles the player wins more than loses the player will be promoted to the next higher rank (final: ChiefOfStaff). Otherwise (more loses than wins in consecutive 10 battles) the player will be demoted to one rank lower (final: recruit).
  • If the player is absent absent consecutively 100 days the player will be demoted 1 rang
The admin can ban a player using his log-in name. A banned player cannot register under any other name because his name is bound to his Computer Serial Number (the player can only "evade" if (s)he switches his/her computer).

The Server package (complete):
  • BattleField.java
  • Location.java
  • MarineBase.java (the main app)
  • NotifyingThread.java
  • PopUpMessage.java
  • SeaBattle.java
  • Shutdown.java
  • ThreadCompleteListener.java
  • Warship.java
  • missed.jpg (image)
  • ship.jpg (image)
  • sinking.jpg (image)
  • build.bat (the batch file to build all java classes)
  • buildServer.bat (the batch file to build Server.jar)
  • Server.jar (executable JAR file)
  • header.txt (the header file)
  • userlist.txt (the list of registered users)
  • banlist.txt (the list of banned users)

PLAYER or CLIENT

It is simple that the Player needs to download the package Player.jar and then register his playing name. If the player is NEW (s)he can play directly after registration. Later on the player needs only to login when (s)he wants to play again. As mentioned above, the player always sends his Computer Serial Number as his PASSWORD (done internally). Meaning: only ONE player per Computer. The package is designed to run on WINDOWS and LINUX (i.e. UBUNTU)

The Client package:
  • Seawar.java (the main app)
  • Location.java (see Server Package)
  • Blinking.java
  • ThreadCompleteListener.java (see Server package)
  • PopUpMessage.java (see Server package)
  • Warship.java (see Server package)
  • missed.jpg (image)
  • ship.jpg (image)
  • sinking.jpg (image)
  • buildPlayer.bat (the batch file to build Player.jar)
  • Player.jar (executable JAR file)

The following screenshots show you how the Client/Server Game works: The default Server port is 9999 and can be changed anytime. Example: port 8888 and the hostname (on the net) is GameHost.
Code:
// on a console
javaw -jar Server.jar 8888
On the Client site (console).
Code:
javaw -jar Player.jar GameHost 8888
Functional Architecture
Seawar_4.png

Starting on 2 different computers (or 2 consoles if you don't have 2 computers)
seawar.png

After LOGIN
Seawar_0.png

You start to play by clicking on any tile where you assume that there is a ship on the Server site (the same the Server proxy does)
seawar_1.png

...the game elapses till you sink all ships on the Server site (you win) OR the Server Proxy shot down all your ships (you lose)
seawar_2.png

and so on...
seawar_3.png

incl. seawar.zip
 

Attachments

Sửa lần cuối:

Joe

Thành viên VIP
21/1/13
3,024
1,336
113
In this Client-Server Application I have implemented the volatile variable (see mod in Seawar.java and box[] in MarineBase.java) for the threads. What is VOLATILE? The term volatile means choppy, erratic or capricious.

In JAVA it means the value (or content) cannot be cached locally. The the true value must be accessed directly from the memory. This way warrants the realtime of process because any change OUTSIDE the threads (or pool) will effect immediately INSIDE the threads.

Seawar.java
Java:
public class Seawar extends JFrame implements ThreadCompleteListener, ActionListener {
  private Socket soc;
  ...
  private volatile int mob = 0;
  ...
  public Seawar(String[] a) throws Exception {
    ...
    moveBox = new JComboBox<String>("Mooring Ships!Moving Ships".split("!"));
    moveBox.addActionListener(e -> {
      mob = moveBox.getSelectedIndex();  // change mode: mooring or moving
    });
    ...
  }
  ...
  private void gotoWar(ActionEvent ae) {
    ...
    if (wait > 0 && MAX > 0) try {
      ...
      // Mooring or Moving ships ?
      if (mob > 0) {
        for (int i = 0; i < row; ++i)
          for (int l = 0; l < col; ++l)
            if (ship[i][l].afloat()) {
              ship[i][l].reset();
              while (true) {
                x = r.nextInt(row);
                y = r.nextInt(col);
                if (ship[x][y].isEmpty()) {
                  ship[x][y].set( );
                  break;
                }
              }
        }
      }
      ...
    }
  }
  ...
}
MarineBase.java
Java:
public class MarineBase extends JFrame {
  ...
  private volatile int[] box = { 0, 0 };
  ...
  public MarineBase(String p) {
    ...
    showBox = new JComboBox<String>("Show Battlefield!Hide Battlefield".split("!"));
    showBox.addActionListener(e -> {
      box[0] = showBox.getSelectedIndex();  // hide or show BattleField
    });
    showBox.setFocusable(false);
    showBox.setForeground(Color.blue);

    moveBox = new JComboBox<String>("Mooring Ships!Moving Ships".split("!"));
    moveBox.addActionListener(e -> {
      box[1] = moveBox.getSelectedIndex(); // Mooring or Moving ships
    });
    ...
  }
  ...
}
and BattleField.java
Java:
  ...
  private class OnMissile extends NotifyingThread {
    ...
    public void go() {
      ...
      // moving ships ?
      if (box[1] > 0x00) {
        for (int i = 0; i < row; ++i)
        for (int l = 0; l < col; ++l)
        if (ship[i][l].afloat()) {
          ship[i][l].reset();
          while (true) {
            x = r.nextInt(row);
            y = r.nextInt(col);
            if (ship[x][y].isEmpty()) {
              ship[x][y].set( );
              break;
            }
          }
        }
      }
      ...
    }
  }
  ...
}
Some developers are NOT aware about this useful feature of "volatile" declaration. Due to eager optimization Java Virtual Machine (JVM) tends to cache locally everything, especially with threads. The consequence is that any change outside threads (or pool) could be recognized TOO LATE and could cause some unpredictable results (e.g. loop won't stop, etc.)
 
Sửa lần cuối: