diff --git a/src/main/java/de/tims/fleetstorm/ai/Logic.java b/src/main/java/de/tims/fleetstorm/ai/Logic.java index 359fcbd..5c4be84 100644 --- a/src/main/java/de/tims/fleetstorm/ai/Logic.java +++ b/src/main/java/de/tims/fleetstorm/ai/Logic.java @@ -1,9 +1,232 @@ package de.tims.fleetstorm.ai; +import java.util.ArrayList; +import java.util.Random; + +import de.tims.fleetstorm.matchfield.Coordinate; +import de.tims.fleetstorm.matchfield.Matchfield; + public class Logic { - public int[] chooseField() { - return new int[] {}; + private Matchfield matchfield; + private ArrayList everySecondField; + + private Coordinate lastShot; + private Coordinate target; + private boolean foundShip; + private boolean clearedAbove; + private boolean clearedBelow; + private boolean clearedRight; + private boolean clearedLeft; + + public Logic() { + foundShip = false; + clearedAbove = false; + clearedBelow = false; + clearedRight = false; + clearedLeft = false; + } + + public Coordinate chooseField() { + Coordinate out; + + if (foundShip) { + // Clear Y-Axis + if (!clearedAbove) { + target = matchfield.getAbove(target); + out = target; + if (target == null || target.getState() == Coordinate.EMPTY) { + clearedAbove = true; + target = lastShot; + } + return out; + } + + if (!clearedBelow) { + target = matchfield.getBelow(target); + out = target; + if (target == null || target.getState() == Coordinate.EMPTY) { + clearedBelow = true; + target = lastShot; + } + isShipOnYAxis(); + return out; + } + + // Clear x-Axis + if (!clearedRight) { + target = matchfield.getRight(target); + out = target; + if (target == null || target.getState() == Coordinate.EMPTY) { + clearedRight = true; + target = lastShot; + } + return out; + } + + if (!clearedLeft) { + target = matchfield.getLeft(target); + out = target; + if (target == null || target.getState() == Coordinate.EMPTY) { + clearedLeft = true; + target = lastShot; + } + sinkShip(); + return out; + } + } + + ArrayList possibleFields = new ArrayList(); + for (int i = 0; i < everySecondField.size(); i++) { + if (everySecondField.get(i).getState() != Coordinate.SHOT + && everySecondField.get(i).getState() != Coordinate.HIT) { + possibleFields.add(everySecondField.get(i)); + } + } + Random randy = new Random(); + lastShot = possibleFields.get(randy.nextInt(possibleFields.size())); + target = possibleFields.get(randy.nextInt(possibleFields.size())); + if (lastShot.getState() == Coordinate.SHIP) { + foundShip = true; + } + return lastShot; + } + + public void isShipOnYAxis() { + if ((clearedAbove && clearedBelow) && ((matchfield.getAbove(lastShot) == null + || (matchfield.getAbove(lastShot).getState() == Coordinate.HIT)) + || (matchfield.getBelow(lastShot) == null + || (matchfield.getBelow(lastShot).getState() == Coordinate.HIT)))) { + clearedLeft = true; + clearedRight = true; + sinkShip(); + } + } + + public ArrayList getEverySecondField() { + ArrayList out = new ArrayList(); + for (int x = 0; x < Math.sqrt(this.matchfield.getSize()); x++) { + for (int y = 0; y < Math.sqrt(this.matchfield.getSize()); y++) { + if ((x % 2 == 0 && y % 2 == 0) || (x % 2 == 1 && y % 2 == 1)) { + out.add(this.matchfield.getField(x, y)); + } + } + } + return out; } + public void findShip() { + if (lastShot.getState() == Coordinate.HIT) { + foundShip = true; + } + } + + public void sinkShip() { + if (foundShip && clearedAbove && clearedBelow && clearedLeft && clearedRight) { + this.foundShip = false; + this.clearedAbove = false; + this.clearedBelow = false; + this.clearedLeft = false; + this.clearedRight = false; + } + } + + public void clearAbove(Coordinate shot) { + target = matchfield.getAbove(shot); + if (target.getState() == Coordinate.EMPTY) { + clearedAbove = true; + } + } + + public void clearBelow(Coordinate shot) { + target = matchfield.getBelow(shot); + if (target.getState() == Coordinate.EMPTY) { + clearedBelow = true; + } + } + + public void clearRight(Coordinate shot) { + target = matchfield.getRight(shot); + if (target.getState() == Coordinate.EMPTY) { + clearedRight = true; + } + } + + public void clearLeft(Coordinate shot) { + target = matchfield.getLeft(shot); + if (target.getState() == Coordinate.EMPTY) { + clearedLeft = true; + } + } + + // Getter And Setter + + public void setEverySecondField(ArrayList everySecondField) { + this.everySecondField = everySecondField; + } + + public void setLastShot(Coordinate coordinate) { + lastShot = this.matchfield.getField(coordinate); + } + + public Coordinate getLastShot() { + return lastShot; + } + + public void setFoundShip(boolean b) { + this.foundShip = b; + } + + public boolean getFoundShip() { + return this.foundShip; + } + + public void setClearedAbove(boolean b) { + this.clearedAbove = b; + } + + public boolean getClearedAbove() { + return this.clearedAbove; + } + + public void setClearedBelow(boolean b) { + this.clearedBelow = b; + } + + public boolean getClearedBelow() { + return this.clearedBelow; + } + + public void setClearedRight(boolean b) { + this.clearedRight = b; + } + + public boolean getClearedRight() { + return this.clearedRight; + } + + public void setClearedLeft(boolean b) { + this.clearedLeft = b; + } + + public boolean getClearedLeft() { + return this.clearedLeft; + } + + public void setTarget(Coordinate target) { + this.target = target; + } + + public Coordinate getTarget() { + return target; + } + + public void setMatchfield(Matchfield matchfield) { + this.matchfield = matchfield; + this.everySecondField = getEverySecondField(); + } + + public Matchfield getMatchfield() { + return matchfield; + } } diff --git a/src/main/java/de/tims/fleetstorm/gui/GameLogic.java b/src/main/java/de/tims/fleetstorm/gui/GameLogic.java new file mode 100644 index 0000000..2bc34d5 --- /dev/null +++ b/src/main/java/de/tims/fleetstorm/gui/GameLogic.java @@ -0,0 +1,268 @@ +package de.tims.fleetstorm.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Font; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.MatteBorder; + +import de.tims.fleetstorm.ai.Logic; +import de.tims.fleetstorm.matchfield.Coordinate; +import de.tims.fleetstorm.matchfield.Matchfield; + +public class GameLogic extends JPanel { + + // GameManager stuff + private int gameState; + private Matchfield matchfield; + private Matchfield enemyMatchfield; + private int matchfieldSize = 10; + private boolean playerMove; + private Logic aiLogic; + + public static final int PREPARATION = 1; + public static final int RUNNING = 2; + public static final int GAME_OVER = 3; + + // GUI stuff + private ArrayList playerFields; + private ArrayList enemyFields; + + public GameLogic(int gapToFrameBorderX, int gapToFrameBorderY, int fieldWidth, int spaceBetween) { + this.playerFields = new ArrayList<>(); + this.enemyFields = new ArrayList<>(); + + setSize(640, 480); + + fieldWrapper = new JPanel(); + fieldWrapper.setBounds(10, 11, 305, 458); + fieldWrapper.setLayout(null); + setLayout(null); + add(fieldWrapper); + + enemyFieldWrapper = new JPanel(); + enemyFieldWrapper.setLayout(null); + enemyFieldWrapper.setBounds(326, 11, 305, 458); + add(enemyFieldWrapper); + + this.generateFieldsForGUI(gapToFrameBorderX, gapToFrameBorderY, fieldWidth, spaceBetween, fieldWrapper, + this.playerFields, false); + + JLabel ownFieldLabel = new JLabel("Eigenes Spielfeld"); + ownFieldLabel.setBounds(10, 11, 114, 14); + fieldWrapper.add(ownFieldLabel); + this.generateFieldsForGUI(gapToFrameBorderX, gapToFrameBorderY, fieldWidth, spaceBetween, enemyFieldWrapper, + this.enemyFields, true); + + JLabel enemyFieldLabel = new JLabel("Gegnerisches Spielfeld"); + enemyFieldLabel.setBounds(10, 11, 168, 14); + enemyFieldWrapper.add(enemyFieldLabel); + } + + private void generateFieldsForGUI(int gapToFrameBorderX, int gapToFrameBorderY, int fieldWidth, int spaceBetween, + JPanel panel, ArrayList fields, boolean registerMouseListener) { + + for (int x = 0; x < this.matchfieldSize; x++) { + for (int y = 0; y < this.matchfieldSize; y++) { + JPanel field = new JPanel(); + + int xPos = gapToFrameBorderX + x * fieldWidth + (x * spaceBetween); + int yPos = gapToFrameBorderY + y * fieldWidth + (y * spaceBetween); + + field.setBounds(xPos, yPos, fieldWidth, fieldWidth); + field.setBorder(new MatteBorder(1, 1, 1, 1, (Color) new Color(0, 0, 0))); + field.setName(x + ":" + y); + + fields.add(field); + panel.add(field); + + if (!registerMouseListener) + continue; + + field.addMouseListener(new MouseAdapter() { + + public void mouseClicked(MouseEvent e) { + int[] coords = getCoordinateFromLabel(field); + int coordX = coords[0]; + int coordY = coords[1]; + + Coordinate chosenField = enemyMatchfield.getField(coordX, coordY); + + boolean shotSuccess = chosenField.shoot(); + + boolean areAllShipsHit = enemyMatchfield.areAllShipsHit(); + if (areAllShipsHit) { + gameOver(true); + return; + } + + if (shotSuccess && chosenField.getState() != Coordinate.HIT) { + nextMove(false); + } else { + nextMove(true); + } + + } + }); + + } + } + } + + private JLabel getXLabel() { + JLabel x = new JLabel("x"); + x.setForeground(Color.WHITE); + return x; + } + + private int[] getCoordinateFromLabel(JPanel panel) { + String panelName = panel.getName(); + String[] panelNameSplit = panelName.split(":"); + int coordX = Integer.parseInt(panelNameSplit[0]); + int coordY = Integer.parseInt(panelNameSplit[1]); + return new int[] { coordX, coordY }; + } + + private void updateFields() { + this.updateField(enemyMatchfield, this.enemyFields); + this.updateField(matchfield, this.playerFields); + } + + private void updateField(Matchfield matchfield, ArrayList fields) { + + for (JPanel coordinatePanel : fields) { + int[] coords = getCoordinateFromLabel(coordinatePanel); + int coordX = coords[0]; + int coordY = coords[1]; + + // reset field + coordinatePanel.setBackground(null); + coordinatePanel.removeAll(); + + int state = matchfield.getField(coordX, coordY).getState(); + + switch (state) { + case Coordinate.SHIP: + if (playerMove) + coordinatePanel.setBackground(new Color(91, 58, 41)); + break; + case Coordinate.SHOT: + coordinatePanel.setBackground(new Color(0, 94, 184)); + break; + case Coordinate.HIT: + coordinatePanel.setBackground(new Color(91, 58, 41)); + coordinatePanel.add(getXLabel()); + break; + } + + coordinatePanel.revalidate(); + coordinatePanel.repaint(); + } + + } + + /** + * This function is only for testing + */ + private static GameLogic gui; + private JPanel fieldWrapper; + private JPanel enemyFieldWrapper; + + public static void main(String[] args) { + JFrame frame = new JFrame("Test GUI"); + gui = new GameLogic(12, 35, 25, 1); + frame.setContentPane(gui); + frame.setSize(640, 480); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setResizable(true); + frame.setVisible(true); + + gui.start(false); + } + + public void start(boolean test) { + this.gameState = GameLogic.PREPARATION; + this.playerMove = true; + + // create player matchfield and set ships + this.matchfield = new Matchfield(matchfieldSize); + this.matchfield.createMatchfield(); + this.matchfield.setShip(new Coordinate(4, 6), 2, 0); + this.matchfield.setShip(new Coordinate(1, 3), 3, 0); + this.matchfield.setShip(new Coordinate(9, 1), 4, 1); + this.matchfield.setShip(new Coordinate(0, 0), 5, 0); + + this.aiLogic = new Logic(); + this.aiLogic.setMatchfield(this.matchfield); + + // create enemy matchfield, set ships and initialize AI (with player's + // matchfield) + this.enemyMatchfield = new Matchfield(matchfieldSize); + this.enemyMatchfield.createMatchfield(); + this.enemyMatchfield.setShip(new Coordinate(8, 9), 2, 0); + this.enemyMatchfield.setShip(new Coordinate(0, 2), 3, 1); + this.enemyMatchfield.setShip(new Coordinate(7, 0), 4, 1); + this.enemyMatchfield.setShip(new Coordinate(3, 6), 5, 0); + + // enter game loop + this.gameState = GameLogic.RUNNING; + if (!test) + this.nextMove(true); + } + + public void nextMove(boolean playerMove) { + this.playerMove = playerMove; + + if (this.playerMove) { + gui.updateFields(); + // waiting here for mouse click event.... + } else { + + Coordinate aiChosenField = null; + while (aiChosenField == null) { + aiChosenField = this.aiLogic.chooseField(); + } + + aiChosenField.shoot(); + + gui.updateFields(); + + boolean areAllShipsHit = this.matchfield.areAllShipsHit(); + if (areAllShipsHit) { + this.gameOver(false); + return; + } + + boolean aiHasNextMove = aiChosenField.getState() != Coordinate.HIT; + this.nextMove(aiHasNextMove); + } + + } + + protected void gameOver(boolean playerWinner) { + this.gameState = GameLogic.GAME_OVER; + + this.removeAll(); + this.setLayout(new BorderLayout()); + + JLabel wonLabel = new JLabel(playerWinner ? "Du hast gewonnen!" : "Du hast verloren!"); + wonLabel.setHorizontalAlignment(SwingConstants.CENTER); + wonLabel.setVerticalAlignment(SwingConstants.CENTER); + wonLabel.setFont(new Font("Tahoma", Font.BOLD, 18)); + this.add(wonLabel, SwingConstants.CENTER); + + this.revalidate(); + this.repaint(); + } + + public int getGameState() { + return gameState; + } +} diff --git a/src/main/java/de/tims/fleetstorm/matchfield/Coordinate.java b/src/main/java/de/tims/fleetstorm/matchfield/Coordinate.java new file mode 100644 index 0000000..ede9574 --- /dev/null +++ b/src/main/java/de/tims/fleetstorm/matchfield/Coordinate.java @@ -0,0 +1,61 @@ +package de.tims.fleetstorm.matchfield; + +public class Coordinate { + private int x; + private int y; + private int state; + + public static final int EMPTY = 0; + public static final int SHIP = 1; + public static final int SHOT = 2; + public static final int HIT = 3; + + public Coordinate(int x, int y) { + this.x = x; + this.y = y; + this.state = 0; + } + + public Integer getX() { + return x; + } + + public Integer getY() { + return y; + } + + public int getState() { + return this.state; + } + + public void setState(int state) { + this.state = state; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Coordinate)) { + return false; + } + return this.x == ((Coordinate) obj).getX() && this.y == ((Coordinate) obj).getY(); + } + + public void print() { + System.out.println("X = " + this.x + ", Y = " + this.y + ", State = " + this.state); + } + + public boolean shoot() { + if (this.state == Coordinate.SHOT || this.state == Coordinate.HIT) + return false; + + if (this.state == Coordinate.SHIP) { + this.state = Coordinate.HIT; + return true; + } + + this.state = Coordinate.SHOT; + + return true; + } + +} diff --git a/src/main/java/de/tims/fleetstorm/matchfield/Matchfield.java b/src/main/java/de/tims/fleetstorm/matchfield/Matchfield.java new file mode 100644 index 0000000..cca91c9 --- /dev/null +++ b/src/main/java/de/tims/fleetstorm/matchfield/Matchfield.java @@ -0,0 +1,113 @@ +package de.tims.fleetstorm.matchfield; + +public class Matchfield { + + private Coordinate[][] matchfield; + private int size; + + public Matchfield(int size) { + this.size = size; + this.matchfield = new Coordinate[this.size][this.size]; + } + + public Coordinate[][] createMatchfield() { + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + this.matchfield[i][j] = new Coordinate(i, j); + } + } + + return this.matchfield; + } + + public int getSize() { + return this.matchfield.length * this.matchfield[0].length; + } + + public int getState(int x, int y) { + return this.matchfield[x][y].getState(); + } + + public void setState(int x, int y, int state) { + this.matchfield[x][y].setState(state); + } + + public void setState(Coordinate coordinate, int state) { + this.matchfield[coordinate.getX()][coordinate.getY()].setState(state); + } + + public Coordinate getField(Coordinate coordinate) { + return matchfield[coordinate.getX()][coordinate.getY()]; + } + + public Coordinate getField(int x, int y) { + return this.matchfield[x][y]; + } + + public Coordinate getRight(Coordinate center) { + if (center.getX() == matchfield.length - 1) { + return null; + } + return this.matchfield[center.getX() + 1][center.getY()]; + } + + public Coordinate getLeft(Coordinate center) { + if (center.getX() == 0) { + return null; + } + return this.matchfield[center.getX() - 1][center.getY()]; + } + + public Coordinate getAbove(Coordinate center) { + if (center.getY() == matchfield.length - 1) { + return null; + } + return matchfield[center.getX()][center.getY() + 1]; + } + + public Coordinate getBelow(Coordinate center) { + if (center.getY() == 0) { + return null; + } + return matchfield[center.getX()][center.getY() - 1]; + } + + /** + * direction 0 => x axis (to the right) direction 1 => y axis (to the bottom) + */ + public boolean setShip(Coordinate coordinate, int length, int direction) { + + for (int i = 0; i < length; i++) { + + Coordinate field = this.getField(coordinate); + if (field.getState() == Coordinate.SHIP) + return false; + + field.setState(Coordinate.SHIP); + if (direction == 0) + coordinate = this.getRight(coordinate); + if (direction == 1) + coordinate = this.getAbove(coordinate); + + if (coordinate == null) + return false; + } + + return true; + } + + public boolean areAllShipsHit() { + int shipCounter = 0; + + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + int fieldState = this.matchfield[i][j].getState(); + if (fieldState == Coordinate.SHIP) + shipCounter++; + } + } + + return shipCounter == 0; + } + +} diff --git a/src/test/java/de/tims/fleetstorm/ai/LogicTest.java b/src/test/java/de/tims/fleetstorm/ai/LogicTest.java index 76fe7f2..79935b5 100644 --- a/src/test/java/de/tims/fleetstorm/ai/LogicTest.java +++ b/src/test/java/de/tims/fleetstorm/ai/LogicTest.java @@ -1,16 +1,376 @@ package de.tims.fleetstorm.ai; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.ArrayList; + import org.junit.jupiter.api.Test; +import de.tims.fleetstorm.matchfield.Coordinate; +import de.tims.fleetstorm.matchfield.Matchfield; + class LogicTest { - Logic logic = new Logic(); @Test - void testFielIsNotNull() { - int[] calcResult = logic.chooseField(); + void testFieldIsNotNull() { + Logic logic = new Logic(); + Matchfield matchfield; + int size = 5; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + // ArrayList everySecondField = logic.getEverySecondField(); + + Coordinate calcResult = logic.chooseField(); assertNotNull(calcResult); } + @Test + void testChoosenFieldHasNotStateShot() { + Logic logic = new Logic(); + Matchfield matchfield; + int size = 5; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + + ArrayList everySecondField = logic.getEverySecondField(); + for (int i = 0; i < everySecondField.size(); i++) { + everySecondField.get(i).setState(Coordinate.SHOT); + } + matchfield.setState(2, 2, Coordinate.EMPTY); + logic.setEverySecondField(everySecondField); + + int calcState = logic.chooseField().getState(); + assertNotEquals(calcState, Coordinate.SHOT); + } + + @Test + void testGetEverySecondField() { + Logic logic = new Logic(); + Matchfield matchfield; + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + + ArrayList everySecondField = logic.getEverySecondField(); + ArrayList expectedResult = new ArrayList(); + + expectedResult.add(new Coordinate(0, 0)); + expectedResult.add(new Coordinate(0, 2)); + expectedResult.add(new Coordinate(1, 1)); + expectedResult.add(new Coordinate(1, 3)); + expectedResult.add(new Coordinate(2, 0)); + expectedResult.add(new Coordinate(2, 2)); + expectedResult.add(new Coordinate(3, 1)); + expectedResult.add(new Coordinate(3, 3)); + + assertEquals(everySecondField, expectedResult); + } + + @Test + void testGetAndSetLastShot() { + Logic logic = new Logic(); + Matchfield matchfield; + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + + Coordinate expectedResult = new Coordinate(2, 2); + logic.setLastShot(expectedResult); + Coordinate result = logic.getLastShot(); + + assertEquals(result, expectedResult); + } + + @Test + void testSetMatchfield() { + Logic logic = new Logic(); + Matchfield matchfield; + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + + Matchfield result = logic.getMatchfield(); + assertEquals(result, null); + logic.setMatchfield(matchfield); + result = logic.getMatchfield(); + assertNotNull(result); + } + + @Test + void testFindShip() { + Logic logic = new Logic(); + Matchfield matchfield; + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + + logic.setLastShot(new Coordinate(2, 2)); + logic.getLastShot().setState(Coordinate.HIT); + logic.findShip(); + assertEquals(logic.getFoundShip(), true); + } + + @Test + void testGetAndsetFoundShip() { + Logic logic = new Logic(); + logic.setFoundShip(true); + assertEquals(logic.getFoundShip(), true); + } + + @Test + void testClearAbove() { + Logic logic = new Logic(); + Matchfield matchfield; + Coordinate shot = new Coordinate(2, 2); + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + logic.setLastShot(shot); + matchfield.getField(shot).setState(Coordinate.EMPTY); + + logic.clearAbove(shot); + + assertEquals(logic.getClearedAbove(), true); + } + + @Test + void testClearBelow() { + Logic logic = new Logic(); + Matchfield matchfield; + Coordinate shot = new Coordinate(2, 2); + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + logic.setLastShot(shot); + matchfield.getField(shot).setState(Coordinate.EMPTY); + + logic.clearBelow(shot); + + assertEquals(logic.getClearedBelow(), true); + } + + @Test + void testClearRight() { + Logic logic = new Logic(); + Matchfield matchfield; + Coordinate shot = new Coordinate(2, 2); + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + logic.setLastShot(shot); + matchfield.getField(shot).setState(Coordinate.EMPTY); + + logic.clearRight(shot); + + assertEquals(logic.getClearedRight(), true); + } + + @Test + void testClearLeft() { + Logic logic = new Logic(); + Matchfield matchfield; + Coordinate shot = new Coordinate(2, 2); + int size = 4; + matchfield = new Matchfield(size); + matchfield.createMatchfield(); + logic.setMatchfield(matchfield); + logic.setLastShot(shot); + matchfield.getField(shot).setState(Coordinate.EMPTY); + + logic.clearLeft(shot); + + assertEquals(logic.getClearedLeft(), true); + } + + @Test + void testConstructor() { + Logic logic = new Logic(); + + assertEquals(logic.getFoundShip(), false); + assertEquals(logic.getClearedAbove(), false); + assertEquals(logic.getClearedBelow(), false); + assertEquals(logic.getClearedLeft(), false); + assertEquals(logic.getClearedRight(), false); + } + + @Test + void testSetterClearedAbove() { + Logic logic = new Logic(); + logic.setClearedAbove(true); + + assertEquals(logic.getClearedAbove(), true); + } + + @Test + void testSetterClearedBelow() { + Logic logic = new Logic(); + logic.setClearedBelow(true); + + assertEquals(logic.getClearedBelow(), true); + } + + @Test + void testSetterClearedRight() { + Logic logic = new Logic(); + logic.setClearedRight(true); + + assertEquals(logic.getClearedRight(), true); + } + + @Test + void testSetterClearedLeft() { + Logic logic = new Logic(); + logic.setClearedLeft(true); + + assertEquals(logic.getClearedLeft(), true); + } + + @Test + void testSinkShip() { + Logic logic = new Logic(); + + logic.setFoundShip(true); + logic.setClearedAbove(true); + logic.setClearedBelow(true); + logic.setClearedRight(true); + logic.setClearedLeft(true); + + logic.sinkShip(); + + assertEquals(logic.getFoundShip(), false); + assertEquals(logic.getClearedAbove(), false); + assertEquals(logic.getClearedBelow(), false); + assertEquals(logic.getClearedLeft(), false); + assertEquals(logic.getClearedRight(), false); + + } + + @Test + void testChooseFieldAboveAfterHit() { + Logic logic = new Logic(); + int size = 4; + Coordinate center = new Coordinate(2, 2); + Coordinate expectedResult = new Coordinate(2, 3); + Matchfield matchfield = new Matchfield(size); + matchfield.createMatchfield(); + matchfield.setState(center, Coordinate.HIT); + matchfield.setState(expectedResult, Coordinate.HIT); + logic.setMatchfield(matchfield); + logic.setLastShot(center); + logic.setTarget(center); + logic.setFoundShip(true); + + Coordinate result = logic.chooseField(); + assertEquals(result, expectedResult); + } + + @Test + void testChooseFieldBelowAfterHit() { + Logic logic = new Logic(); + int size = 4; + Coordinate center = new Coordinate(2, 2); + Coordinate expectedResult = new Coordinate(2, 1); + Matchfield matchfield = new Matchfield(size); + matchfield.createMatchfield(); + matchfield.setState(center, Coordinate.HIT); + matchfield.setState(expectedResult, Coordinate.HIT); + logic.setMatchfield(matchfield); + logic.setLastShot(center); + logic.setTarget(center); + logic.setFoundShip(true); + logic.chooseField();// first Shot + Coordinate result = logic.chooseField(); // second Shot + + assertEquals(result, expectedResult); + } + + @Test + void testChooseFieldRightAfterHit() { + Logic logic = new Logic(); + int size = 4; + Coordinate center = new Coordinate(2, 2); + Coordinate expectedResult = new Coordinate(3, 2); + Matchfield matchfield = new Matchfield(size); + matchfield.createMatchfield(); + matchfield.setState(center, Coordinate.HIT); + matchfield.setState(expectedResult, Coordinate.HIT); + logic.setMatchfield(matchfield); + logic.setLastShot(center); + logic.setTarget(center); + logic.setFoundShip(true); + + logic.chooseField(); // first Shot + logic.chooseField(); // second Shot + Coordinate result = logic.chooseField(); + + assertEquals(result, expectedResult); + } + + @Test + void testChooseFieldLeftAfterHit() { + Logic logic = new Logic(); + int size = 4; + Coordinate center = new Coordinate(2, 2); + Coordinate expectedResult = new Coordinate(1, 2); + Matchfield matchfield = new Matchfield(size); + matchfield.createMatchfield(); + matchfield.setState(center, Coordinate.HIT); + matchfield.setState(expectedResult, Coordinate.HIT); + logic.setMatchfield(matchfield); + logic.setLastShot(center); + logic.setTarget(center); + logic.setFoundShip(true); + + logic.chooseField(); // first Shot + logic.chooseField(); // second Shot + logic.chooseField(); // third Shot Coordinate + Coordinate result = logic.chooseField(); + assertEquals(result, expectedResult); + } + + @Test + void testShipIsOnYAxis() { + int size = 10; + Logic logic = new Logic(); + Matchfield matchfield = new Matchfield(size); + Coordinate s1 = new Coordinate(5, 4); + Coordinate s2 = new Coordinate(5, 5); + Coordinate s3 = new Coordinate(5, 6); + + matchfield.createMatchfield(); + matchfield.setState(s1, Coordinate.SHIP); + matchfield.setState(s2, Coordinate.HIT); + matchfield.setState(s3, Coordinate.SHIP); + + logic.setMatchfield(matchfield); + logic.setLastShot(s2); + logic.setTarget(s2); + logic.setFoundShip(true); + + logic.chooseField(); // First shot (s3) + logic.getMatchfield().setState(s3, Coordinate.HIT); // + logic.chooseField(); // Second Shot + logic.getMatchfield().setState(new Coordinate(5, 7), Coordinate.SHOT); + + logic.chooseField(); // Third Shot (s1) + logic.getMatchfield().setState(s1, Coordinate.HIT); // + logic.chooseField(); // fourth Shot + + assertEquals(logic.getFoundShip(), false); + assertEquals(logic.getClearedAbove(), false); + assertEquals(logic.getClearedBelow(), false); + assertEquals(logic.getClearedLeft(), false); + assertEquals(logic.getClearedRight(), false); + + } } diff --git a/src/test/java/de/tims/fleetstorm/gui/LogicTest.java b/src/test/java/de/tims/fleetstorm/gui/LogicTest.java new file mode 100644 index 0000000..4b02637 --- /dev/null +++ b/src/test/java/de/tims/fleetstorm/gui/LogicTest.java @@ -0,0 +1,36 @@ +package de.tims.fleetstorm.gui; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class LogicTest { + + GameLogic guiLogic = new GameLogic(0, 0, 0, 0); + + @BeforeEach + void setup() { + guiLogic.start(true); + } + + @Test + void testIfGameStateIsRunningAfterStart() { + int expectedState = GameLogic.RUNNING; + + int calculatedState = guiLogic.getGameState(); + + assertEquals(expectedState, calculatedState); + } + + @Test + void testIfGameStateIsGameOverAfterGameOverFunction() { + int expectedState = GameLogic.GAME_OVER; + + guiLogic.gameOver(true); + int calculatedState = guiLogic.getGameState(); + + assertEquals(expectedState, calculatedState); + } + +} diff --git a/src/test/java/de/tims/fleetstorm/matchfield/CoordinateTest.java b/src/test/java/de/tims/fleetstorm/matchfield/CoordinateTest.java new file mode 100644 index 0000000..196f4c2 --- /dev/null +++ b/src/test/java/de/tims/fleetstorm/matchfield/CoordinateTest.java @@ -0,0 +1,82 @@ +package de.tims.fleetstorm.matchfield; + +import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class CoordinateTest { + + int x = 1; + int y = 3; + + Coordinate coordinate = new Coordinate(x, y); + + @Test + void testGetCorrectValuesForXY() { + assertEquals(coordinate.getX(), x); + assertEquals(coordinate.getY(), y); + } + + @Test + void testCoordinatehasDefaultStates() { + assertEquals(coordinate.getState(), Coordinate.EMPTY); + assertEquals(coordinate.getState(), 0); + } + + @ParameterizedTest(name = "All Getters/Setters are working") + @MethodSource("AllGettersAreWorking") + void testGetAndSetForAllStates(String testName, int state, int stateCode, int expectedResult) { + coordinate.setState(state); + int result = coordinate.getState(); + assertThat(result).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream AllGettersAreWorking() { + return Stream.of(Arguments.of("State = SHIP", 1, Coordinate.SHIP, Coordinate.SHIP), + Arguments.of("State = SHOT", 2, Coordinate.SHOT, Coordinate.SHOT), + Arguments.of("State = HIT", 3, Coordinate.HIT, Coordinate.HIT), + Arguments.of("State = EMPTY", 0, Coordinate.EMPTY, Coordinate.EMPTY)); + } + + @ParameterizedTest(name = "test if shoot function sets correct field states") + @MethodSource("ShootFunctionFieldStates") + void testShootFunctionSetsCorrectFieldStates(String testName, Coordinate coordinateToTest, int expectedState) { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + // set dummy ship + matchfield.setShip(new Coordinate(0, 0), 5, 0); + + Coordinate realCoordinate = matchfield.getField(coordinateToTest); + realCoordinate.shoot(); + int calculatedResult = realCoordinate.getState(); + assertThat(calculatedResult).describedAs(testName).isEqualTo(expectedState); + } + + static Stream ShootFunctionFieldStates() { + return Stream.of(Arguments.of("Field State is HIT", new Coordinate(0, 0), Coordinate.HIT), + Arguments.of("Field State is SHOT", new Coordinate(0, 1), Coordinate.SHOT)); + } + + @Test + void testIfShootCheckWhenFieldIsAlreadyShot() { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + // set dummy ship + matchfield.setShip(new Coordinate(3, 3), 4, 1); + + assertTrue(matchfield.getField(0, 0).shoot()); + assertFalse(matchfield.getField(0, 0).shoot()); + + matchfield.getField(3, 4).shoot(); + assertFalse(matchfield.getField(3, 4).shoot()); + } + +} diff --git a/src/test/java/de/tims/fleetstorm/matchfield/MatchfieldCreationTest.java b/src/test/java/de/tims/fleetstorm/matchfield/MatchfieldCreationTest.java new file mode 100644 index 0000000..5bda4fe --- /dev/null +++ b/src/test/java/de/tims/fleetstorm/matchfield/MatchfieldCreationTest.java @@ -0,0 +1,145 @@ + +package de.tims.fleetstorm.matchfield; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class MatchfieldCreationTest { + + @Test + void testMatchfieldCreateNotEmpty() { + Matchfield matchfield = new Matchfield(0); + Coordinate[][] calcResult = matchfield.createMatchfield(); + assertNotNull(calcResult); + } + + @ParameterizedTest(name = "matchfield creation has correct size") + @MethodSource("testMatchfieldSize") + void testMatchfieldCreationHasCorrectSize(String testName, int size, int expectedResult) { + Matchfield matchfield = new Matchfield(size); + matchfield.createMatchfield(); + + int calcResult = matchfield.getSize(); + assertThat(calcResult).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream testMatchfieldSize() { + return Stream.of(Arguments.of("field size 10x10", 10, 100), Arguments.of("field size 15x15", 15, 225)); + } + + @ParameterizedTest(name = "matchfield get field is correct") + @MethodSource("testMatchfieldGetFieldState") + void testMatchfieldGetCorrectState(String testName, int x, int y, int expectedResult) { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + int calcResult = matchfield.getState(x, y); + assertThat(calcResult).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream testMatchfieldGetFieldState() { + return Stream.of(Arguments.of("field x:0 y:0 has empty state", 0, 0, Coordinate.EMPTY)); + } + + @ParameterizedTest(name = "matchfield change field is correct") + @MethodSource("testMatchfieldSetStateIsCorrect") + void testMatchfieldGetCorrectState(String testName, int x, int y, int state, int expectedResult) { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + matchfield.setState(x, y, state); + + int calcResult = matchfield.getState(x, y); + assertThat(calcResult).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream testMatchfieldSetStateIsCorrect() { + return Stream.of( + Arguments.of("field x:0 y:0 has state SHIP after setState()", 0, 0, Coordinate.SHIP, Coordinate.SHIP)); + } + + @ParameterizedTest(name = "Get the Coordinate right") + @MethodSource("getCoordinateRight") + void testGetRight(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) { + + Coordinate result = matchfield.getRight(center); + assertThat(result).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream getCoordinateRight() { + Matchfield matchfield = new Matchfield(10); + return Stream.of( + Arguments.of("right from (5/5) - should be (6,5)", matchfield, new Coordinate(5, 5), + matchfield.getField(6, 5)), + Arguments.of("right from (9/5) - should be null", matchfield, new Coordinate(9, 5), null)); + } + + @ParameterizedTest(name = "Get the Coordinate left") + @MethodSource("getCoordinateLeft") + void testGetLeft(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) { + + Coordinate result = matchfield.getLeft(center); + assertThat(result).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream getCoordinateLeft() { + Matchfield matchfield = new Matchfield(10); + return Stream.of( + Arguments.of("left from (5/5) - should be (4,5)", matchfield, new Coordinate(5, 5), + matchfield.getField(4, 5)), + Arguments.of("left from (0/5) - should be null", matchfield, new Coordinate(0, 5), null)); + } + + @ParameterizedTest(name = "Get the Coordinate above") + @MethodSource("getCoordinateAbove") + void testGetAbove(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) { + + Coordinate result = matchfield.getAbove(center); + assertThat(result).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream getCoordinateAbove() { + Matchfield matchfield = new Matchfield(10); + return Stream.of( + Arguments.of("above from (5/5) - should be (5,6)", matchfield, new Coordinate(5, 5), + matchfield.getField(5, 6)), + Arguments.of("above from (5/9) - should be null", matchfield, new Coordinate(5, 5), null)); + } + + @ParameterizedTest(name = "Get the Coordinate below") + @MethodSource("getCoordinateBelow") + void testGetBelow(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) { + + Coordinate result = matchfield.getBelow(center); + assertThat(result).describedAs(testName).isEqualTo(expectedResult); + } + + static Stream getCoordinateBelow() { + Matchfield matchfield = new Matchfield(10); + return Stream.of( + Arguments.of("below from (5/5) - should be (5,4)", matchfield, new Coordinate(5, 5), + matchfield.getField(5, 4)), + Arguments.of("below from (5/0) - should be null", matchfield, new Coordinate(5, 0), null)); + } + + @Test + void testsetStateOverloaded() { + + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + int x = 3; + int y = 3; + matchfield.setState(new Coordinate(x, y), Coordinate.SHIP); + int result = matchfield.getState(x, y); + assertEquals(result, Coordinate.SHIP); + + } +} diff --git a/src/test/java/de/tims/fleetstorm/matchfield/MatchfieldShipTest.java b/src/test/java/de/tims/fleetstorm/matchfield/MatchfieldShipTest.java new file mode 100644 index 0000000..665f367 --- /dev/null +++ b/src/test/java/de/tims/fleetstorm/matchfield/MatchfieldShipTest.java @@ -0,0 +1,133 @@ + +package de.tims.fleetstorm.matchfield; + +import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class MatchfieldShipTest { + + @ParameterizedTest(name = "ship was set on the correct positions") + @MethodSource("testShipPositioning") + void testMatchfieldShipSetHasCorrectPositions(String testName, int matchfieldSize, Coordinate coordinate, + int direction, int length, Coordinate[] coordinatesWithShip) { + Matchfield matchfield = new Matchfield(matchfieldSize); + matchfield.createMatchfield(); + + matchfield.setShip(coordinate, length, direction); + + int shipSetCounter = 0; + for (Coordinate toCheckCoordinate : coordinatesWithShip) { + if (matchfield.getField(toCheckCoordinate).getState() == Coordinate.SHIP) + shipSetCounter++; + } + + assertThat(shipSetCounter).describedAs(testName).isEqualTo(length); + } + + static Stream testShipPositioning() { + Coordinate[] coordinatesWithShip00_2_0 = new Coordinate[] { new Coordinate(0, 0), new Coordinate(1, 0) }; + Coordinate[] coordinatesWithShip01_3_0 = new Coordinate[] { new Coordinate(0, 1), new Coordinate(1, 1), + new Coordinate(2, 1) }; + Coordinate[] coordinatesWithShip02_4_1 = new Coordinate[] { new Coordinate(0, 2), new Coordinate(0, 3), + new Coordinate(0, 4), new Coordinate(0, 5) }; + + return Stream.of( + Arguments.of("set ship from 0:0, length 2, direction 0", 10, new Coordinate(0, 0), 0, 2, + coordinatesWithShip00_2_0), + Arguments.of("set ship from 0:1, length 3, direction 0", 10, new Coordinate(0, 1), 0, 3, + coordinatesWithShip01_3_0), + Arguments.of("set ship from 0:2, length 4, direction 1", 10, new Coordinate(0, 2), 1, 4, + coordinatesWithShip02_4_1)); + } + + @ParameterizedTest(name = "ship positioning on invalid or valid coordinates") + @MethodSource("testShipPositioningFailed") + void testMatchfieldShipSetWithInvalidOrValidCoordinates(String testName, int matchfieldSize, Coordinate coordinate, + int direction, int length, boolean expectedResult) { + Matchfield matchfield = new Matchfield(matchfieldSize); + matchfield.createMatchfield(); + + boolean calculatedResult = matchfield.setShip(coordinate, length, direction); + + if (expectedResult) + assertThat(calculatedResult).describedAs(testName).isEqualTo(true); + + if (!expectedResult) + assertThat(calculatedResult).describedAs(testName).isEqualTo(false); + } + + static Stream testShipPositioningFailed() { + return Stream.of( + Arguments.of("invalid ship position from 9:0, length 2, direction 0", 10, new Coordinate(9, 0), 0, 2, + false), + Arguments.of("valid ship position from 8:0, length 5, direction 1", 10, new Coordinate(9, 0), 1, 5, + true)); + } + + @Test + void testShipPositionAlreadySetWithShip() { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + matchfield.setShip(new Coordinate(0, 0), 5, 1); + assertThat(matchfield.setShip(new Coordinate(0, 1), 5, 1)).describedAs("set ship on coordinate with ship") + .isEqualTo(false); + + assertThat(matchfield.setShip(new Coordinate(1, 1), 4, 0)).describedAs("set ship on coordinate without ship") + .isEqualTo(true); + assertThat(matchfield.setShip(new Coordinate(4, 1), 2, 1)) + .describedAs("set second ship on coordinate without ship").isEqualTo(false); + } + + @Test + void testIfAllShipsHitReturnsFalseWhenNoShipIsHit() { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + matchfield.setShip(new Coordinate(0, 0), 5, 1); + boolean calulatedResult = matchfield.areAllShipsHit(); + assertFalse(calulatedResult); + } + + @Test + void testIfAllShipsHitReturnsTrueWhenAllShipsAreHit() { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + matchfield.setShip(new Coordinate(0, 0), 5, 1); + matchfield.getField(0, 0).setState(Coordinate.HIT); + matchfield.getField(0, 1).setState(Coordinate.HIT); + matchfield.getField(0, 2).setState(Coordinate.HIT); + matchfield.getField(0, 3).setState(Coordinate.HIT); + matchfield.getField(0, 4).setState(Coordinate.HIT); + + boolean calulatedResult = matchfield.areAllShipsHit(); + assertTrue(calulatedResult); + } + + @Test + void testIfAllShipsHitReturnsFalseWhenTwoShipsAreNotFullyHit() { + Matchfield matchfield = new Matchfield(10); + matchfield.createMatchfield(); + + matchfield.setShip(new Coordinate(0, 0), 5, 1); + matchfield.getField(0, 0).setState(Coordinate.HIT); + matchfield.getField(0, 1).setState(Coordinate.HIT); + matchfield.getField(0, 2).setState(Coordinate.HIT); + matchfield.getField(0, 3).setState(Coordinate.HIT); + matchfield.getField(0, 4).setState(Coordinate.HIT); + + matchfield.setShip(new Coordinate(3, 4), 2, 0); + matchfield.getField(4, 4).setState(Coordinate.HIT); + + boolean calulatedResult = matchfield.areAllShipsHit(); + assertFalse(calulatedResult); + } +}