GameGrid: Game programming with Java

Research project PHBern  
HomePrintJava-Online

Solitaire board game


Solitaire (aka Jumper) is a single player board game. It is played with 32 stones on 33 cells forming a cross. To win the game all stones except one need to be removed by jumping with one stone over an other. The stones are moved by clicking and dragging them horizontally or vertically (but not diagonally) over one stone into a free cell.

allowed not allowed


Run this example

Edit this example in the Online-Editor (BoardSolitaire.java)

Download the program code (BoardSolitaire.zip)

 

Program code:

// BoardSolitaire.java

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

public class BoardSolitaire extends GameGrid implements GGMouseTouchListener
{
  final int DOWN = 0;
  final int UP = 1;
  Actor draggedMarble;
  private ArrayList<Location> boardPatternLocations = new ArrayList<Location>();
  private Location initialMarbleLocation;

  public BoardSolitaire()
  {
    super(7, 7, 70, null"sprites/solitaire.png"false);
    setBgColor(255, 166, 0);
    setTitle("Solitaire");
    loadMarbleLocations();
    loadMarbles();
    show();
    setSimulationPeriod(20);
    doRun();
  }

  public void act()
  {
    refresh();
  }

  public void mouseTouched(Actor touchedMarble, GGMouse mouse, Point spot)
  {
    Location mouseLoc = toLocation(mouse.getX(), mouse.getY());
    Point mousePoint = new Point(mouse.getX(), mouse.getY());
    switch (mouse.getEvent())
    {
      case GGMouse.lPress:
        //define draggedMarble:
        if (draggedMarble == null)
        {
          draggedMarble = touchedMarble;
          initialMarbleLocation = touchedMarble.getLocation();
          draggedMarble.show(UP);
          draggedMarble.setOnTop();
        }
        else
        {
          draggedMarble.show(DOWN);
          draggedMarble.setLocationOffset(new Point(0, 0));
          draggedMarble.setLocation(initialMarbleLocation);
          draggedMarble = null;
        }
        break;
      case GGMouse.lDrag:
        if (draggedMarble != null)
          draggedMarble.setPixelLocation(mousePoint);
        break;

      case GGMouse.lRelease:
        if (draggedMarble != null)
        {
          draggedMarble.setLocationOffset(new Point(0, 0));
          if (isValidJumpLocation(mouseLoc, initialMarbleLocation, true)
            && jumpedMarbleExists(mouseLoc, initialMarbleLocation))
          {
            draggedMarble.setLocation(mouseLoc);
            Actor jumpedMarble = getJumpedMarble(mouseLoc, initialMarbleLocation);
            removeActor(jumpedMarble);
          }
          else
          {
            draggedMarble.setLocation(initialMarbleLocation);
          }
          draggedMarble.show(DOWN);
          draggedMarble = null;
          isGameOver();
        }
        break;
    }
  }

  private boolean jumpedMarbleExists(Location loc, Location initialLoc)
  {
    return getJumpedMarble(loc, initialLoc) != null;
  }

  private Actor getJumpedMarble(Location loc, Location initialLoc)
  {
    Double jumpDirection = loc.getDirectionTo(initialLoc);
    Location overJumpedLoc = loc.getNeighbourLocation(jumpDirection);
    return getOneActorAt(overJumpedLoc, Marble.class);
  }

  private void loadMarbleLocations()
  {
    for (int y = 0; y < 7; y++)
    {
      if (y < || y > 4)
      {
        for (int x = 2; x < 5; x++)
          boardPatternLocations.add(new Location(x, y));
      }
      else
      {
        for (int x = 0; x < 7; x++)
          boardPatternLocations.add(new Location(x, y));
      }
    }
  }

  // Initializes marbles on the board
  private void loadMarbles()
  {
    for (Location loc : boardPatternLocations)
    {
      Marble marble = new Marble(DOWN);
      marble.addMouseTouchListener(this, GGMouse.lPress | GGMouse.lDrag | GGMouse.lRelease);
      addActorNoRefresh(marble, loc);
    }
    this.removeActorsAt(new Location(3, 3)); //make hole in middle
  }

  // check if location is a valid jump location
  private boolean isValidJumpLocation(Location loc, Location previousLoc, boolean isDragged)
  {
    int expectedMarbleNr;
    if (isDragged)
      expectedMarbleNr = 1;
    else
      expectedMarbleNr = 0;
    ArrayList<Location> validJumpLocs = new ArrayList<Location>();
    for (int possibleDir = 0; possibleDir < 360; possibleDir += 90)
      validJumpLocs.add(previousLoc.getAdjacentLocation(possibleDir, 2));
    return (boardPatternLocations.contains(loc) && validJumpLocs.contains(loc)
      && getActorsAt(loc, Marble.class).size() == expectedMarbleNr);
  }

  private void isGameOver()
  {
    ArrayList<Actor> leftMarbles = getActors(Marble.class);
    // One left => you win
    if (leftMarbles.size() == 1)
    {
      addActor(new Actor("sprites/you_win.gif")new Location(3, 3));
      restart();
    }
    else
    {
      //check if there are any valid moves left
      for (Actor a : leftMarbles)
      {
        if (hasOrthagonalJumpableNeighbours(a))
          return;
      }
      //no more valid jumps possible => you lose!
      addActor(new Actor("sprites/gameover.gif")new Location(3, 3));
      restart();
    }
  }

  private boolean hasOrthagonalJumpableNeighbours(Actor a)
  {
    Location marbleLoc = a.getLocation();
    for (Location loc : marbleLoc.getNeighbourLocations(0.5))
    {
      double locDir = marbleLoc.getDirectionTo(loc);
      Location jumpLoc = loc.getNeighbourLocation(locDir);
      if (getActorsAt(loc, Marble.class).size() != 0
        && isValidJumpLocation(jumpLoc, marbleLoc, false))
        return true;
    }
    return false;
  }

  // restart game
  private void restart()
  {
    delay(5000);
    removeAllActors();
    loadMarbles();
  }

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

// -----------           class Marble    ------------------------
class Marble extends Actor
{

  public Marble(int imgID)
  {
    super("sprites/marble.png"2);
    show(imgID);
  }
}



Solitaire board game: simple variation

In this example, the stones do not have to be dragged. To move them, simply click the desired stone and then click the free cell it has to jump to. The program code of this variation is much easier to understand.

Run this example

Edit this example in the Online-Editor (BoardSolitaire2.java)

Download the program code (BoardSolitaire2.zip)