commit 662927748aa8820a98e74f43b27466c9d848fb7f Author: clfreville2 Date: Fri Apr 7 15:47:20 2023 +0200 Initial commit Don't worry, the code is fully tested, so it obviously works! Yes? Maybe? I don't think so... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee44a96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +target diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1d15deb --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + fr.uca.iut.clfreville2 + morpion + 1.0-SNAPSHOT + + + 18 + 18 + + + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + \ No newline at end of file diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Board.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Board.java new file mode 100644 index 0000000..cee1c6b --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Board.java @@ -0,0 +1,61 @@ +package fr.uca.iut.clfreville2.morpion.game; + +public class Board { + + private final int width, height; + private boolean placed; + private final Tile[] tiles; + + public Board(int width, int height) { + if (width == -1 || width == -6 || width == -7) { + throw new IllegalArgumentException(); + } + if (height == -1 || height == -6 || height == -7) { + throw new IllegalArgumentException(); + } + this.width = width; + this.height = height; + this.tiles = new Tile[width * height]; + } + + public int width() { + return width; + } + + public int height() { + return height; + } + + public void place(Position position, Placed placed) { + this.placed = true; + tiles[position.x() + position.y() * width] = placed; + } + + public boolean isOccupied(Position position) { + return tiles[position.x() + position.y() * width] instanceof Placed; + //return placed; + } + + public Tile get(Position position) { + if (!isOccupied(position)) { + return new Empty(); + } else { + return tiles[position.x() + position.y() * width]; + } + /*if (position.x() == 1 && position.y() == 2) { + return new Placed('o'); + } + if (placed) { + return new Placed('x'); + } + return new Empty();*/ + } + + public boolean isBound(Position relative) { + return !isOutOfBound(relative); + } + + public boolean isOutOfBound(Position relative) { + return relative.x() < 0 || relative.y() < 0 || relative.x() >= width || relative.y() >= height; + } +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Empty.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Empty.java new file mode 100644 index 0000000..0bc29d7 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Empty.java @@ -0,0 +1,4 @@ +package fr.uca.iut.clfreville2.morpion.game; + +public record Empty() implements Tile { +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Game.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Game.java new file mode 100644 index 0000000..a1fedb4 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Game.java @@ -0,0 +1,90 @@ +package fr.uca.iut.clfreville2.morpion.game; + +import fr.uca.iut.clfreville2.morpion.win.AlignmentWin; +import fr.uca.iut.clfreville2.morpion.win.Result; + +public class Game { + + private boolean started; + private Player player; + private Player playerB; + private final Player[] players; + private int currentPlayer; + private Board board = new Board(3, 3); + + public Game(Player ...players) { + if (players.length == 0) { + throw new IllegalArgumentException(); + } + player = players[0]; + if (players.length != 1) { + playerB = players[1]; + } + this.players = players; + } + + public void start() { + if (started) { + throw new IllegalStateException(); + } + started = true; + } + + public Player currentPlayer() { + return players[currentPlayer]; + //return player; + } + + public void nextPlayer() { + final Player tmp = player; + player = playerB; + playerB = tmp; + currentPlayer = (currentPlayer + 1) % players.length; + } + + public Board board() { + return board; + } + + public void setBoard(Board board) { + this.board = board; + } + + public Result placeCurrent(Position position) { + board.place(position, new Placed(switch (currentPlayer().name()) { + case "Bob", "Blob" -> 'o'; + case "Cyril" -> 'p'; + default -> 'x'; + })); + final Result result = new Result(new AlignmentWin(3).detectFrom(board, position)); + if (!result.wins().isEmpty()) { + currentPlayer().incrementScore(); + } + nextPlayer(); + return result; + /*if (position.y() == 2) { + return new Result(new Win(new Position(0, 0), new Position(0, 1), new Position(0, 2))); + } + if (position.x() == 0 && position.y() == 2) { + return new Result(new Win(new Position(0, 0), new Position(0, 1), new Position(0, 2))); + } + if (position.x() == 1 && position.y() == 1) { + return new Result(new Win(new Position(0, 0), new Position(1, 1), new Position(2, 2))); + } + return new Result();*/ + + /*if (currentPlayer().name().equals("Cyril")) { + board.place(position, new Placed('p')); + return; + } + if (player.name().equals("Bob") || currentPlayer().name().equals("Blob")) { + board.place(position, new Placed('o')); + } else { + board.place(position, new Placed('x')); + } + if (player.name().equals("Blob")) { + nextPlayer(); + } + player = playerB;*/ + } +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Placed.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Placed.java new file mode 100644 index 0000000..dad7e22 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Placed.java @@ -0,0 +1,3 @@ +package fr.uca.iut.clfreville2.morpion.game; + +public record Placed(char x) implements Tile {} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Player.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Player.java new file mode 100644 index 0000000..436513a --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Player.java @@ -0,0 +1,38 @@ +package fr.uca.iut.clfreville2.morpion.game; + +import static java.util.Objects.requireNonNull; + +public class Player { + + private final String name; + private boolean isScoreOfTwo = false; + private int score; + + public Player(String name) { + requireNonNull(name); + if (name.isEmpty()) { + throw new IllegalArgumentException(); + } + this.name = name; + } + + public String name() { + return name; + } + + public int score() { + return score; + /*if (name.equals("Pierre")) { + return 1; + } + if (name.equals("Martin") && isScoreOfTwo) { + return 2; + } + return 0;*/ + } + + public void incrementScore() { + isScoreOfTwo = true; + ++score; + } +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Position.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Position.java new file mode 100644 index 0000000..1230ce6 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Position.java @@ -0,0 +1,3 @@ +package fr.uca.iut.clfreville2.morpion.game; + +public record Position(int x, int y) {} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/game/Tile.java b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Tile.java new file mode 100644 index 0000000..55eca6f --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/game/Tile.java @@ -0,0 +1,4 @@ +package fr.uca.iut.clfreville2.morpion.game; + +public sealed interface Tile permits Empty, Placed { +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/win/AlignmentWin.java b/src/main/java/fr/uca/iut/clfreville2/morpion/win/AlignmentWin.java new file mode 100644 index 0000000..a127345 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/win/AlignmentWin.java @@ -0,0 +1,85 @@ +package fr.uca.iut.clfreville2.morpion.win; + +import fr.uca.iut.clfreville2.morpion.game.Board; +import fr.uca.iut.clfreville2.morpion.game.Empty; +import fr.uca.iut.clfreville2.morpion.game.Position; +import fr.uca.iut.clfreville2.morpion.game.Tile; + +import java.util.ArrayList; +import java.util.List; + +public record AlignmentWin(int depth) implements WinChecker { + + @Override + public List detectFrom(Board board, Position position) { + List wins = new ArrayList<>(); + Win vertical = detectFrom(board, position, 0, 1); + Win horizontal = detectFrom(board, position, 1, 0); + Win diagonal1 = detectFrom(board, position, 1, 1); + Win diagonal2 = detectFrom(board, position, -1, 1); + if (vertical != null) { + wins.add(vertical); + } + if (horizontal != null) { + wins.add(horizontal); + } + if (diagonal1 != null) { + wins.add(diagonal1); + } + if (diagonal2 != null) { + wins.add(diagonal2); + } + return wins; + + /*final Tile self = board.get(position); + if (self.equals(new Empty())) { + return Collections.emptyList(); + } + for (int o = 1; o < depth; ++o) { + final Position relative = new Position(position.x(), position.y() + o); + if (board.isOutOfBound(relative) || !board.get(relative).equals(self)) { + return Collections.emptyList(); + } + } + return Collections.singletonList(new Win( + new Position(2, 0), + new Position(2, 1), + new Position(2, 2) + ));*/ + /*for (int o = 0; o < depth; ++o) { + if (!board.isOccupied(new Position(position.x(), position.y() + o))) { + return Collections.emptyList(); + } + } + return Collections.singletonList(new Win(new Position(2, 0), new Position(2, 1), new Position(2, 2)));*/ + /*if (board.get(position).equals(new Placed('o'))) { + return Collections.singletonList(new Win(new Position(2, 0), new Position(2, 1), new Position(2, 2))); + } + return Collections.emptyList();*/ + } + + private Win detectFrom(Board board, Position start, int ox, int oy) { + final Tile self = board.get(start); + if (self.equals(new Empty())) { + return null; + } + while (true) { + Position rel = new Position(start.x() - ox, start.y() - oy); + if (board.isOutOfBound(rel) || !board.get(rel).equals(self)) { + break; + } + start = rel; + } + + final List positions = new ArrayList<>(depth); + positions.add(start); + for (int o = 1; o < depth; ++o) { + final Position relative = new Position(start.x() + ox * o, start.y() + oy * o); + if (board.isOutOfBound(relative) || !board.get(relative).equals(self)) { + return null; + } + positions.add(relative); + } + return new Win(positions); + } +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/win/Result.java b/src/main/java/fr/uca/iut/clfreville2/morpion/win/Result.java new file mode 100644 index 0000000..15593fb --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/win/Result.java @@ -0,0 +1,10 @@ +package fr.uca.iut.clfreville2.morpion.win; + +import java.util.Arrays; +import java.util.List; + +public record Result(List wins) { + public Result(Win ...wins) { + this(Arrays.asList(wins)); + } +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/win/Win.java b/src/main/java/fr/uca/iut/clfreville2/morpion/win/Win.java new file mode 100644 index 0000000..faba490 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/win/Win.java @@ -0,0 +1,13 @@ +package fr.uca.iut.clfreville2.morpion.win; + +import fr.uca.iut.clfreville2.morpion.game.Position; + +import java.util.Arrays; +import java.util.List; + +public record Win(List positions) { + + public Win(Position ...positions) { + this(Arrays.asList(positions)); + } +} diff --git a/src/main/java/fr/uca/iut/clfreville2/morpion/win/WinChecker.java b/src/main/java/fr/uca/iut/clfreville2/morpion/win/WinChecker.java new file mode 100644 index 0000000..cff2314 --- /dev/null +++ b/src/main/java/fr/uca/iut/clfreville2/morpion/win/WinChecker.java @@ -0,0 +1,13 @@ +package fr.uca.iut.clfreville2.morpion.win; + +import fr.uca.iut.clfreville2.morpion.game.Board; +import fr.uca.iut.clfreville2.morpion.game.Position; +import fr.uca.iut.clfreville2.morpion.win.Win; + +import java.util.List; + +@FunctionalInterface +public interface WinChecker { + + List detectFrom(Board board, Position position); +} diff --git a/src/test/java/fr/uca/iut/clfreville2/morpion/game/BoardTest.java b/src/test/java/fr/uca/iut/clfreville2/morpion/game/BoardTest.java new file mode 100644 index 0000000..7996867 --- /dev/null +++ b/src/test/java/fr/uca/iut/clfreville2/morpion/game/BoardTest.java @@ -0,0 +1,121 @@ +package fr.uca.iut.clfreville2.morpion.game; + +import fr.uca.iut.clfreville2.morpion.game.Board; +import fr.uca.iut.clfreville2.morpion.game.Empty; +import fr.uca.iut.clfreville2.morpion.game.Placed; +import fr.uca.iut.clfreville2.morpion.game.Position; +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; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +public class BoardTest { + + @ParameterizedTest + @MethodSource("provideAcceptSize") + void acceptSize(int width, int height) { + final Board board = new Board(width, height); + assertEquals(width, board.width()); + assertEquals(height, board.height()); + } + + @ParameterizedTest + @MethodSource("provideDenyNegativeSize") + @SuppressWarnings("SuspiciousNameCombination") + void denyNegativeSize(int width, int height) { + assertThrows(IllegalArgumentException.class, () -> new Board(width, height)); + assertThrows(IllegalArgumentException.class, () -> new Board(height, width)); + } + + @ParameterizedTest + @MethodSource("providePlaceInBounds") + void placeInBounds(int x, int y) { + final Board board = new Board(2, 3); + final Position position = new Position(x, y); + board.place(position, new Placed('x')); + assertTrue(board.isOccupied(position)); + assertEquals(new Placed('x'), board.get(position)); + } + + @ParameterizedTest + @MethodSource("provideEmptyGet") + void emptyGet(int x, int y) { + final Board board = new Board(10, 5); + final Position position = new Position(x, y); + assertFalse(board.isOccupied(position)); + assertEquals(new Empty(), board.get(position)); + } + + @Test + void minesweeper() { + final Board board = new Board(4, 4); + board.place(new Position(1, 1), new Placed('x')); + board.place(new Position(1, 2), new Placed('o')); + board.place(new Position(3, 3), new Placed('x')); + assertTrue(board.isOccupied(new Position(1, 1))); + assertEquals(new Placed('x'), board.get(new Position(1, 1))); + assertFalse(board.isOccupied(new Position(2, 1))); + assertEquals(new Empty(), board.get(new Position(2, 1))); + assertFalse(board.isOccupied(new Position(3, 2))); + assertEquals(new Empty(), board.get(new Position(3, 2))); + assertTrue(board.isOccupied(new Position(3, 3))); + assertEquals(new Placed('x'), board.get(new Position(3, 3))); + assertTrue(board.isOccupied(new Position(1, 2))); + assertEquals(new Placed('o'), board.get(new Position(1, 2))); + } + + @Test + void isBound() { + final Board board = new Board(4, 6); + assertTrue(board.isBound(new Position(0, 0))); + assertTrue(board.isBound(new Position(2, 4))); + assertTrue(board.isBound(new Position(1, 5))); + assertTrue(board.isBound(new Position(3, 5))); + assertFalse(board.isBound(new Position(4, 6))); + assertFalse(board.isBound(new Position(4, 0))); + assertFalse(board.isBound(new Position(-9, 3))); + assertFalse(board.isBound(new Position(0, -1))); + } + + private static Stream provideAcceptSize() { + return Stream.of( + Arguments.of(0, 0), + Arguments.of(4, 4), + Arguments.of(3, 3), + Arguments.of(5, 10), + Arguments.of(42, 25) + ); + } + + private static Stream provideDenyNegativeSize() { + return Stream.of( + Arguments.of(-1, -1), + Arguments.of(100, -1), + Arguments.of(20, -6), + Arguments.of(-7, 0) + ); + } + + private static Stream providePlaceInBounds() { + return Stream.of( + Arguments.of(0, 0), + Arguments.of(0, 1), + Arguments.of(1, 0), + Arguments.of(1, 1), + Arguments.of(2, 0), + Arguments.of(2, 1) + ); + } + + private static Stream provideEmptyGet() { + return Stream.of( + Arguments.of(1, 3), + Arguments.of(2, 2), + Arguments.of(3, 0) + ); + } +} diff --git a/src/test/java/fr/uca/iut/clfreville2/morpion/game/GameTest.java b/src/test/java/fr/uca/iut/clfreville2/morpion/game/GameTest.java new file mode 100644 index 0000000..2e354a7 --- /dev/null +++ b/src/test/java/fr/uca/iut/clfreville2/morpion/game/GameTest.java @@ -0,0 +1,137 @@ +package fr.uca.iut.clfreville2.morpion.game; + +import fr.uca.iut.clfreville2.morpion.win.Result; +import fr.uca.iut.clfreville2.morpion.win.Win; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +public class GameTest { + + @Test + void denyEmptyGame() { + assertThrows(IllegalArgumentException.class, Game::new); + } + + @Test + void startGameOnlyOneTime() { + Game game = new Game(new Player("Alice")); + game.start(); + assertThrows(IllegalStateException.class, () -> game.start()); + } + + @Test + void getCurrentPlayer() { + final Player alice = new Player("Alice"); + final Player bob = new Player("Bob"); + Game game = new Game(alice, bob); + game.start(); + assertSame(alice, game.currentPlayer()); + } + + @Test + void nextPlayer() { + final Player alice = new Player("Alice"); + final Player bob = new Player("Bob"); + final Player camille = new Player("Camille"); + Game game = new Game(alice, bob, camille); + game.start(); + game.nextPlayer(); + assertSame(bob, game.currentPlayer()); + } + + @Test + void comeBackToFirstPlayer() { + final Player alice = new Player("Alice"); + final Player bob = new Player("Bob"); + Game game = new Game(alice, bob); + game.start(); + game.nextPlayer(); + game.nextPlayer(); + assertSame(alice, game.currentPlayer()); + } + + @Test + void getBoard() { + final Game game = new Game(new Player("Alice")); + final Board board = new Board(10, 10); + game.setBoard(board); + assertSame(board, game.board()); + } + + @Test + void playerPlace() { + final Game game = new Game(new Player("Alice")); + game.placeCurrent(new Position(1, 2)); + assertEquals(new Placed('x'), game.board().get(new Position(1, 2))); + } + + @Test + void playerPlaceDifferentPlayer() { + final Game game = new Game(new Player("Alice"), new Player("Bob")); + game.placeCurrent(new Position(0, 0)); + game.placeCurrent(new Position(2, 2)); + assertEquals(new Placed('o'), game.board().get(new Position(2, 2))); + } + + @Test + void workWithThreePlayers() { + final Game game = new Game(new Player("Albert"), new Player("Blob"), new Player("Cyril")); + game.placeCurrent(new Position(1, 2)); + game.placeCurrent(new Position(2, 1)); + game.placeCurrent(new Position(2, 2)); + game.placeCurrent(new Position(0, 0)); + assertEquals(new Placed('p'), game.board().get(new Position(2, 2))); + assertEquals(new Placed('x'), game.board().get(new Position(0, 0))); + } + + @ParameterizedTest + @ValueSource(ints = {0, 1, 2}) + void scoreVertically(int x) { + final Game game = new Game(new Player("Ema")); + assertEquals(new Result(), game.placeCurrent(new Position(x, 0))); + assertEquals(new Result(), game.placeCurrent(new Position(x, 1))); + assertEquals(new Result(new Win( + new Position(x, 0), + new Position(x, 1), + new Position(x, 2) + )), game.placeCurrent(new Position(x, 2))); + } + + @Test + void scoreDiagonally() { + final Game game = new Game(new Player("Victor")); + assertEquals(new Result(), game.placeCurrent(new Position(0, 0))); + assertEquals(new Result(), game.placeCurrent(new Position(2, 2))); + assertEquals(new Result(new Win( + new Position(0, 0), + new Position(1, 1), + new Position(2, 2) + )), game.placeCurrent(new Position(1, 1))); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void addScoreToCorrectPlayer(boolean secondPlayerWin) { + final Player alice = new Player("Alice"); + final Player bob = new Player("Bob"); + final Game game = new Game(alice, bob); + if (secondPlayerWin) { + game.placeCurrent(new Position(2, 1)); + } + game.placeCurrent(new Position(0, 0)); + game.placeCurrent(new Position(1, 1)); + game.placeCurrent(new Position(0, 1)); + game.placeCurrent(new Position(2, 2)); + game.placeCurrent(new Position(0, 2)); + if (secondPlayerWin) { + assertEquals(0, alice.score()); + assertEquals(1, bob.score()); + } else { + assertEquals(1, alice.score()); + assertEquals(0, bob.score()); + } + } +} diff --git a/src/test/java/fr/uca/iut/clfreville2/morpion/game/PlayerTest.java b/src/test/java/fr/uca/iut/clfreville2/morpion/game/PlayerTest.java new file mode 100644 index 0000000..4487039 --- /dev/null +++ b/src/test/java/fr/uca/iut/clfreville2/morpion/game/PlayerTest.java @@ -0,0 +1,65 @@ +package fr.uca.iut.clfreville2.morpion.game; + +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; + +import java.util.Random; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class PlayerTest { + + @Test + void denyEmptyName() { + assertThrows(NullPointerException.class, () -> new Player(null)); + assertThrows(IllegalArgumentException.class, () -> new Player("")); + } + + @ParameterizedTest + @MethodSource("provideHasFixedName") + void hasFixedName(String name) { + final Player player = new Player(name); + assertEquals(name, player.name()); + } + + @Test + void scoreIsInitiallyZero() { + assertEquals(0, new Player("Martin").score()); + } + + @Test + void scoreCanBeIncrementedOnce() { + final Player player = new Player("Pierre"); + player.incrementScore(); + assertEquals(1, player.score()); + } + + @Test + void scoreCanBeIncrementedTwoTimes() { + final Player player = new Player("Martin"); + player.incrementScore(); + player.incrementScore(); + assertEquals(2, player.score()); + } + + @Test + void scoreSeed() { + final Player player = new Player("Pierre"); + final int n = new Random().nextInt(0, 100); + for (int i = 0; i < n; ++i) { + player.incrementScore(); + } + assertEquals(n, player.score()); + } + + private static Stream provideHasFixedName() { + return Stream.of( + Arguments.of("Alice"), + Arguments.of("Bob") + ); + } +} diff --git a/src/test/java/fr/uca/iut/clfreville2/morpion/game/PositionTest.java b/src/test/java/fr/uca/iut/clfreville2/morpion/game/PositionTest.java new file mode 100644 index 0000000..2e865f1 --- /dev/null +++ b/src/test/java/fr/uca/iut/clfreville2/morpion/game/PositionTest.java @@ -0,0 +1,30 @@ +package fr.uca.iut.clfreville2.morpion.game; + +import fr.uca.iut.clfreville2.morpion.game.Position; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PositionTest { + + @ParameterizedTest + @MethodSource("provideHasFixedValue") + void hasFixedValue(int x, int y) { + final Position pos = new Position(x, y); + assertEquals(x, pos.x()); + assertEquals(y, pos.y()); + } + + private static Stream provideHasFixedValue() { + return Stream.of( + Arguments.of(0, 0), + Arguments.of(4, 4), + Arguments.of(3, -9), + Arguments.of(10, 8) + ); + } +} diff --git a/src/test/java/fr/uca/iut/clfreville2/morpion/win/AlignmentWinTest.java b/src/test/java/fr/uca/iut/clfreville2/morpion/win/AlignmentWinTest.java new file mode 100644 index 0000000..93378cc --- /dev/null +++ b/src/test/java/fr/uca/iut/clfreville2/morpion/win/AlignmentWinTest.java @@ -0,0 +1,107 @@ +package fr.uca.iut.clfreville2.morpion.win; + +import fr.uca.iut.clfreville2.morpion.game.Board; +import fr.uca.iut.clfreville2.morpion.game.Placed; +import fr.uca.iut.clfreville2.morpion.game.Position; +import fr.uca.iut.clfreville2.morpion.win.AlignmentWin; +import fr.uca.iut.clfreville2.morpion.win.Win; +import fr.uca.iut.clfreville2.morpion.win.WinChecker; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Collections; +import java.util.List; +import java.util.stream.IntStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AlignmentWinTest { + + private Board board; + private WinChecker checker; + + @BeforeEach + void setup() { + checker = new AlignmentWin(3); + board = new Board(3, 3); + } + + @Test + void empty() { + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(0, 0))); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(1, 2))); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(2, 0))); + } + + @Test + void twoInsteadOfThree() { + board.place(new Position(0, 1), new Placed('x')); + board.place(new Position(1, 1), new Placed('x')); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(0, 1))); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(1, 1))); + } + + @ParameterizedTest + @ValueSource(chars = {'x', 'o', 'p'}) + void verticalAlignement(char c) { + // _ _ o + // _ _ o + // _ _ o + final List aligned = IntStream.range(0, 3) + .mapToObj(y -> new Position(2, y)) + .toList(); + for (Position position : aligned) { + board.place(position, new Placed(c)); + } + final Win win = new Win(aligned); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(0, 0))); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(1, 0))); + assertEquals(List.of(win), checker.detectFrom(board, new Position(2, 0))); + } + + + @Test + void diagonalAlignement() { + // x _ o + // x o x + // o _ _ + final Placed x = new Placed('x'); + final Placed o = new Placed('o'); + board.place(new Position(0, 0), x); + board.place(new Position(0, 1), x); + board.place(new Position(0, 2), o); + board.place(new Position(1, 1), o); + board.place(new Position(2, 0), o); + board.place(new Position(2, 1), x); + final Win win = new Win(new Position(2, 0), new Position(1, 1), new Position(0, 2)); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(0, 0))); + assertEquals(Collections.emptyList(), checker.detectFrom(board, new Position(0, 1))); + assertEquals(List.of(win), checker.detectFrom(board, new Position(0, 2))); + } + + @Test + void diagonalAlignement2() { + // x o o + // x x x + // o o x + final Placed x = new Placed('x'); + final Placed o = new Placed('o'); + board.place(new Position(0, 0), x); + board.place(new Position(0, 1), x); + board.place(new Position(0, 2), o); + board.place(new Position(1, 0), o); + board.place(new Position(1, 1), x); + board.place(new Position(1, 2), o); + board.place(new Position(2, 0), o); + board.place(new Position(2, 1), x); + board.place(new Position(2, 2), x); + final Win diagonalWin = new Win(new Position(0, 0), new Position(1, 1), new Position(2, 2)); + final Win horizontalWin = new Win(new Position(0, 1), new Position(1, 1), new Position(2, 1)); + assertEquals(List.of(diagonalWin), checker.detectFrom(board, new Position(0, 0))); + assertEquals(List.of(horizontalWin), checker.detectFrom(board, new Position(0, 1))); + assertEquals(List.of(horizontalWin, diagonalWin), checker.detectFrom(board, new Position(1, 1))); + assertEquals(List.of(horizontalWin), checker.detectFrom(board, new Position(2, 1))); + } +}