Spielprogrammierung mit Java
HomeAufgabenDruckenJava-Online

Pearl-Game gegen Computer


Pearl Game ist eine Erweiterung des Nimspiels. Die Gewinnstrategie lässt sich aber nicht mehr so einfach ermitteln. Zu Beginn sind 18 Perlen in 4 Reihen angeordnet. Der erste Spieler entfernt mit Mausklick eine beliebige Anzahl Perlen allerdings nur aus der gleichen Reihe und drückt "Ok". Danach kommt der zweite Spieler zum Zug. Wer die letzte Perle entfernen muss, hat verloren.

In dieser Applikation ist das Pearl-Game gegen computer programmiert.

 

 

Programmcode downloaden: PearlGameVsComputer.zip

Programmcode:

// PearlGameVsComputer.java

import ch.aplu.jgamegrid.*;
import java.awt.*;
import java.util.*;
import java.util.List;

public class PearlGameVsComputer extends GameGrid implements GGMouseListener,
  GGButtonListener
{
  private int nbPearl = 0;
  private int nbTakenPearl;
  private int nbRows = 4;
  private int activeRow;
  private GGBackground bg;
  private GGButton okBtn = new GGButton("sprites/ok.gif"true);
  private GGButton newBtn = new GGButton("sprites/new.gif"true);
  private ComputerPlayer cp;
  private final boolean misereMode = true;

  public PearlGameVsComputer()
  {
    super(8, 6, 60, false);
    setBgColor(new Color(80, 15, 247));
    bg = getBg();
    addMouseListener(thisGGMouse.lPress);
    addActor(okBtn, new Location(6, 4));
    okBtn.addButtonListener(this);
    addActor(newBtn, new Location(6, 4));
    newBtn.addButtonListener(this);
    cp = new ComputerPlayer(thismisereMode);
    init();
    show();
  }

  public void init()
  {
    int nb = 6;
    cp.reset();
    bg.clear();
    for (int = 0; k < nbRows; k++)
    {
      for (int = 0; i < nb; i++)
      {
        Pearl pearl = new Pearl();
        addActor(pearl, new Location(+ i, 1 + k));
        cp.updatePearlArrangement(k + 1, +1);
        nbPearl++;
      }
      nb--;
    }
    prepareNextHumanMove(); // human starts
    okBtn.show();
    newBtn.hide();
    refresh();
    setTitle(nbPearl
      + " Pearls. Remove any number of pearls from same row and press OK.");
  }

  public boolean mouseEvent(GGMouse mouse)
  {
    Location loc = toLocationInGrid(mouse.getX(), mouse.getY());
    Actor pearlAtClick = getOneActorAt(new Location(loc), Pearl.class);
    if (pearlAtClick != null)
    {
      int = pearlAtClick.getY();

      if (activeRow != && activeRow != y)
        setTitle("You must remove pearls from the same row.");
      else
      {
        activeRow = y;
        pearlAtClick.removeSelf();
        nbPearl--;
        setTitle(nbPearl + " Pearls remaining. Click 'OK' to continue.");
        nbTakenPearl++;
        cp.updatePearlArrangement(y, -1);
        if (nbPearl == 0)
        {
          if (misereMode)
            gameOver("You lost!");
          else
            gameOver("You won!");
        }
        refresh();
      }
    }
    return true;
  }

  public void gameOver(String msg)
  {
    setTitle("Press 'new Game' to play again.");
    bg.setPaintColor(Color.red);
    bg.setFont(new Font("Arial"Font.BOLD, 32));
    bg.drawText(msg, new Point(toPoint(new Location(2, 5))));
    okBtn.hide();
    newBtn.show();
    refresh();
  }

  public void buttonClicked(GGButton button)
  {
    if (nbPearl == 0)
      init();
    else
    {
      if (nbTakenPearl == 0)
        setTitle("You have to remove at least 1 Pearl!");
      else
      {
        cp.makeMove();
        refresh();
        nbPearl = getNumberOfActors(Pearl.class);
        if (nbPearl == 0)
        {
          if (misereMode)
            gameOver("You win!");
          else
            gameOver("You lose!");
        }
        else
          prepareNextHumanMove();
      }
    }
  }

  private void prepareNextHumanMove()
  {
    nbTakenPearl = 0;
    setTitle(nbPearl + " pearls remaining. Your move now.");
    activeRow = 0; // Spieler darf neue "Ziehreihe" bestimmen
  }

  public void buttonPressed(GGButton button)
  {
  }

  public void buttonReleased(GGButton button)
  {
  }

  public void reset()
  {
  }

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

//
class Pearl extends Actor
{

  public Pearl()
  {
    super("sprites/pearl.gif");
  }
}

//
class ComputerPlayer
{
  protected int[] pearlArrangement;
  private final int dualMax = 4;
  private int vertCells;
  protected GameGrid gg;
  protected boolean misere;
  private boolean changeStrat;

  public ComputerPlayer(GameGrid pearlGG, boolean misere)
  {
    this.gg = pearlGG;
    this.vertCells = gg.getNbVertCells();
    this.misere = misere;
  }

  public void updatePearlArrangement(int row, int amount)
  {
    pearlArrangement[row] += amount;
  }

  public void makeMove()
  {
    int nbToRemoveMatches = 0;
    int[] tgPearls = new int[vertCells];

    int removeRow = shouldIChangeStrat();
    if (removeRow != -1)
    {
      System.arraycopy(pearlArrangement, 0, tgPearls, 0, vertCells);
      tgPearls[removeRow] = 0;
      if (isUSituation(tgPearls))
        nbToRemoveMatches = pearlArrangement[removeRow];
      else
        nbToRemoveMatches = pearlArrangement[removeRow] - 1;
    }
    // if optimal Strategy is not possible, do something random.
    else if (!isUSituation(pearlArrangement))
    {
      ArrayList<Actor> pearls = gg.getActors(Pearl.class);
      System.out.println("Doing something random");
      // from a random (not empty!) row
      Collections.shuffle(pearls);
      removeRow = pearls.get(0).getY();
      // take a random amount (at least 1)
      nbToRemoveMatches = (int)((pearlArrangement[removeRow] - 1) * Math.random() + 1);
    }
    else
    {
      // list for saving all possible solutions
      List<int[]> solutions = new ArrayList<int[]>();
      // Try all possible situations and add them to "solutions if they're
      // good.
      for (int = 0; y < vertCells; y++)
      {
        System.arraycopy(pearlArrangement, 0, tgPearls, 0, vertCells);
        for (int = 0; i < pearlArrangement[y]; i++)
        {
          tgPearls = makeSituation(tgPearls, y);
          if (isUSituation(tgPearls) == false)
          {
            solutions.add((new int[]
              {
                y, i + 1
              }));
          }
        }
      }
      // choose a random solution
      Collections.shuffle(solutions);
      removeRow = solutions.get(0)[0];
      nbToRemoveMatches = solutions.get(0)[1];
      System.out.println("Number of solutions: " + solutions.size());
    }
    removePearls(removeRow, nbToRemoveMatches);
  }

  private int shouldIChangeStrat()
  {
    if (changeStrat || !misere)
      return -1;
    boolean oneHeapBiggerTwo = false;
    int bigHeap = -1;
    for (int heap = 0; heap < vertCells; heap++)
    {
      if (pearlArrangement[heap] > 1)
      {
        bigHeap = heap;
        if (oneHeapBiggerTwo)
          return -1;
        oneHeapBiggerTwo = true;
      }
    }
    System.out.println("changing strategy for misere!");
    changeStrat = true;
    return bigHeap;
  }

  private void miserify(int[] sit)
  {
    if (!misere)
      return;
    else
    {
      for (int heap : sit)
      {
        if (heap > 1)
          return;
      }
      changeStrat = true;
    }
  }

  private void removePearls(int removeRow, int nbToRemoveMatches)
  {
    updatePearlArrangement(removeRow, -nbToRemoveMatches);

    List<Actor> removeCandidates = new ArrayList<Actor>();

    for (Actor p : gg.getActors(Pearl.class))
    {
      if (p.getY() == removeRow)
        removeCandidates.add(p);
    }
    Collections.shuffle(removeCandidates);
    while (nbToRemoveMatches > 0)
    {
      Actor removedPearl = removeCandidates.remove(0);
      removedPearl.removeSelf();
      nbToRemoveMatches--;
    }
  }

  // for debugging only
  private String toString(int[] k)
  {
    String output = "";
    for (int = 0; i < k.length; i++)
      output = (output + k[i] + ", ");
    return output;
  }

  /*
 
 
 
  private int[] makeSituation(int[] sit, int row)
  {
    sit[row] = sit[row] - 1;
    return sit;
  }

  // Check if its a U-Situation
  private Boolean isUSituation(int[] sit)
  {
    int[] allDuals = new int[dualMax];
    int[] oneDual = new int[dualMax];
    for (int = 0; y < vertCells; y++)
    {
      oneDual = toDual(sit[y]);
      for (int = 0; i < allDuals.length; i++)
      {
        allDuals[i] = allDuals[i] + oneDual[i];
      }
    }
    for (int = 0; i < allDuals.length; i++)
    {
      if (allDuals[i] % == 1)
        return true;
    }
    return false;
  }

  /**
 
 
 
  private int[] toDual(int input)
  {
    int[] output = new int[dualMax]; // 4 dualstellen
    int = 0;
    while (input != 0)
    {
      output[x] = input % 2;
      input = input / 2;
      x++;
    }
    return output;
  }

  public void reset()
  {
    pearlArrangement = new int[vertCells];
    changeStrat = false;
  }
}