diff --git a/src/de/itsblue/ConnectFour/ConnectFour.java b/src/de/itsblue/ConnectFour/ConnectFour.java index fe67e89..e580b7e 100644 --- a/src/de/itsblue/ConnectFour/ConnectFour.java +++ b/src/de/itsblue/ConnectFour/ConnectFour.java @@ -18,7 +18,6 @@ package de.itsblue.ConnectFour; - import java.awt.*; import javax.swing.*; @@ -29,29 +28,37 @@ public class ConnectFour extends JFrame { /** * */ - private static final long serialVersionUID = 1L; - + private static final long serialVersionUID = 1L; + ConnectFour() { // Constructor // initialize window this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setTitle("Connect 4"); - + this.setPreferredSize(new Dimension(600, 600)); this.getContentPane().setLayout(new GridBagLayout()); + // Board initilisieren GameBoard board = new GameBoard(); - board.setPreferredSize(new Dimension(200,200)); + board.setPreferredSize(new Dimension(400, 400)); this.add(board); - for(int i = 0; i < 7; i++) { - board.insertPlate(new Plate(PlateType.X), i); + // plate in das Board einfügen + 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 this.pack(); this.setVisible(true); diff --git a/src/de/itsblue/ConnectFour/GameBoard.java b/src/de/itsblue/ConnectFour/GameBoard.java index d91afe4..c8c9626 100644 --- a/src/de/itsblue/ConnectFour/GameBoard.java +++ b/src/de/itsblue/ConnectFour/GameBoard.java @@ -21,6 +21,15 @@ package de.itsblue.ConnectFour; import javax.swing.*; 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 { /** @@ -31,17 +40,23 @@ public class GameBoard extends JPanel { /** * The rows of the board */ - public int BoardRows = 6; + private int BoardRows = 6; /** * The columns of the board */ - public int BoardColumns = 7; + private int BoardColumns = 7; /** * 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 @@ -55,13 +70,14 @@ public class GameBoard extends JPanel { * * @param plate Plate object to insert * @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 - if (column > BoardColumns - 1) - return false; + if (column > BoardColumns - 1 || this.boardLocked) + return "err"; // search for an empty row 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 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.boardLocked = false; } /** * Function to fill the board with containers */ - public void initBoard() { + private void initBoard() { // configure the main layout 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; if (parentSize.getWidth() / this.BoardColumns > parentSize.getHeight() / this.BoardRows) @@ -121,14 +148,139 @@ public class GameBoard extends JPanel { return containerSize; } + /** + * 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 null if there was no matching chain or the PlateType of + * the chain + */ + public PlateType checkContainerForWin(int c, int r) { + + // if there is no plate in the container to check + // -> return false + if (this.getPlateContainer(c, r) == null || !this.getPlateContainer(c, r).containsPlate()) + return null; + + // check all possible winnings clockwise + for (int pc = 0; pc < 8; pc++) { + + 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 null 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 checkR = 0; + + switch (direction) { + case 0: + // check top + checkC = c; + checkR = r + i; + break; + case 1: + // check top right vert + checkC = c + i; + checkR = r + i; + break; + case 2: + // check right + checkC = c + i; + checkR = r; + break; + case 3: + // check bottom right vert + checkC = c + i; + checkR = r - i; + break; + case 4: + // check bottom + checkC = c; + checkR = r - i; + break; + case 5: + // check bottom left vert + checkC = c - i; + checkR = r - i; + break; + case 6: + // check left + checkC = c - i; + checkR = r; + break; + case 7: + // check top left vert + checkC = c - i; + checkR = r + i; + break; + } + + containers[i] = this.getPlateContainer(checkC, checkR); + } + + return containers; + } + /** * Override paint function to rescale all caontainers on every repaint */ @Override public void paint(Graphics g) { - System.out.println("updating sizes"); - + // update the size of all containers for (PlateContainer[] plateContainers : BoardContainers) { for (PlateContainer plateContainer : plateContainers) { plateContainer.setPreferredSize(new Dimension(this.getSuggestedContainerSize(this.getSize()), @@ -139,127 +291,13 @@ public class GameBoard extends JPanel { 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); } - - 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 - // -> return false - if (this.getPlateContainer(c, r) == null || !this.getPlateContainer(c, r).containsPlate()) - return false; - - // 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++) { - currentContainer = null; - - int checkC = 0; - int checkR = 0; - - switch (pc) { - case 0: - // check top - checkC = c; - checkR = r + i; - break; - case 1: - // check top right vert - checkC = c + i; - checkR = r + i; - break; - case 2: - // check right - checkC = c + i; - checkR = r; - break; - case 3: - // check bottom right vert - checkC = c + i; - checkR = r - i; - break; - case 4: - checkC = c; - checkR = r - i; - // check bottom - break; - case 5: - // check bottom left vert - checkC = c - i; - checkR = r - i; - break; - case 6: - // check left - checkC = c - i; - checkR = r; - break; - case 7: - // check top left vert - checkC = c - i; - checkR = r + i; - break; - default: - currentContainer = null; - break; - } - - currentContainer = this.getPlateContainer(checkC, checkR); - - if (currentContainer != null && currentContainer.containsPlate()) - sums[pc] += currentContainer.getContainedPlate().getValue(); - } - } - - for (int sum : sums) { - if (Math.abs(sum) == 4) { - if (sum > 0) - System.out.println("negative won"); - else - System.out.println("positive won"); - - return true; - } - } - - return false; - } - - 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; } } - */ - - /* - * void switchPlayer() { if (p != 1) p = 1; else p = 1; } - */ } \ No newline at end of file diff --git a/src/de/itsblue/ConnectFour/PlateContainer.java b/src/de/itsblue/ConnectFour/PlateContainer.java index 928f372..5403311 100644 --- a/src/de/itsblue/ConnectFour/PlateContainer.java +++ b/src/de/itsblue/ConnectFour/PlateContainer.java @@ -21,6 +21,14 @@ package de.itsblue.ConnectFour; import javax.swing.JPanel; 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 { /** @@ -33,6 +41,11 @@ public class PlateContainer extends JPanel { */ private Plate containedPlate = null; + /** + * is the container currently highlighted? + */ + private boolean highlighted = false; + /** * Constructor */ @@ -49,8 +62,6 @@ public class PlateContainer extends JPanel { if (this.containsPlate()) return false; - System.out.println("adding plate " + plate); - this.containedPlate = plate; return true; @@ -68,8 +79,7 @@ public class PlateContainer extends JPanel { /** * Function to check if the container is occupied * - * @return true if occupied - * false if not + * @return true if occupied false if not */ public boolean containsPlate() { if (this.containedPlate != null) @@ -79,20 +89,29 @@ 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: null */ public Plate removePlate() { if (!this.containsPlate()) return null; - + Plate ret = this.containedPlate; this.containedPlate = null; + this.highlighted = false; + return ret; } + /** + * Function to highlight the container + */ + public void highlight() { + this.highlighted = true; + } + /** * Override the paint function to draw the shape of the plate */ @@ -111,5 +130,14 @@ public class PlateContainer extends JPanel { // draw plate g.fillOval((int) (this.getWidth() * 0.1), (int) (this.getHeight() * 0.1), (int) (this.getWidth() * 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)); + } } } \ No newline at end of file