Finished up board and winning check
This commit is contained in:
parent
bc73ed4829
commit
f4098bf044
3 changed files with 219 additions and 146 deletions
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package de.itsblue.ConnectFour;
|
package de.itsblue.ConnectFour;
|
||||||
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -42,15 +41,23 @@ public class ConnectFour extends JFrame {
|
||||||
|
|
||||||
this.getContentPane().setLayout(new GridBagLayout());
|
this.getContentPane().setLayout(new GridBagLayout());
|
||||||
|
|
||||||
|
// Board initilisieren
|
||||||
GameBoard board = new GameBoard();
|
GameBoard board = new GameBoard();
|
||||||
board.setPreferredSize(new Dimension(200,200));
|
board.setPreferredSize(new Dimension(400, 400));
|
||||||
this.add(board);
|
this.add(board);
|
||||||
|
|
||||||
for(int i = 0; i < 7; i++) {
|
// plate in das Board einfügen
|
||||||
board.insertPlate(new Plate(PlateType.X), i);
|
board.insertPlate(new Plate(PlateType.O), 1);
|
||||||
|
|
||||||
|
// ein paar mehr plates einfügen
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
String res = board.insertPlate(new Plate(PlateType.X), i);
|
||||||
|
// wen das Rückgabewert weder "ok" noch "err" ist, hat jemand gewonnen
|
||||||
|
if (res != "ok" && res != "err")
|
||||||
|
System.out.println(PlateType.valueOf(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
board.insertPlate(new Plate(PlateType.O), 1);
|
// board kann mit board.clearBoard(); geleert werden.
|
||||||
|
|
||||||
// finish up
|
// finish up
|
||||||
this.pack();
|
this.pack();
|
||||||
|
|
|
@ -21,6 +21,15 @@ package de.itsblue.ConnectFour;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
|
import de.itsblue.ConnectFour.Plate.PlateType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GameBoard is a fully usable connect4 game board. It can take plates and
|
||||||
|
* insert them into a given column and check if somebody won the game.
|
||||||
|
*
|
||||||
|
* @author Oliver Schappacher
|
||||||
|
* @author Dorian Zedler
|
||||||
|
*/
|
||||||
public class GameBoard extends JPanel {
|
public class GameBoard extends JPanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,17 +40,23 @@ public class GameBoard extends JPanel {
|
||||||
/**
|
/**
|
||||||
* The rows of the board
|
* The rows of the board
|
||||||
*/
|
*/
|
||||||
public int BoardRows = 6;
|
private int BoardRows = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The columns of the board
|
* The columns of the board
|
||||||
*/
|
*/
|
||||||
public int BoardColumns = 7;
|
private int BoardColumns = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array containing all plate containers
|
* Array containing all plate containers
|
||||||
*/
|
*/
|
||||||
PlateContainer[][] BoardContainers = new PlateContainer[BoardColumns][BoardRows];
|
private PlateContainer[][] BoardContainers = new PlateContainer[BoardColumns][BoardRows];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, the board will not accept any insertions. Will be set to
|
||||||
|
* false by the clear() function.
|
||||||
|
*/
|
||||||
|
private boolean boardLocked = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -55,13 +70,14 @@ public class GameBoard extends JPanel {
|
||||||
*
|
*
|
||||||
* @param plate Plate object to insert
|
* @param plate Plate object to insert
|
||||||
* @param column The column to insert the plate into
|
* @param column The column to insert the plate into
|
||||||
* @return true if the inserton was successfull, false if the column is full
|
* @return "ok" if the inserton was successfull, "err" if the column is full,
|
||||||
|
* PlateType as string if a plate type has won
|
||||||
*/
|
*/
|
||||||
public boolean insertPlate(Plate plate, int column) {
|
public String insertPlate(Plate plate, int column) {
|
||||||
|
|
||||||
// check if the column is out of range
|
// check if the column is out of range
|
||||||
if (column > BoardColumns - 1)
|
if (column > BoardColumns - 1 || this.boardLocked)
|
||||||
return false;
|
return "err";
|
||||||
|
|
||||||
// search for an empty row
|
// search for an empty row
|
||||||
for (int i = BoardRows - 1; i >= 0; i--) {
|
for (int i = BoardRows - 1; i >= 0; i--) {
|
||||||
|
@ -69,13 +85,16 @@ public class GameBoard extends JPanel {
|
||||||
// if the container is empty -> add the plate
|
// if the container is empty -> add the plate
|
||||||
this.BoardContainers[column][i].insertPlate(plate);
|
this.BoardContainers[column][i].insertPlate(plate);
|
||||||
|
|
||||||
this.checkContainerForWin(column, i);
|
PlateType winCheckResult = this.checkContainerForWin(column, i);
|
||||||
|
|
||||||
return true;
|
if (winCheckResult == null)
|
||||||
|
return "ok";
|
||||||
|
|
||||||
|
return winCheckResult.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return "err";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,12 +108,14 @@ public class GameBoard extends JPanel {
|
||||||
this.BoardContainers[c][r].removePlate();
|
this.BoardContainers[c][r].removePlate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.boardLocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to fill the board with containers
|
* Function to fill the board with containers
|
||||||
*/
|
*/
|
||||||
public void initBoard() {
|
private void initBoard() {
|
||||||
// configure the main layout
|
// configure the main layout
|
||||||
this.setLayout(new GridLayout(this.BoardRows, this.BoardColumns));
|
this.setLayout(new GridLayout(this.BoardRows, this.BoardColumns));
|
||||||
|
|
||||||
|
@ -110,7 +131,13 @@ public class GameBoard extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSuggestedContainerSize(Dimension parentSize) {
|
/**
|
||||||
|
* Function to calculate a size for the containers to fit a given dimension
|
||||||
|
*
|
||||||
|
* @param parentSize dimension for the containers to fit into
|
||||||
|
* @return suggested container size
|
||||||
|
*/
|
||||||
|
private int getSuggestedContainerSize(Dimension parentSize) {
|
||||||
int containerSize;
|
int containerSize;
|
||||||
|
|
||||||
if (parentSize.getWidth() / this.BoardColumns > parentSize.getHeight() / this.BoardRows)
|
if (parentSize.getWidth() / this.BoardColumns > parentSize.getHeight() / this.BoardRows)
|
||||||
|
@ -122,51 +149,83 @@ public class GameBoard extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override paint function to rescale all caontainers on every repaint
|
* Function to check if a certain container is the beginning of a four plate log
|
||||||
|
* chain of plates of the same type what would indicate the end of the game. If
|
||||||
|
* a matching chain is found, the involved containers are highlited.
|
||||||
|
*
|
||||||
|
* @param c column of the container to check
|
||||||
|
* @param r row of the container to check
|
||||||
|
* @return <code>null</code> if there was no matching chain or the PlateType of
|
||||||
|
* the chain
|
||||||
*/
|
*/
|
||||||
@Override
|
public PlateType checkContainerForWin(int c, int r) {
|
||||||
public void paint(Graphics g) {
|
|
||||||
|
|
||||||
System.out.println("updating sizes");
|
|
||||||
|
|
||||||
for (PlateContainer[] plateContainers : BoardContainers) {
|
|
||||||
for (PlateContainer plateContainer : plateContainers) {
|
|
||||||
plateContainer.setPreferredSize(new Dimension(this.getSuggestedContainerSize(this.getSize()),
|
|
||||||
this.getSuggestedContainerSize(this.getSize())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.paint(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPreferredSize(Dimension preferredSize) {
|
|
||||||
Dimension newSize = new Dimension(this.getSuggestedContainerSize(preferredSize) * this.BoardColumns,
|
|
||||||
this.getSuggestedContainerSize(preferredSize) * this.BoardRows);
|
|
||||||
super.setPreferredSize(newSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkContainerForWin(int c, int r) {
|
|
||||||
|
|
||||||
System.out.println("checking container c=" + c + " r=" + r + " for win");
|
|
||||||
|
|
||||||
// if there is no plate in the container to check
|
// if there is no plate in the container to check
|
||||||
// -> return false
|
// -> return false
|
||||||
if (this.getPlateContainer(c, r) == null || !this.getPlateContainer(c, r).containsPlate())
|
if (this.getPlateContainer(c, r) == null || !this.getPlateContainer(c, r).containsPlate())
|
||||||
return false;
|
return null;
|
||||||
|
|
||||||
// check all possible winnings clockwise
|
// check all possible winnings clockwise
|
||||||
int[] sums = new int[8];
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
PlateContainer currentContainer = null;
|
|
||||||
|
|
||||||
for (int pc = 0; pc < 8; pc++) {
|
for (int pc = 0; pc < 8; pc++) {
|
||||||
currentContainer = null;
|
|
||||||
|
int sum = 0;
|
||||||
|
PlateContainer[] currentContainers = this.getPlateContainerRow(c, r, pc);
|
||||||
|
|
||||||
|
for (PlateContainer plateContainer : currentContainers) {
|
||||||
|
if (plateContainer != null && plateContainer.containsPlate())
|
||||||
|
sum += plateContainer.getContainedPlate().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(sum) == 4) {
|
||||||
|
this.boardLocked = true;
|
||||||
|
|
||||||
|
for (PlateContainer plateContainer : currentContainers) {
|
||||||
|
plateContainer.highlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getPlateContainer(c, r).getContainedPlate().getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get the container at a certain column and row.
|
||||||
|
*
|
||||||
|
* @param c column of the container
|
||||||
|
* @param r row of the container
|
||||||
|
* @return <code>null</code> if there is no container at the given posistion or
|
||||||
|
* the container at the given position
|
||||||
|
*/
|
||||||
|
public PlateContainer getPlateContainer(int c, int r) {
|
||||||
|
if (this.BoardContainers.length > c && c >= 0 && this.BoardContainers[c].length > r && r >= 0)
|
||||||
|
return this.BoardContainers[c][r];
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get a row of four containers starting at a given one
|
||||||
|
*
|
||||||
|
* @param c column of the container to start at
|
||||||
|
* @param r row of the conatiner to start at
|
||||||
|
* @param direction direction of the row (0-7)
|
||||||
|
* @return list of containers starting with the given one
|
||||||
|
*/
|
||||||
|
private PlateContainer[] getPlateContainerRow(int c, int r, int direction) {
|
||||||
|
|
||||||
|
PlateContainer[] containers = new PlateContainer[4];
|
||||||
|
|
||||||
|
if (direction < 0 || direction > 7)
|
||||||
|
return containers;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
||||||
int checkC = 0;
|
int checkC = 0;
|
||||||
int checkR = 0;
|
int checkR = 0;
|
||||||
|
|
||||||
switch (pc) {
|
switch (direction) {
|
||||||
case 0:
|
case 0:
|
||||||
// check top
|
// check top
|
||||||
checkC = c;
|
checkC = c;
|
||||||
|
@ -188,9 +247,9 @@ public class GameBoard extends JPanel {
|
||||||
checkR = r - i;
|
checkR = r - i;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
// check bottom
|
||||||
checkC = c;
|
checkC = c;
|
||||||
checkR = r - i;
|
checkR = r - i;
|
||||||
// check bottom
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
// check bottom left vert
|
// check bottom left vert
|
||||||
|
@ -207,59 +266,38 @@ public class GameBoard extends JPanel {
|
||||||
checkC = c - i;
|
checkC = c - i;
|
||||||
checkR = r + i;
|
checkR = r + i;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
currentContainer = null;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentContainer = this.getPlateContainer(checkC, checkR);
|
containers[i] = this.getPlateContainer(checkC, checkR);
|
||||||
|
|
||||||
if (currentContainer != null && currentContainer.containsPlate())
|
|
||||||
sums[pc] += currentContainer.getContainedPlate().getValue();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int sum : sums) {
|
return containers;
|
||||||
if (Math.abs(sum) == 4) {
|
|
||||||
if (sum > 0)
|
|
||||||
System.out.println("negative won");
|
|
||||||
else
|
|
||||||
System.out.println("positive won");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
}
|
* Override paint function to rescale all caontainers on every repaint
|
||||||
|
|
||||||
public PlateContainer getPlateContainer(int containerColumn, int containerRow) {
|
|
||||||
|
|
||||||
if (this.BoardContainers.length > containerColumn && containerColumn >= 0
|
|
||||||
&& this.BoardContainers[containerColumn].length > containerRow && containerRow >= 0)
|
|
||||||
return this.BoardContainers[containerColumn][containerRow];
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void winningCondition() { for (int i = 0; i <= 2; i++) for (int j = 0; j <=
|
|
||||||
* 6; j++) { if (GameBoard[i][j] == p && GameBoard[i + 1][j] == p && GameBoard[i
|
|
||||||
* + 2][j] == p && GameBoard[i + 3][j] == p) { finish = true; } } for (int i =
|
|
||||||
* 0; i <= 5; i++) for (int j = 0; j <= 3; j++) { if (GameBoard[i][j] == p &&
|
|
||||||
* GameBoard[i][j + 1] == p && GameBoard[i][j + 2] == p && GameBoard[i][j + 3]
|
|
||||||
* == p) finish = true; }
|
|
||||||
*
|
|
||||||
* for (int i = 0; i <= 2; i++) for (int j = 0; j <= 3; j++) { if
|
|
||||||
* (GameBoard[i][j] == p && GameBoard[i + 1][j + 1] == p && GameBoard[i + 2][j +
|
|
||||||
* 2] == p && GameBoard[i + 3][j + 3] == p) finish = true; }
|
|
||||||
*
|
|
||||||
* for (int i = 0; i < 3; i++) for (int j = 6; j > 2; j--) { if (GameBoard[i][j]
|
|
||||||
* == p && GameBoard[i + 1][j - 1] == p && GameBoard[i + 2][j - 2] == p &&
|
|
||||||
* GameBoard[i + 3][j - 3] == p) finish = true; } }
|
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
|
public void paint(Graphics g) {
|
||||||
|
|
||||||
/*
|
// update the size of all containers
|
||||||
* void switchPlayer() { if (p != 1) p = 1; else p = 1; }
|
for (PlateContainer[] plateContainers : BoardContainers) {
|
||||||
|
for (PlateContainer plateContainer : plateContainers) {
|
||||||
|
plateContainer.setPreferredSize(new Dimension(this.getSuggestedContainerSize(this.getSize()),
|
||||||
|
this.getSuggestedContainerSize(this.getSize())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.paint(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override setPrefferedSize function to force aspect ratio
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
|
public void setPreferredSize(Dimension preferredSize) {
|
||||||
|
Dimension newSize = new Dimension(this.getSuggestedContainerSize(preferredSize) * this.BoardColumns,
|
||||||
|
this.getSuggestedContainerSize(preferredSize) * this.BoardRows);
|
||||||
|
super.setPreferredSize(newSize);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,14 @@ package de.itsblue.ConnectFour;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlateContainer is a visual element intendet to be used in a GameBoard in
|
||||||
|
* order to store a plate and indicate what kind of plate it contains. It can ge
|
||||||
|
* highlighted for examplte to indicate that it was involeved in the end of a
|
||||||
|
* game.
|
||||||
|
*
|
||||||
|
* @author Dorian Zedler
|
||||||
|
*/
|
||||||
public class PlateContainer extends JPanel {
|
public class PlateContainer extends JPanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,6 +41,11 @@ public class PlateContainer extends JPanel {
|
||||||
*/
|
*/
|
||||||
private Plate containedPlate = null;
|
private Plate containedPlate = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is the container currently highlighted?
|
||||||
|
*/
|
||||||
|
private boolean highlighted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
@ -49,8 +62,6 @@ public class PlateContainer extends JPanel {
|
||||||
if (this.containsPlate())
|
if (this.containsPlate())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
System.out.println("adding plate " + plate);
|
|
||||||
|
|
||||||
this.containedPlate = plate;
|
this.containedPlate = plate;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -68,8 +79,7 @@ public class PlateContainer extends JPanel {
|
||||||
/**
|
/**
|
||||||
* Function to check if the container is occupied
|
* Function to check if the container is occupied
|
||||||
*
|
*
|
||||||
* @return <code>true</code> if occupied
|
* @return <code>true</code> if occupied <code>false</code> if not
|
||||||
* <code>false</code> if not
|
|
||||||
*/
|
*/
|
||||||
public boolean containsPlate() {
|
public boolean containsPlate() {
|
||||||
if (this.containedPlate != null)
|
if (this.containedPlate != null)
|
||||||
|
@ -79,7 +89,7 @@ public class PlateContainer extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to clear the container
|
* Function to clear the container, also removes the highlighting
|
||||||
*
|
*
|
||||||
* @return if it was occupied: contained plate, else: <code>null</code>
|
* @return if it was occupied: contained plate, else: <code>null</code>
|
||||||
*/
|
*/
|
||||||
|
@ -90,9 +100,18 @@ public class PlateContainer extends JPanel {
|
||||||
Plate ret = this.containedPlate;
|
Plate ret = this.containedPlate;
|
||||||
this.containedPlate = null;
|
this.containedPlate = null;
|
||||||
|
|
||||||
|
this.highlighted = false;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to highlight the container
|
||||||
|
*/
|
||||||
|
public void highlight() {
|
||||||
|
this.highlighted = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the paint function to draw the shape of the plate
|
* Override the paint function to draw the shape of the plate
|
||||||
*/
|
*/
|
||||||
|
@ -111,5 +130,14 @@ public class PlateContainer extends JPanel {
|
||||||
// draw plate
|
// draw plate
|
||||||
g.fillOval((int) (this.getWidth() * 0.1), (int) (this.getHeight() * 0.1), (int) (this.getWidth() * 0.8),
|
g.fillOval((int) (this.getWidth() * 0.1), (int) (this.getHeight() * 0.1), (int) (this.getWidth() * 0.8),
|
||||||
(int) (this.getHeight() * 0.8));
|
(int) (this.getHeight() * 0.8));
|
||||||
|
|
||||||
|
if (this.highlighted) {
|
||||||
|
g.setColor(Color.green);
|
||||||
|
Graphics2D g2 = (Graphics2D) g;
|
||||||
|
g2.setStroke(new BasicStroke((int) (this.getWidth() * 0.1)));
|
||||||
|
|
||||||
|
g2.drawOval((int) (this.getWidth() * 0.1), (int) (this.getHeight() * 0.1), (int) (this.getWidth() * 0.8),
|
||||||
|
(int) (this.getHeight() * 0.8));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in a new issue