Spielprogrammierung mit Java
HomeAufgabenDruckenJava-Online

2 Personen Nim-Spiel mit Bluetooth Kommunikation


Zu Beginn des Spiels bauen die beiden Spieler eine Bluetooth-Verbindung auf (siehe vorhergehendes Beispiel). Der Bluetooth-Client startet das Spiel.
 

Der spielberechtigte Spieler nimmt mit Mausklick 1, 2, oder 3 Zündhölzer weg. Dabei wird via Bluetooth jeweils ein Integer (x-Koordinate des entfernten Zündholzes) zum anderen Computer gesendet und das entprechende Zündholz auch aus seiner Ansicht entfernt. Mit Klick auf OK wird der Zug beendet und als Information der Integer -1 gesendet. Der Spieler wird in einen wartenden Zustand versetzt, während der andere Spieler spielberechtigt ist. Wer das letzte Hölzchen entfernt, hat verloren. Dabei wird zur Information der Integer -2 verschickt, was die Anzeige You Win beim anderen Spieler bewirkt. Gleichzeitug ändert der Button Ok auf New Game. Beim Klicken wird das Spiel neu initialisiert. Dabei übermittelt der Gewinner mit dem Integer -3, dass er bereit ist, neu zu spielen.

Die einfache Variante dieses Spiels (Spieler gegen Computer) findet man unter Gitter-Games-NimSpiel.

Programmcode:

// BtNim.java

import ch.aplu.jgamegrid.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import ch.aplu.bluetooth.*;
import javax.swing.JOptionPane;

public class BtNim extends GameGrid
  implements GGMouseListener, GGButtonListener, BtPeerListener, GGExitListener
{
  private int nbMatches;
  private int nbTakenMatches;
  private GGBackground bg;
  private GGButton okBtn = new GGButton("sprites/ok.gif"true);
  private GGButton newBtn = new GGButton("sprites/new.gif"true);
  private BluetoothPeer bp;
  private boolean isMyMove;
  private boolean isWinner = false;

  public BtNim()
  {
    super(56912false);
    bg = getBg();
    addActor(okBtn, new Location(504));
    okBtn.addButtonListener(this);
    addActor(newBtn, new Location(504));
    newBtn.addButtonListener(this);
    addMouseListener(this, GGMouse.lPress);
    init();
    show();
    connect();
    addExitListener(this);
  }

  private void init()
  {
    nbMatches = 15;
    nbTakenMatches = 0;
    bg.clear();
    for (int i = 0; i < nbMatches; i++)
      addActor(new Match()new Location(2 + 3 * i, 4));
    okBtn.show();
    newBtn.hide();
    if (isMyMove)
      setTitle(nbMatches + " matches. Click on 1, 2 or 3 matches to remove, then click 'OK'. It is your to play");
    else
      setTitle("Click on 1, 2 or 3 matches to remove, then click 'OK'. Wait to play");
    refresh();
  }

  public boolean mouseEvent(GGMouse mouse)
  {
    if (!isMyMove)
      return true;
    Location loc = toLocationInGrid(mouse.getX(), mouse.getY());
    Actor actor = null;
    for (int y = 2; y < 7; y++)
    {
      actor = getOneActorAt(new Location(loc.x, y), Match.class);
      if (actor != null)
        break;
    }
    if (actor != null)
    {
      if (nbTakenMatches == 3)
        setTitle("Take a maximum of 3. Click 'OK' to continue");
      else
      {
        actor.removeSelf();
        int[] data = new int[1];
        data[0] = actor.getLocation().x;
        bp.sendDataBlock(data);
        nbMatches--;
        setTitle(nbMatches + " matches remaining. Click 'OK' to continue");
        nbTakenMatches++;
        if (nbMatches == 0)
        {
          setTitle("You lost. Press 'New Game' to play again.");
          bg.setPaintColor(Color.red);
          bg.setFont(new Font("Arial"Font.BOLD, 90));
          bg.drawText("you lost!"new Point(toPoint(new Location(36))));
          isMyMove = false;
          isWinner = false;
          data = new int[1];
          data[0] = -2;
          bp.sendDataBlock(data);
          okBtn.hide();
          newBtn.show();
        }
        refresh();
      }
    }
    return false;
  }

  public void buttonClicked(GGButton button)
  {
    if (nbMatches == 0)
    {
      init();
      if (isWinner)
      {
        int[] data = {-3};
        bp.sendDataBlock(data);
      }

    }
    else
    {
      if (nbTakenMatches == 0)
        setTitle("You have to remove at least 1 match");
      else
      {
        isMyMove = false;
        int[] data = new int[1];
        data[0] = -1;
        bp.sendDataBlock(data);
        setTitle(nbMatches + " matches remaining. Wait to play");
      }
    }
  }

  public void buttonPressed(GGButton button)
  {
  }

  public void buttonReleased(GGButton button)
  {
  }

  private void connect()
  {
    String serverName;
    String prompt = "Enter Bluetooth Name";
    serverName = JOptionPane.showInputDialog(null, prompt, "");
    if (serverName == null)
      System.exit(0);
    serverName = serverName.trim();
    if (serverName.equals(""))
    {
      setTitle("Waiting as Server. Bluetooth Name: " + BluetoothFinder.getLocalBluetoothName());
      bp = new BluetoothPeer(serverName, "nim"thistrue);
    }
    else
    {
      setTitle("Connecting to " + serverName);
      bp = new BluetoothPeer(serverName, "nim"thistrue);
      if (bp.isConnected())
      {
        setTitle("Client connected, it is you to play");
        isMyMove = true// Client plays first
      }
      else
        setTitle("Waiting as server. Bluetooth Name: " + BluetoothFinder.getLocalBluetoothName());
    }
  }

  public void notifyConnection(boolean connected)
  {
    System.out.println("Notify " + (connected ? "connected" : "connection lost"));
    if (connected)
    {
      setTitle("Server connected, wait to play");
      isMyMove = false;
    }
  }

  public void receiveDataBlock(int[] data)
  {
    int x = data[0];
    switch (x)
    {
      case -1:
        isMyMove = true;
        setTitle(nbMatches + " matches. It is your to play");
        nbTakenMatches = 0;
        break;
      case -2:
        bg.setPaintColor(Color.red);
        bg.setFont(new Font("Arial"Font.BOLD, 90));
        bg.drawText("You won!"new Point(toPoint(new Location(36))));
        okBtn.hide();
        newBtn.show();
        setTitle("You won. Press 'New Game' to play again");
        isMyMove = false;
        isWinner = true;
        refresh();
        break;
      case -3:
        isMyMove = true;
        setTitle("Take a maximum of 3. Click 'Ok' to continue");
        break;
      default:
        Location loc = new Location(x, 4);
        getOneActorAt(loc).removeSelf();
        nbMatches--;
        setTitle(nbMatches + " matches. Wait to play");
        refresh();
        break;
    }
  }

  public boolean notifyExit()
  {
    bp.releaseConnection();
    return true;
  }

  public static void main(String[] args)
  {
    new BtNim();
  }
}

// -------------class Match--------------------------
class Match extends Actor
{
  public Match()
  {
    super("sprites/match.gif");
  }
}

Erklärungen zum Programmcode:
connect()
sendDataBlock(data)
receiveDataBlock(int[] data)
Der Aufbau der Bluetooth-Verbindung, Senden und Empfangen der Daten wird im Beispiel BtCom.java erklärt
for (int y = 2; y < 7; y++)
{   actor = getOneActorAt(new Location(loc.x, y), Match.class);  
}
Bei der Erfassung des Mausklicks werden mehrere vertikal übereinander liegende Felder mit der gleichen x-Koordinate überprüfen, damit man irgendwo auf das Zündholz klicken kann
implements GGButtonListener
Implementiert einen GGButtonListener mit dem Callbackmethoden buttonClicked(), buttonPressed() und buttonReleased()
GGButton okBtn = new GGButton("sprites/ok.gif", true);
okBtn.addButtonListener(this);
Erzeugt einen Ok-Button und registriert den GGButtonListener. Der Parameter true ermöglicht drei verschiedene Ansichten des Button (normal, click, rollover). Die entsprechenden Sprite-Bilder ok_0.gif, ok_1.git, ok_2.gif müssen sich im Ordner sprites befinden
okBtn.hide()
newBtn.show()
Die beiden Buttons okBtn und newBtn haben die gleiche Grösse und die gleiche Position. Zu Beginn des Spieles ist der okBtn sichtbar und dient zum Abschliessen eines Zuges und zur Übergabe der Spielberechtigung an den zweiten Spieler. Wenn das Spiel beendet ist (nbMaches = 0), wird der okBtn versteckt und an seiner Stelle der newBtn angezeigt, mit dem ein neues Spiel gestartet werden kann.