In unserer Lernumgebung finden man dieses Spiel in drei Varianten:
|
Programmcode für lokale Bearbeitung Downloaden: FourInARow1.zip
Der Spieler beginnt jeweils mit einem gelben Spielstein. Man bewegt die Maus zu der ausgewählten Spalte und lässt den Spielstein mit einem Mausklick hinunter fallen. Der rote Spielstein wird jeweils unmittelbar danach durch den Computer gesetzt. Obwohl der Computer eine optimale Strategie spielt, kann auch der Spieler gewinnen.
Programmcode für lokale Bearbeitung Downloaden: FourInARow2.zip |
Programmcode Downloaden: FourInARowVsComputer.zip
Erklärungen zum Programmcode Variante 1 (zwei Spieler):
class Token | Token ist ein eigenständiges Objekt. Der Token weiss, wie er sich bewegen muss und merkt, wenn er an der definitiven Position angekommen ist und welcher Spieler ihn in die Bewegung gesetzt hat |
Location nextLoc = new Location(getX(), getY() + 1) | Der Spielstein bewegt sich im Gitter nach unten |
if (gameGrid.getOneActorAt(nextLoc) == null && isMoveValid()) | Es wird überprüft, ob die nächst untere Zelle leer ist und ob der Spielstein nicht bereits in der untersten waagrechten Linie ist | setLocationOffset(new java.awt.Point(0, 10 * nb)) |
Der Spielstein bewegt sich nicht sprunghaft von Zelle zur Zelle, sondern kontinuierlich. Seine "Zwischenpositionen" werden mit Pixelkoordinaten angegeben |
class BG addActor(new BG(), new Location(3, -1)) |
Die Klasse BG braucht man lediglich dazu, um die Spielsteine hinten dem gelochten Brett fallen zu lassen. Das gelochte Brett ist ein Actor mit transparenten Löchern, der bzgl. Sichtbarkeit vor den Token positioniert wird |
boolean check4Win(Location loc) | Bei jedem neu gesetzten Spielstein müssen Zeilen, Spalten und Diagonalen überprüft werden |
Programmcode zur Variante 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; } } |