This game can be found in four different versions on this webpage:
|
![]() |
Download the program code (FourInARow1.zip)
Program code of version 1:
// FourInARow1.java import ch.aplu.jgamegrid.*; import java.awt.*; public class FourInARow1 extends GameGrid implements GGMouseListener { private int currentPlayer = 0; public boolean finished = false; Token activeToken; public FourInARow1() { super(7, 7, 70, null, null, false); addMouseListener(this, GGMouse.lPress | GGMouse.move); this.getBg().setBgColor(Color.white); activeToken = new Token(currentPlayer, this); addActor(activeToken, new Location(0, 0), Location.SOUTH); addActor(new BG(), new Location(3, -1)); //outside of grid, so it doesn't disturb game getBg().setFont(new Font("SansSerif", Font.BOLD, 48)); getBg().setPaintColor(Color.red); show(); setSimulationPeriod(30); doRun(); addStatusBar(30); setStatusText("Move mouse to a column and click to set the token."); setTitle("Four In A Row (for two local players)"); } public void reset() { getBg().clear(); removeActors(Token.class); //remove all tokens setStatusText("Game reset! " + (currentPlayer == 0 ? "Yellow" : "Red") + " player begins."); activeToken = new Token(currentPlayer, this); addActor(activeToken, new Location(0, 0), Location.SOUTH); finished = false; } public boolean mouseEvent(GGMouse mouse) { Location mouseLoc = toLocation(mouse.getX(), mouse.getY()); if (mouse.getEvent() == GGMouse.move) { //move active Token with mouse if (!finished && activeToken.getX() != mouseLoc.x) activeToken.setX(mouseLoc.x); return true; } if (finished) { reset(); return true; } if (getOneActorAt(new Location(mouseLoc.x, 1)) == null) { //drop Token if column isn't full activeToken.setActEnabled(true); setMouseEnabled(false); currentPlayer = (currentPlayer + 1) % 2; } else { setStatusText("This column is full."); } return true; } public int getPlayerOfTokenAt(int x, int y) { Location loc = new Location(x, y); if (getOneActorAt(loc) == null) return -1; else return ((Token)getOneActorAt(loc)).getPlayer(); } //return true, if four are connected through that token public boolean check4Win(Location loc) { int col = loc.x; int row = loc.y; return (checkVertically(col, row, 4) || checkHorizontally(col, row, 4) || checkDiagonally1(col, row, 4) || checkDiagonally2(col, row, 4)); } //for checking nrOfTokens (win situation: nrOfTokens = 4) private boolean checkDiagonally1(int col, int row, int nrOfTokens) { for (int j = 0; j < nrOfTokens; j++) { int adjacentSameTokens = 0; for (int i = 0; i < nrOfTokens; i++) { if ((col + i - j) >= 0 && (col + i - j) < nbHorzCells && (row + i - j) >= 1 && (row + i - j) < nbVertCells && getPlayerOfTokenAt(col + i - j, row + i - j) == getPlayerOfTokenAt(col, row)) { adjacentSameTokens++; } } if (adjacentSameTokens >= nrOfTokens) return true; } return false; } private boolean checkDiagonally2(int col, int row, int nrOfTokens) { for (int j = 0; j < nrOfTokens; j++) { int adjacentSameTokens = 0; for (int i = 0; i < nrOfTokens; i++) { if ((col - i + j) >= 0 && (col - i + j) < nbHorzCells && (row + i - j) >= 1 && (row + i - j) < nbVertCells && getPlayerOfTokenAt(col - i + j, row + i - j) == getPlayerOfTokenAt(col, row)) { adjacentSameTokens++; } } if (adjacentSameTokens >= nrOfTokens) return true; } return false; } private boolean checkHorizontally(int col, int row, int nrOfTokens) { int adjacentSameTokens = 1; int i = 1; while (col - i >= 0 && getPlayerOfTokenAt(col - i, row) == getPlayerOfTokenAt(col, row)) { adjacentSameTokens++; i++; } i = 1; while (col + i < nbHorzCells && getPlayerOfTokenAt(col + i, row) == getPlayerOfTokenAt(col, row)) { adjacentSameTokens++; i++; } return (adjacentSameTokens >= nrOfTokens); } private boolean checkVertically(int col, int row, int nrOfTokens) { int adjacentSameTokens = 1; int i = 1; while (row + i < nbVertCells && getPlayerOfTokenAt(col, row + i) == getPlayerOfTokenAt(col, row)) { adjacentSameTokens++; i++; } return (adjacentSameTokens >= nrOfTokens); } public static void main(String[] args) { new FourInARow1(); } } //------------- class BG ---------------- class BG extends Actor { public BG() { super(false, "sprites/4inARowBG.png"); } public void reset() { this.setLocationOffset(new java.awt.Point(0, 4 * 70)); this.setOnTop(); } } //------------- class Token ------------------- class Token extends Actor { private int player, nb; private FourInARow1 gg; public Token(int player, FourInARow1 gg) { super(false, "sprites/token.png", 2); this.player = player; this.gg = gg; setActEnabled(false); show(player); // 0 = yellow , 1 = red } public void act() { Location nextLoc = new Location(getX(), getY() + 1); if (gameGrid.getOneActorAt(nextLoc) == null && isMoveValid()) { if (nb == 6) { nb = 0; setLocationOffset(new java.awt.Point(0, 0)); move(); } else setLocationOffset(new java.awt.Point(0, 10 * nb)); nb++; } else { //token has arrived setActEnabled(false); if (gg.check4Win(getLocation())) { gg.setStatusText((player == 0 ? "Yellow" : "Red") + " player won! Click on the board to play again."); gg.getBg().drawText("Game Over", new Point(10, 55)); gg.finished = true; } else { // make new Token: gg.activeToken = new Token((player + 1) % 2, gg); gg.addActor(gg.activeToken, new Location(getX(), 0), Location.SOUTH); } gg.setMouseEnabled(true); } } public int getPlayer() { return player; } } |
Explaining the program code of version 1:
class Token | Token is a independent object. The token (stone) knows how to move, where its final position is and which player played it |
Location nextLoc = new Location(getX(), getY() + 1) | the stone moves down the grid |
if (gameGrid.getOneActorAt(nextLoc) == null && isMoveValid()) | checks if the next lower cell is emtpy or if the stone has already reached the lowest row |
setLocationOffset(new java.awt.Point(0, 10 * nb)) |
the stone does not jump from cell to cell, but falls smoothly down the column. Its "positions in between cells" are calculated into pixel coordinates |
class BG addActor(new BG(), new Location(3, -1)) |
the class is only used, to let the stones fall behind the board. The perforated board is a Actor with transparent holes, which is set in front of the stones |
boolean check4Win(Location loc) | after each newly set stone the horizontal, vertical and diagonal lines need to be checked |
The player starts with a yellow stone. The mouse cursor is set above the designated column and with a click the stone falls to the lowest possible cell. The red stone is set immediately afterwards by the computer. Even though the PC plays with an ideal strategy, it is possible to beat it.
|
![]() |