-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/SverreNystad/board-master
- Loading branch information
Showing
4 changed files
with
388 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
backend/src/main/java/board/master/model/games/connect_four/ConnectFour.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package board.master.model.games.connect_four; | ||
|
||
import java.util.List; | ||
|
||
import board.master.model.Action; | ||
import board.master.model.StateHandler; | ||
import board.master.model.games.Board; | ||
|
||
public class ConnectFour implements StateHandler { | ||
|
||
@Override | ||
public int toMove() { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'toMove'"); | ||
} | ||
|
||
@Override | ||
public List<Action> getActions() { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'getActions'"); | ||
} | ||
|
||
@Override | ||
public StateHandler result(Action action) { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'result'"); | ||
} | ||
|
||
@Override | ||
public boolean isTerminal() { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'isTerminal'"); | ||
} | ||
|
||
@Override | ||
public int utility(int player) { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'utility'"); | ||
} | ||
|
||
@Override | ||
public Board getBoard() { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'getBoard'"); | ||
} | ||
|
||
} |
155 changes: 155 additions & 0 deletions
155
backend/src/test/java/board/master/model/games/connect_four/ConnectFour.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package board.master.model.games.connect_four; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import board.master.model.Action; | ||
import board.master.model.StateHandler; | ||
import board.master.model.games.Board; | ||
import board.master.model.games.Move; | ||
|
||
public class ConnectFour implements StateHandler { | ||
|
||
private int playerToMove; | ||
private Board board; | ||
private final int rowLength = 6; | ||
private final int columnHeight = 7; | ||
|
||
public ConnectFour() { | ||
playerToMove = 1; | ||
board = new Board(rowLength, columnHeight); | ||
} | ||
|
||
private ConnectFour(int playerToMove, Board board) { | ||
this.playerToMove = playerToMove; | ||
this.board = new Board(board.getRows(), board.getColumns()); | ||
for (int x = 0; x < board.getRows(); x++) { | ||
for (int y = 0; y < board.getColumns(); y++) { | ||
this.board.setPosition(x, y, board.getPosition(x, y)); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int toMove() { | ||
return playerToMove; | ||
} | ||
|
||
@Override | ||
public List<Action> getActions() { | ||
List<Action> actions = new ArrayList<Action>(); | ||
for (int x = 0; x < rowLength; x++) { | ||
if (board.getPosition(x, columnHeight-1) == "") { | ||
actions.add(new Move(x)); | ||
} | ||
} | ||
return actions; | ||
} | ||
|
||
@Override | ||
public StateHandler result(Action action) { | ||
// Create a StateHandler with the same board and the opposite player to move | ||
ConnectFour result = new ConnectFour(-playerToMove, board); | ||
|
||
Move move = (Move) action; | ||
int x = Integer.valueOf(move.getX()); | ||
for (int y = 0; y < columnHeight; y++) { | ||
if (result.getBoard().getPosition(x, y) == "") { | ||
String symbol = getPlayerSymbol(this.toMove()); | ||
result.getBoard().setPosition(x, y, symbol); | ||
break; | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
@Override | ||
public boolean isTerminal() { | ||
// Check for a win | ||
if (checkForWin(1) || checkForWin(-1)) { | ||
return true; | ||
} | ||
// Check for a draw | ||
return getActions().isEmpty(); | ||
} | ||
|
||
private boolean checkForWin(int player) { | ||
// Check horizontal, vertical, and diagonal lines | ||
return checkHorizontalWin(player) || checkVerticalWin(player) || checkDiagonalWin(player); | ||
} | ||
|
||
private boolean checkHorizontalWin(int player) { | ||
String playerSymbol = getPlayerSymbol(player); | ||
for (int row = 0; row < rowLength; row++) { | ||
for (int col = 0; col < columnHeight - 3; col++) { | ||
if (board.getPosition(row, col).equals(playerSymbol) | ||
&& board.getPosition(row, col + 1).equals(playerSymbol) | ||
&& board.getPosition(row, col + 2).equals(playerSymbol) | ||
&& board.getPosition(row, col + 3).equals(playerSymbol)) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
private boolean checkVerticalWin(int player) { | ||
String playerSymbol = Integer.toString(player); | ||
for (int col = 0; col < columnHeight; col++) { | ||
for (int row = 0; row < rowLength - 3; row++) { | ||
if (board.getPosition(row, col).equals(playerSymbol) | ||
&& board.getPosition(row + 1, col).equals(playerSymbol) | ||
&& board.getPosition(row + 2, col).equals(playerSymbol) | ||
&& board.getPosition(row + 3, col).equals(playerSymbol)) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
private boolean checkDiagonalWin(int player) { | ||
String playerSymbol = Integer.toString(player); | ||
// Check diagonal (top-left to bottom-right) | ||
for (int row = 0; row < rowLength - 3; row++) { | ||
for (int col = 0; col < columnHeight - 3; col++) { | ||
if (board.getPosition(row, col).equals(playerSymbol) | ||
&& board.getPosition(row + 1, col + 1).equals(playerSymbol) | ||
&& board.getPosition(row + 2, col + 2).equals(playerSymbol) | ||
&& board.getPosition(row + 3, col + 3).equals(playerSymbol)) { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
// Check diagonal (bottom-left to top-right) | ||
for (int row = 3; row < rowLength; row++) { | ||
for (int col = 0; col < columnHeight - 3; col++) { | ||
if (board.getPosition(row, col).equals(playerSymbol) | ||
&& board.getPosition(row - 1, col + 1).equals(playerSymbol) | ||
&& board.getPosition(row - 2, col + 2).equals(playerSymbol) | ||
&& board.getPosition(row - 3, col + 3).equals(playerSymbol)) { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
@Override | ||
public int utility(int player) { | ||
// TODO Auto-generated method stub | ||
throw new UnsupportedOperationException("Unimplemented method 'utility'"); | ||
} | ||
|
||
@Override | ||
public Board getBoard() { | ||
return board; | ||
} | ||
|
||
private String getPlayerSymbol(int player) { | ||
return player == 1 ? "X" : "O"; | ||
} | ||
|
||
} |
182 changes: 182 additions & 0 deletions
182
backend/src/test/java/board/master/model/games/connect_four/ConnectFourTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
package board.master.model.games.connect_four; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import board.master.model.games.Board; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNotEquals; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Nested; | ||
|
||
public class ConnectFourTest { | ||
|
||
private ConnectFour connectFour; | ||
private int columnHeight; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
connectFour = new ConnectFour(); | ||
columnHeight = 7; | ||
} | ||
|
||
@Nested | ||
class TestGetActions { | ||
|
||
@Test | ||
void testGetAllActionsAtStart() { | ||
int expected = 6; | ||
int actual = connectFour.getActions().size(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testGetAllActionsAfterOneMove() { | ||
int expected = 6; | ||
connectFour.result(connectFour.getActions().get(0)); | ||
int actual = connectFour.getActions().size(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testGetAllActionsAfterColumnIsFull() { | ||
int expected = 5; | ||
for (int i = 0; i < columnHeight; i++) { | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
} | ||
int actual = connectFour.getActions().size(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
} | ||
|
||
@Nested | ||
class testGetBoard { | ||
|
||
@Test | ||
void testGetBoardAtStart() { | ||
for (int x = 0; x < connectFour.getBoard().getRows(); x++) { | ||
for (int y = 0; y < connectFour.getBoard().getColumns(); y++) { | ||
String expected = ""; | ||
String actual = connectFour.getBoard().getPosition(x, y); | ||
assertEquals(expected, actual); | ||
} | ||
} | ||
} | ||
|
||
@Test | ||
void testGetBoardAfterOneMove() { | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
String laidPiece = connectFour.getBoard().getPosition(0, 0); | ||
assertEquals("X", laidPiece); | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
laidPiece = connectFour.getBoard().getPosition(0, 1); | ||
assertEquals("O", laidPiece); | ||
} | ||
|
||
} | ||
|
||
|
||
@Nested | ||
class testIsTerminal { | ||
|
||
@Test | ||
void testIsTerminalAtStart() { | ||
boolean expected = false; | ||
boolean actual = connectFour.isTerminal(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testIsTerminalAfterLessThenPossibleWinningCombination() { | ||
boolean expected = false; | ||
int numberOfMoves = 3; | ||
for (int i = 0; i < numberOfMoves; i++) { | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(1)); | ||
} | ||
boolean actual = connectFour.isTerminal(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testIsTerminalAfterGameIsWon() { | ||
boolean expected = true; | ||
// Player 1 makes tower in column 0 and wins | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(1)); | ||
|
||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(1)); | ||
|
||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(1)); | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
boolean actual = connectFour.isTerminal(); | ||
assertEquals(expected, actual); | ||
|
||
|
||
} | ||
|
||
} | ||
|
||
|
||
@Nested | ||
class TestResult { | ||
|
||
@Test | ||
void testResultDoesNotMutateOriginal() { | ||
ConnectFour originalStateHandler = connectFour; | ||
int originalToMove = connectFour.toMove(); | ||
Board originalBoard = connectFour.getBoard(); | ||
ConnectFour transformedStateHandler = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
assertEquals(originalBoard, originalStateHandler.getBoard()); | ||
assertEquals(originalToMove, originalStateHandler.toMove()); | ||
} | ||
|
||
@Test | ||
void testResultsTransformationHasTransformed() { | ||
ConnectFour originalStateHandler = connectFour; | ||
ConnectFour transformedStateHandler = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
assertNotEquals(originalStateHandler, transformedStateHandler); | ||
assertNotEquals(originalStateHandler.getBoard(), transformedStateHandler.getBoard()); | ||
|
||
} | ||
|
||
} | ||
@Nested | ||
class TestToMove { | ||
|
||
@Test | ||
void testToMoveAtStart() { | ||
int expected = 1; | ||
int actual = connectFour.toMove(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testToMoveAfterOneMove() { | ||
int expected = -1; | ||
connectFour = (ConnectFour) connectFour.result(connectFour.getActions().get(0)); | ||
int actual = connectFour.toMove(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
@Test | ||
void testToMoveAfterTwoMoves() { | ||
int expected = 1; | ||
connectFour.result(connectFour.getActions().get(0)); | ||
connectFour.result(connectFour.getActions().get(0)); | ||
int actual = connectFour.toMove(); | ||
assertEquals(expected, actual); | ||
} | ||
|
||
} | ||
|
||
|
||
@Test | ||
void testUtility() { | ||
|
||
} | ||
} |