From cd7739359c1fce469418ac5b49580816906bf0aa Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Fri, 15 Apr 2016 13:19:46 +0200 Subject: Reformat code and rearrange members --- src/ch/epfl/xblast/Cell.java | 81 ++-- src/ch/epfl/xblast/Direction.java | 38 +- src/ch/epfl/xblast/Lists.java | 42 +- src/ch/epfl/xblast/SubCell.java | 71 ++-- src/ch/epfl/xblast/server/Block.java | 26 +- src/ch/epfl/xblast/server/Board.java | 93 ++--- src/ch/epfl/xblast/server/Bomb.java | 52 ++- src/ch/epfl/xblast/server/GameState.java | 161 ++++--- src/ch/epfl/xblast/server/Player.java | 464 ++++++++++----------- .../epfl/xblast/server/debug/GameStatePrinter.java | 64 +-- 10 files changed, 541 insertions(+), 551 deletions(-) (limited to 'src') diff --git a/src/ch/epfl/xblast/Cell.java b/src/ch/epfl/xblast/Cell.java index ecad75b..16632cc 100644 --- a/src/ch/epfl/xblast/Cell.java +++ b/src/ch/epfl/xblast/Cell.java @@ -36,6 +36,32 @@ public final class Cell { * The list of the board's Cell-s, spiral-ordered. */ public static final List SPIRAL_ORDER = Collections.unmodifiableList(spiralOrder()); + /** + * The coordinates of the Cell. + */ + private final int x, y; + + /** + * Instantiates a new Cell with the given coordinates. + * + * @param x the x-coordinate + * @param y the y-coordinate + */ + public Cell(int x, int y) { + this.x = normalize(COLUMNS, x); + this.y = normalize(ROWS, y); + } + + /** + * Normalizes the given number (using the integer floor modulus). + * + * @param max the maximum (the divisor) + * @param n the number to normalize (the dividend) + * @return the normalized value + */ + static int normalize(int max, int n) { + return Math.floorMod(n, max); + } /** * Builds a major-ordered list of Cell-s. @@ -96,33 +122,6 @@ public final class Cell { } - /** - * Normalizes the given number (using the integer floor modulus). - * - * @param max the maximum (the divisor) - * @param n the number to normalize (the dividend) - * @return the normalized value - */ - static int normalize(int max, int n) { - return Math.floorMod(n, max); - } - - /** - * The coordinates of the Cell. - */ - private final int x, y; - - /** - * Instantiates a new Cell with the given coordinates. - * - * @param x the x-coordinate - * @param y the y-coordinate - */ - public Cell(int x, int y) { - this.x = normalize(COLUMNS, x); - this.y = normalize(ROWS, y); - } - /** * Returns the normalized x-coordinate of the Cell. * @@ -141,15 +140,6 @@ public final class Cell { return this.y; } - /** - * Returns the index of the Cell (major ordered). - * - * @return the index of the Cell - */ - public int rowMajorIndex() { - return this.y * COLUMNS + this.x; - } - /** * Returns the neighboring Cell at the given Direction. * @@ -160,6 +150,16 @@ public final class Cell { return new Cell(this.x + dir.xVector(), this.y + dir.yVector()); } + /** + * Returns the hash code for this Cell, given by its row-major index. + * + * @return the hash code + */ + @Override + public int hashCode() { + return this.rowMajorIndex(); + } + /** * Returns T(the given Object is equal to this Cell (have the same coordinates)). * @@ -175,13 +175,12 @@ public final class Cell { } /** - * Returns the hash code for this Cell, given by its row-major index. + * Returns the index of the Cell (major ordered). * - * @return the hash code + * @return the index of the Cell */ - @Override - public int hashCode() { - return this.rowMajorIndex(); + public int rowMajorIndex() { + return this.y * COLUMNS + this.x; } /** diff --git a/src/ch/epfl/xblast/Direction.java b/src/ch/epfl/xblast/Direction.java index e2df042..5f5df33 100644 --- a/src/ch/epfl/xblast/Direction.java +++ b/src/ch/epfl/xblast/Direction.java @@ -28,6 +28,25 @@ public enum Direction { */ W; + /** + * T(the Direction is horizontal to the screen (East or West)). + * + * @return T(the Direction is horizontal to the screen) + */ + public boolean isHorizontal() { + return this == E || this == W; + } + + /** + * T(the current and given Directions are parallel (identical or opposite)). + * + * @param that a Direction to compare + * @return T(the current and given Directions are parallel) + */ + public boolean isParallelTo(Direction that) { + return that == this || that == this.opposite(); + } + /** * Returns the opposite Direction. * @@ -48,25 +67,6 @@ public enum Direction { } } - /** - * T(the Direction is horizontal to the screen (East or West)). - * - * @return T(the Direction is horizontal to the screen) - */ - public boolean isHorizontal() { - return this == E || this == W; - } - - /** - * T(the current and given Directions are parallel (identical or opposite)). - * - * @param that a Direction to compare - * @return T(the current and given Directions are parallel) - */ - public boolean isParallelTo(Direction that) { - return that == this || that == this.opposite(); - } - /** * T(the current and given Directions are perpendicular). * diff --git a/src/ch/epfl/xblast/Lists.java b/src/ch/epfl/xblast/Lists.java index 1f2e1c7..d599776 100644 --- a/src/ch/epfl/xblast/Lists.java +++ b/src/ch/epfl/xblast/Lists.java @@ -12,19 +12,6 @@ import java.util.stream.Stream; */ public final class Lists { - /** - * Returns a reversed copy of the given list, leaving the original one unmodified. - * - * @param l the list to reverse - * @param the type of the list's elements - * @return a reversed copy of the list. - */ - private static List reversed(List l) { - List r = new ArrayList<>(l); - Collections.reverse(r); - return r; - } - /** * Returns a symmetric version of the list, without repeating the last element of the input list. * For instance, mirrored([kay]) will return [kayak]. @@ -43,17 +30,15 @@ public final class Lists { } /** - * Returns a copy of the given list with element e inserted at index i. + * Returns a reversed copy of the given list, leaving the original one unmodified. * - * @param l the list - * @param i the insertion index - * @param e the element to insert + * @param l the list to reverse * @param the type of the list's elements - * @return a copy of the list with the element inserted + * @return a reversed copy of the list. */ - public static List inserted(List l, int i, T e) { - List r = new LinkedList<>(l); - r.add(i, e); + private static List reversed(List l) { + List r = new ArrayList<>(l); + Collections.reverse(r); return r; } @@ -69,6 +54,21 @@ public final class Lists { return Lists.inserted(Lists.inserted(l, 0, e), l.size() + 1, e); } + /** + * Returns a copy of the given list with element e inserted at index i. + * + * @param l the list + * @param i the insertion index + * @param e the element to insert + * @param the type of the list's elements + * @return a copy of the list with the element inserted + */ + public static List inserted(List l, int i, T e) { + List r = new LinkedList<>(l); + r.add(i, e); + return r; + } + /** * Returns all the permutations of the elements of the given list * diff --git a/src/ch/epfl/xblast/SubCell.java b/src/ch/epfl/xblast/SubCell.java index adb0f9b..9585fd2 100644 --- a/src/ch/epfl/xblast/SubCell.java +++ b/src/ch/epfl/xblast/SubCell.java @@ -27,20 +27,6 @@ public final class SubCell { * The height of the board (total of sub-rows). */ private static final int SUB_ROWS = SUB_ROW_DIVISIONS * Cell.ROWS; - - /** - * Returns the central SubCell of the given Cell. - * - * @param cell the reference Cell - * @return the central SubCell - */ - public static SubCell centralSubCellOf(Cell cell) { - return new SubCell( - cell.x() * SUB_COL_DIVISIONS + (SUB_COL_DIVISIONS / 2), - cell.y() * SUB_ROW_DIVISIONS + (SUB_ROW_DIVISIONS / 2) - ); - } - /** * The coordinates of the SubCell. */ @@ -75,6 +61,24 @@ public final class SubCell { return this.y; } + /** + * Returns T(this SubCell is central). + * + * @return T(this SubCell is central) + */ + public boolean isCentral() { + return this.distanceToCentral() == 0; + } + + /** + * Returns the Manhattan distance to the closest central SubCell. + * + * @return the distance + */ + public int distanceToCentral() { + return this.distanceTo(centralSubCellOf(this.containingCell())); + } + /** * Computes the Manhattan distance to the given SubCell. * @@ -86,21 +90,25 @@ public final class SubCell { } /** - * Returns the Manhattan distance to the closest central SubCell. + * Returns the central SubCell of the given Cell. * - * @return the distance + * @param cell the reference Cell + * @return the central SubCell */ - public int distanceToCentral() { - return this.distanceTo(centralSubCellOf(this.containingCell())); + public static SubCell centralSubCellOf(Cell cell) { + return new SubCell( + cell.x() * SUB_COL_DIVISIONS + (SUB_COL_DIVISIONS / 2), + cell.y() * SUB_ROW_DIVISIONS + (SUB_ROW_DIVISIONS / 2) + ); } /** - * Returns T(this SubCell is central). + * Returns the Cell containing this SubCell. * - * @return T(this SubCell is central) + * @return the containing Cell */ - public boolean isCentral() { - return this.distanceToCentral() == 0; + public Cell containingCell() { + return new Cell(this.x / SUB_COL_DIVISIONS, this.y / SUB_ROW_DIVISIONS); } /** @@ -114,12 +122,13 @@ public final class SubCell { } /** - * Returns the Cell containing this SubCell. + * Returns the hash code of this SubCell, given by its row-major index. * - * @return the containing Cell + * @return the hash code */ - public Cell containingCell() { - return new Cell(this.x / SUB_COL_DIVISIONS, this.y / SUB_ROW_DIVISIONS); + @Override + public int hashCode() { + return this.rowMajorIndex(); } /** @@ -136,16 +145,6 @@ public final class SubCell { return (((SubCell) that).rowMajorIndex() == this.rowMajorIndex()); } - /** - * Returns the hash code of this SubCell, given by its row-major index. - * - * @return the hash code - */ - @Override - public int hashCode() { - return this.rowMajorIndex(); - } - /** * Returns a String representation of the coordinates of the SubCell. * diff --git a/src/ch/epfl/xblast/server/Block.java b/src/ch/epfl/xblast/server/Block.java index ca04f31..1bfe891 100644 --- a/src/ch/epfl/xblast/server/Block.java +++ b/src/ch/epfl/xblast/server/Block.java @@ -59,6 +59,15 @@ public enum Block { this.maybeAssociatedBonus = null; } + /** + * Returns T(this block can host a player). + * + * @return T(this block can host a player) + */ + public boolean canHostPlayer() { + return this.isFree() || this.isBonus(); + } + /** * Returns T(this block is free). * @@ -69,12 +78,12 @@ public enum Block { } /** - * Returns T(this block can host a player). + * Returns T(this block is a bonus). * - * @return T(this block can host a player) + * @return T(this block is a bonus) */ - public boolean canHostPlayer() { - return this.isFree() || this.isBonus(); + public boolean isBonus() { + return this == BONUS_BOMB || this == BONUS_RANGE; } /** @@ -95,15 +104,6 @@ public enum Block { return this != INDESTRUCTIBLE_WALL; } - /** - * Returns T(this block is a bonus). - * - * @return T(this block is a bonus) - */ - public boolean isBonus() { - return this == BONUS_BOMB || this == BONUS_RANGE; - } - /** * Returns the bonus associated with the block. * diff --git a/src/ch/epfl/xblast/server/Board.java b/src/ch/epfl/xblast/server/Board.java index bcb94a2..06f3081 100644 --- a/src/ch/epfl/xblast/server/Board.java +++ b/src/ch/epfl/xblast/server/Board.java @@ -30,24 +30,6 @@ public final class Board { private static final int INNER_BOARD_COLUMNS = BOARD_COLUMNS - 2; private static final int QUADRANT_ROWS = 6; private static final int QUADRANT_COLUMNS = 7; - - /** - * Throw an exception if the matrix does not have the given number of rows/columns. - * - * @param matrix the tested matrix - * @param rows the expected number of rows - * @param columns the expected number of columns - * @throws IllegalArgumentException if the matrix does not comply with the given sizes. - */ - private static void checkBlockMatrix(List> matrix, int rows, int columns) { - if (matrix == null || matrix.size() != rows) - throw new IllegalArgumentException(); - - for (List row : matrix) - if (row.size() != columns) - throw new IllegalArgumentException(); - } - /** * List containing all the blocks of the board. */ @@ -67,21 +49,37 @@ public final class Board { } /** - * Build a new Board with the given Matrix. + * Build a symmetric walled board from the NWB quadrant. * - * @param rows list containing all the rows - * @return a new Board built with given rows - * @throws IllegalArgumentException if rows is not BOARD_ROWS * BOARD_COLUMNS + * @param quadrantNWBlocks the NW quadrant of the board (inner blocks only!) + * @return a new walled board symmetrically filled with the given NW quadrant + * @throws IllegalArgumentException if quadrantNWBlocks is not QUADRANT_ROWS * QUADRANT_COLUMNS */ - public static Board ofRows(List> rows) { - Board.checkBlockMatrix(rows, BOARD_ROWS, BOARD_COLUMNS); + public static Board ofQuadrantNWBlocksWalled(List> quadrantNWBlocks) { + Board.checkBlockMatrix(quadrantNWBlocks, QUADRANT_ROWS, QUADRANT_COLUMNS); - List> blockSequence = rows.stream() - .flatMap(Collection::stream) - .map(Sq::constant) - .collect(Collectors.toList()); + List> innerRows = Lists.mirrored(quadrantNWBlocks.stream() + .map(Lists::mirrored) + .collect(Collectors.toList())); - return new Board(blockSequence); + return Board.ofInnerBlocksWalled(innerRows); + } + + /** + * Throw an exception if the matrix does not have the given number of rows/columns. + * + * @param matrix the tested matrix + * @param rows the expected number of rows + * @param columns the expected number of columns + * @throws IllegalArgumentException if the matrix does not comply with the given sizes. + */ + private static void checkBlockMatrix(List> matrix, int rows, int columns) { + if (matrix == null || matrix.size() != rows) + throw new IllegalArgumentException(); + + for (List row : matrix) + if (row.size() != columns) + throw new IllegalArgumentException(); } /** @@ -105,40 +103,41 @@ public final class Board { } /** - * Build a symmetric walled board from the NWB quadrant. + * Build a new Board with the given Matrix. * - * @param quadrantNWBlocks the NW quadrant of the board (inner blocks only!) - * @return a new walled board symmetrically filled with the given NW quadrant - * @throws IllegalArgumentException if quadrantNWBlocks is not QUADRANT_ROWS * QUADRANT_COLUMNS + * @param rows list containing all the rows + * @return a new Board built with given rows + * @throws IllegalArgumentException if rows is not BOARD_ROWS * BOARD_COLUMNS */ - public static Board ofQuadrantNWBlocksWalled(List> quadrantNWBlocks) { - Board.checkBlockMatrix(quadrantNWBlocks, QUADRANT_ROWS, QUADRANT_COLUMNS); + public static Board ofRows(List> rows) { + Board.checkBlockMatrix(rows, BOARD_ROWS, BOARD_COLUMNS); - List> innerRows = Lists.mirrored(quadrantNWBlocks.stream() - .map(Lists::mirrored) - .collect(Collectors.toList())); + List> blockSequence = rows.stream() + .flatMap(Collection::stream) + .map(Sq::constant) + .collect(Collectors.toList()); - return Board.ofInnerBlocksWalled(innerRows); + return new Board(blockSequence); } /** - * Return the sequence of blocks related to the given cell. + * Returns the block related to the given cell. * * @param c cell - * @return the sequence of blocks related to the given cell. + * @return the first block of the sequence related to the given cell */ - public Sq blocksAt(Cell c) { - return this.blocks.get(c.rowMajorIndex()); + public Block blockAt(Cell c) { + return this.blocksAt(c).head(); } /** - * Returns the block related to the given cell. + * Return the sequence of blocks related to the given cell. * * @param c cell - * @return the first block of the sequence related to the given cell + * @return the sequence of blocks related to the given cell. */ - public Block blockAt(Cell c) { - return this.blocksAt(c).head(); + public Sq blocksAt(Cell c) { + return this.blocks.get(c.rowMajorIndex()); } } diff --git a/src/ch/epfl/xblast/server/Bomb.java b/src/ch/epfl/xblast/server/Bomb.java index a99a8cb..78de111 100644 --- a/src/ch/epfl/xblast/server/Bomb.java +++ b/src/ch/epfl/xblast/server/Bomb.java @@ -21,30 +21,22 @@ import java.util.stream.Stream; public final class Bomb { private static final UnaryOperator FUSE_STEP_FUNCTION = fl -> fl - 1; - - /** - * Builds and returns a new fuse sequence of given length. - * - * @param fuseLength the fuse length - * @return the fuse sequence - */ - private static Sq buildFuseSequence(int fuseLength) { - int fl = ArgumentChecker.requireNonNegative(fuseLength); - return Sq.iterate(fl, Bomb.FUSE_STEP_FUNCTION).limit(fl); - } - private PlayerID ownerId; private Cell position; private Sq fuseLengths; private int range; - /** - * Generates one arm of explosion. + * Instantiates a new Bomb. + * + * @param ownerId id of the owner of the bomb + * @param position position of the bomb + * @param fuseLength length of the bomb's fuse + * @param range range of the bomb + * @throws IllegalArgumentException if range or fuseLengths is negative + * @throws NullPointerException if ownerId, position or fuseLengths is null */ - private Sq> explosionArmTowards(Direction dir) { - return Sq - .constant(Sq.iterate(position, position -> position.neighbor(dir)).limit(range)) - .limit(Ticks.EXPLOSION_TICKS); + public Bomb(PlayerID ownerId, Cell position, int fuseLength, int range) { + this(ownerId, position, Bomb.buildFuseSequence(fuseLength), range); } /** @@ -65,17 +57,23 @@ public final class Bomb { } /** - * Instantiates a new Bomb. + * Builds and returns a new fuse sequence of given length. * - * @param ownerId id of the owner of the bomb - * @param position position of the bomb - * @param fuseLength length of the bomb's fuse - * @param range range of the bomb - * @throws IllegalArgumentException if range or fuseLengths is negative - * @throws NullPointerException if ownerId, position or fuseLengths is null + * @param fuseLength the fuse length + * @return the fuse sequence */ - public Bomb(PlayerID ownerId, Cell position, int fuseLength, int range) { - this(ownerId, position, Bomb.buildFuseSequence(fuseLength), range); + private static Sq buildFuseSequence(int fuseLength) { + int fl = ArgumentChecker.requireNonNegative(fuseLength); + return Sq.iterate(fl, Bomb.FUSE_STEP_FUNCTION).limit(fl); + } + + /** + * Generates one arm of explosion. + */ + private Sq> explosionArmTowards(Direction dir) { + return Sq + .constant(Sq.iterate(position, position -> position.neighbor(dir)).limit(range)) + .limit(Ticks.EXPLOSION_TICKS); } /** diff --git a/src/ch/epfl/xblast/server/GameState.java b/src/ch/epfl/xblast/server/GameState.java index 71e32a6..86e596e 100644 --- a/src/ch/epfl/xblast/server/GameState.java +++ b/src/ch/epfl/xblast/server/GameState.java @@ -37,47 +37,64 @@ public final class GameState { * Pseudo-random source for randomized behaviours. */ private static final Random RANDOM_SOURCE = new Random(GameState.RANDOM_SEED); + private final int ticks; + private final Board board; + private final List players; + private final List bombs; + private final List>> explosions; + private final List> blasts; /** - * Builds and returns the player priority order permutations. + * Instantiates a new (clean) GameState. * - * @return the list of player priority orders + * @param board the board + * @param players list of the players */ - private static List> buildPlayerPriorityOrderList() { - return Lists.permutations(Arrays.asList(PlayerID.values())); + public GameState(Board board, List players) { + this(0, board, players, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } /** - * Returns a randomly chosen bonus Block with an equal probability distribution. + * Instantiates a new GameState. * - * @return a random bonus block + * @param ticks the tick corresponding to the state + * @param board the game's board + * @param players list of the players + * @param bombs list of the bombs + * @param explosions list of the explosions + * @param blasts list of particle blasts + * @throws IllegalArgumentException if ticks is negative or players does not contains 4 players. + * @throws NullPointerException if any element except ticks is null. */ - private static Block randomBonus() { - int randomIndex = RANDOM_SOURCE.nextInt(GameState.RANDOM_BONUSES.length); - return GameState.RANDOM_BONUSES[randomIndex]; + public GameState(int ticks, Board board, List players, List bombs, List>> explosions, List> blasts) { + this.ticks = ArgumentChecker.requireNonNegative(ticks); + this.board = Objects.requireNonNull(board); + + if (players.size() != PlayerID.values().length) throw new IllegalArgumentException(); + this.players = new ArrayList<>(players); + + this.bombs = new ArrayList<>(Objects.requireNonNull(bombs)); + this.explosions = new ArrayList<>(Objects.requireNonNull(explosions)); + this.blasts = new ArrayList<>(Objects.requireNonNull(blasts)); } /** - * Filters the given list of players and returns the lively ones. + * Builds and returns the player priority order permutations. * - * @param players a list of players - * @return the list of alive players + * @return the list of player priority orders */ - private static List alivePlayers(List players) { - return players.stream() - .filter(Player::isAlive) - .collect(Collectors.toList()); + private static List> buildPlayerPriorityOrderList() { + return Lists.permutations(Arrays.asList(PlayerID.values())); } /** - * Maps the given bombs to their position. + * Returns a randomly chosen bonus Block with an equal probability distribution. * - * @param bombs a list of bombs - * @return a map of positions and their bombs + * @return a random bonus block */ - private static Map bombedCells(List bombs) { - return bombs.stream() - .collect(Collectors.toMap(Bomb::position, Function.identity())); + private static Block randomBonus() { + int randomIndex = RANDOM_SOURCE.nextInt(GameState.RANDOM_BONUSES.length); + return GameState.RANDOM_BONUSES[randomIndex]; } /** @@ -90,18 +107,6 @@ public final class GameState { return b.stream().collect(Collectors.groupingBy(Bomb::ownerId)); } - /** - * Returns a set of cells that contains at least one blast in the given blasts sequences. - * - * @param blasts the list of blast sequences - * @return the set of blasted cells - */ - private static Set blastedCells(List> blasts) { - return blasts.stream() - .map(Sq::head) - .collect(Collectors.toSet()); - } - /** * Computes the next state of a blast. * @@ -418,61 +423,41 @@ public final class GameState { return bombs1; } - private final int ticks; - private final Board board; - private final List players; - private final List bombs; - private final List>> explosions; - private final List> blasts; - /** - * Instantiates a new GameState. - * - * @param ticks the tick corresponding to the state - * @param board the game's board - * @param players list of the players - * @param bombs list of the bombs - * @param explosions list of the explosions - * @param blasts list of particle blasts - * @throws IllegalArgumentException if ticks is negative or players does not contains 4 players. - * @throws NullPointerException if any element except ticks is null. + * @return the tick related to the state. */ - public GameState(int ticks, Board board, List players, List bombs, List>> explosions, List> blasts) { - this.ticks = ArgumentChecker.requireNonNegative(ticks); - this.board = Objects.requireNonNull(board); - - if (players.size() != PlayerID.values().length) throw new IllegalArgumentException(); - this.players = new ArrayList<>(players); - - this.bombs = new ArrayList<>(Objects.requireNonNull(bombs)); - this.explosions = new ArrayList<>(Objects.requireNonNull(explosions)); - this.blasts = new ArrayList<>(Objects.requireNonNull(blasts)); + public int ticks() { + return this.ticks; } /** - * Instantiates a new (clean) GameState. + * Returns T(the game is over). * - * @param board the board - * @param players list of the players + * @return true if all the players are dead or if the game reached the time limit */ - public GameState(Board board, List players) { - this(0, board, players, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + public boolean isGameOver() { + return this.alivePlayers().size() <= 1 || this.ticks >= Ticks.TOTAL_TICKS; } /** - * @return the tick related to the state. + * Returns the alive players. + * + * @return a list of the alive players */ - public int ticks() { - return this.ticks; + public List alivePlayers() { + return GameState.alivePlayers(this.players); } /** - * Returns T(the game is over). + * Filters the given list of players and returns the lively ones. * - * @return true if all the players are dead or if the game reached the time limit + * @param players a list of players + * @return the list of alive players */ - public boolean isGameOver() { - return this.alivePlayers().size() <= 1 || this.ticks >= Ticks.TOTAL_TICKS; + private static List alivePlayers(List players) { + return players.stream() + .filter(Player::isAlive) + .collect(Collectors.toList()); } /** @@ -511,21 +496,23 @@ public final class GameState { } /** - * Returns the alive players. + * Returns a mapping of Cells and their Bomb. * - * @return a list of the alive players + * @return the map of bombs */ - public List alivePlayers() { - return GameState.alivePlayers(this.players); + public Map bombedCells() { + return GameState.bombedCells(this.bombs); } /** - * Returns a mapping of Cells and their Bomb. + * Maps the given bombs to their position. * - * @return the map of bombs + * @param bombs a list of bombs + * @return a map of positions and their bombs */ - public Map bombedCells() { - return GameState.bombedCells(this.bombs); + private static Map bombedCells(List bombs) { + return bombs.stream() + .collect(Collectors.toMap(Bomb::position, Function.identity())); } /** @@ -537,6 +524,18 @@ public final class GameState { return GameState.blastedCells(this.blasts); } + /** + * Returns a set of cells that contains at least one blast in the given blasts sequences. + * + * @param blasts the list of blast sequences + * @return the set of blasted cells + */ + private static Set blastedCells(List> blasts) { + return blasts.stream() + .map(Sq::head) + .collect(Collectors.toSet()); + } + /** * Computes and returns the game state for the next tick, given the current state and the given events. * diff --git a/src/ch/epfl/xblast/server/Player.java b/src/ch/epfl/xblast/server/Player.java index 414be71..fc2508c 100644 --- a/src/ch/epfl/xblast/server/Player.java +++ b/src/ch/epfl/xblast/server/Player.java @@ -13,167 +13,53 @@ import java.util.Objects; */ public final class Player { - /** - * The life state of a player. - */ - public static final class LifeState { - - /** - * Enum containing all the possible life states. - */ - public enum State { - INVULNERABLE, - VULNERABLE, - DYING, - DEAD - } - - private final int lives; - private final State state; - - /** - * Instantiates a new LifeSate. - * - * @param lives the number of lives - * @param state the state - * @throws IllegalArgumentException if lives is negative - */ - public LifeState(int lives, State state) { - this.lives = ArgumentChecker.requireNonNegative(lives); - this.state = Objects.requireNonNull(state); - } - - /** - * Returns the number of lives. - * - * @return the number of lives - */ - public int lives() { - return this.lives; - } - - /** - * Returns the State. - * - * @return the state - */ - public State state() { - return this.state; - } - - /** - * Returns T(this State allows the player to move). - * - * @return T(this State allows the player to move) - */ - public boolean canMove() { - return this.state() == State.INVULNERABLE || this.state() == State.VULNERABLE; - } - - @Override - public String toString() { - return "LifeState{" + - "lives=" + lives + - ", state=" + state + - '}'; - } - - } - - /** - * The "directed" position of a player. - */ - public static final class DirectedPosition { - - private final SubCell position; - private final Direction direction; - - /** - * Builds and returns an infinite sequence of directed positions corresponding to a stopped player. - * - * @return the sequence - */ - public static Sq stopped(DirectedPosition p) { - return Sq.constant(p); - } - - /** - * Builds and returns an infinite sequence of directed position corresponding to a moving player. - * - * @return the sequence - */ - public static Sq moving(DirectedPosition p) { - return Sq.iterate(p, x -> x.withPosition(x.position().neighbor(x.direction()))); - } - - /** - * Instantiates a new DirectedPosition. - * - * @param position the position of the player - * @param direction the direction of the player - * @throws IllegalArgumentException if position or direction is null - */ - public DirectedPosition(SubCell position, Direction direction) { - this.position = Objects.requireNonNull(position); - this.direction = Objects.requireNonNull(direction); - } - - /** - * Returns the position. - * - * @return the position - */ - public SubCell position() { - return this.position; - } - - /** - * Creates and returns a DirectedPosition with the given SubCell position. - * - * @return a new directed position with the given position and the previous direction - */ - public DirectedPosition withPosition(SubCell newPosition) { - return new DirectedPosition(newPosition, this.direction()); - } - - /** - * Returns the direction. - * - * @return the direction - */ - public Direction direction() { - return this.direction; - } - - /** - * Creates and returns a DirectedPosition with the given Direction. - * - * @return a new directed position with the previous position and the given direction - */ - public DirectedPosition withDirection(Direction newDirection) { - return new DirectedPosition(this.position(), newDirection); - } - - @Override - public String toString() { - return "DirectedPosition{" + - "position=" + position + - ", direction=" + direction + - '}'; - } - - } - /** * The default Direction of a new Player. */ private static final Direction DEFAULT_DIRECTION = Direction.S; - private final PlayerID id; private final Sq lifeStates; private final Sq directedPos; private final int maxBombs; private final int bombRange; + /** + * Instantiates a new Player. + * + * @param id the Player's id + * @param lives the number of lives of the Player + * @param position the starting position of the Player + * @param maxBombs the maximum number of Bomb-s the Player can carry + * @param bombRange the range of the Bomb-s + * @throws IllegalArgumentException + * @throws NullPointerException + */ + public Player(PlayerID id, int lives, Cell position, int maxBombs, int bombRange) { + this( + id, + Player.buildDefaultLifeStateSequence(lives), + Player.buildDefaultDirectedPositionSequence(position), + maxBombs, + bombRange + ); + } + /** + * Instantiates a new Player. + * + * @param id the Player's id + * @param lifeStates a sequence of LifeState-s + * @param directedPos a sequence of DirectedPosition-s + * @param maxBombs the maximum number of Bomb-s the Player can carry + * @param bombRange the range of the Bomb-s + * @throws IllegalArgumentException + * @throws NullPointerException + */ + public Player(PlayerID id, Sq lifeStates, Sq directedPos, int maxBombs, int bombRange) { + this.id = Objects.requireNonNull(id); + this.lifeStates = Objects.requireNonNull(lifeStates); + this.directedPos = Objects.requireNonNull(directedPos); + this.maxBombs = ArgumentChecker.requireNonNegative(maxBombs); + this.bombRange = ArgumentChecker.requireNonNegative(bombRange); + } /** * Builds a default LifeState sequence with the given number of lives. @@ -211,64 +97,6 @@ public final class Player { return DirectedPosition.stopped(dp); } - /** - * Instantiates a new Player. - * - * @param id the Player's id - * @param lifeStates a sequence of LifeState-s - * @param directedPos a sequence of DirectedPosition-s - * @param maxBombs the maximum number of Bomb-s the Player can carry - * @param bombRange the range of the Bomb-s - * @throws IllegalArgumentException - * @throws NullPointerException - */ - public Player(PlayerID id, Sq lifeStates, Sq directedPos, int maxBombs, int bombRange) { - this.id = Objects.requireNonNull(id); - this.lifeStates = Objects.requireNonNull(lifeStates); - this.directedPos = Objects.requireNonNull(directedPos); - this.maxBombs = ArgumentChecker.requireNonNegative(maxBombs); - this.bombRange = ArgumentChecker.requireNonNegative(bombRange); - } - - /** - * Instantiates a new Player. - * - * @param id the Player's id - * @param lives the number of lives of the Player - * @param position the starting position of the Player - * @param maxBombs the maximum number of Bomb-s the Player can carry - * @param bombRange the range of the Bomb-s - * @throws IllegalArgumentException - * @throws NullPointerException - */ - public Player(PlayerID id, int lives, Cell position, int maxBombs, int bombRange) { - this( - id, - Player.buildDefaultLifeStateSequence(lives), - Player.buildDefaultDirectedPositionSequence(position), - maxBombs, - bombRange - ); - } - - /** - * Returns the Player's ID. - * - * @return the player's ID - */ - public PlayerID id() { - return this.id; - } - - /** - * Returns the Player's LifeState sequence. - * - * @return the player's life states - */ - public Sq lifeStates() { - return this.lifeStates; - } - /** * Builds and returns the Player's next life LifeState sequence. * @@ -295,12 +123,12 @@ public final class Player { } /** - * Returns the Player's current LifeState. + * Returns the Player's current number of remaining lives. * - * @return the current life state of the player + * @return the current number of lives of the player */ - public LifeState lifeState() { - return this.lifeStates.head(); + public int lives() { + return this.lifeStates.head().lives(); } /** @@ -313,12 +141,12 @@ public final class Player { } /** - * Returns the Player's current number of remaining lives. + * Returns the Player's current LifeState. * - * @return the current number of lives of the player + * @return the current life state of the player */ - public int lives() { - return this.lifeStates.head().lives(); + public LifeState lifeState() { + return this.lifeStates.head(); } /** @@ -340,39 +168,39 @@ public final class Player { } /** - * Returns the Player's current position (SubCell). + * Returns the Player's current Direction. * - * @return the position of the player + * @return the current direction of the player */ - public SubCell position() { - return this.directedPos.head().position(); + public Direction direction() { + return this.directedPos.head().direction(); } /** - * Returns the Player's current Direction. + * Instantiates a new Player with the given Bomb limit. * - * @return the current direction of the player + * @return a new Player with the new maximum of bombs */ - public Direction direction() { - return this.directedPos.head().direction(); + public Player withMaxBombs(int newMaxBombs) { + return new Player(this.id(), this.lifeStates(), directedPos, newMaxBombs, this.bombRange()); } /** - * Returns the Player's Bomb limit. + * Returns the Player's ID. * - * @return the maximum number of bombs that the player can use + * @return the player's ID */ - public int maxBombs() { - return this.maxBombs; + public PlayerID id() { + return this.id; } /** - * Instantiates a new Player with the given Bomb limit. + * Returns the Player's LifeState sequence. * - * @return a new Player with the new maximum of bombs + * @return the player's life states */ - public Player withMaxBombs(int newMaxBombs) { - return new Player(this.id(), this.lifeStates(), directedPos, newMaxBombs, this.bombRange()); + public Sq lifeStates() { + return this.lifeStates; } /** @@ -393,6 +221,15 @@ public final class Player { return new Player(this.id(), this.lifeStates(), this.directedPos, this.maxBombs(), newBombRange); } + /** + * Returns the Player's Bomb limit. + * + * @return the maximum number of bombs that the player can use + */ + public int maxBombs() { + return this.maxBombs; + } + /** * Instantiates and returns a new Bomb for the current Player, registered with its ID, current position and range. * @@ -402,6 +239,165 @@ public final class Player { return new Bomb(this.id(), this.position().containingCell(), Ticks.BOMB_FUSE_TICKS, this.bombRange()); } + /** + * Returns the Player's current position (SubCell). + * + * @return the position of the player + */ + public SubCell position() { + return this.directedPos.head().position(); + } + + /** + * The life state of a player. + */ + public static final class LifeState { + + private final int lives; + private final State state; + /** + * Instantiates a new LifeSate. + * + * @param lives the number of lives + * @param state the state + * @throws IllegalArgumentException if lives is negative + */ + public LifeState(int lives, State state) { + this.lives = ArgumentChecker.requireNonNegative(lives); + this.state = Objects.requireNonNull(state); + } + + /** + * Returns the number of lives. + * + * @return the number of lives + */ + public int lives() { + return this.lives; + } + + /** + * Returns T(this State allows the player to move). + * + * @return T(this State allows the player to move) + */ + public boolean canMove() { + return this.state() == State.INVULNERABLE || this.state() == State.VULNERABLE; + } + + /** + * Returns the State. + * + * @return the state + */ + public State state() { + return this.state; + } + + @Override + public String toString() { + return "LifeState{" + + "lives=" + lives + + ", state=" + state + + '}'; + } + + /** + * Enum containing all the possible life states. + */ + public enum State { + INVULNERABLE, + VULNERABLE, + DYING, + DEAD + } + + } + + /** + * The "directed" position of a player. + */ + public static final class DirectedPosition { + + private final SubCell position; + private final Direction direction; + + /** + * Instantiates a new DirectedPosition. + * + * @param position the position of the player + * @param direction the direction of the player + * @throws IllegalArgumentException if position or direction is null + */ + public DirectedPosition(SubCell position, Direction direction) { + this.position = Objects.requireNonNull(position); + this.direction = Objects.requireNonNull(direction); + } + + /** + * Builds and returns an infinite sequence of directed positions corresponding to a stopped player. + * + * @return the sequence + */ + public static Sq stopped(DirectedPosition p) { + return Sq.constant(p); + } + + /** + * Builds and returns an infinite sequence of directed position corresponding to a moving player. + * + * @return the sequence + */ + public static Sq moving(DirectedPosition p) { + return Sq.iterate(p, x -> x.withPosition(x.position().neighbor(x.direction()))); + } + + /** + * Creates and returns a DirectedPosition with the given SubCell position. + * + * @return a new directed position with the given position and the previous direction + */ + public DirectedPosition withPosition(SubCell newPosition) { + return new DirectedPosition(newPosition, this.direction()); + } + + /** + * Returns the position. + * + * @return the position + */ + public SubCell position() { + return this.position; + } + + /** + * Returns the direction. + * + * @return the direction + */ + public Direction direction() { + return this.direction; + } + + /** + * Creates and returns a DirectedPosition with the given Direction. + * + * @return a new directed position with the previous position and the given direction + */ + public DirectedPosition withDirection(Direction newDirection) { + return new DirectedPosition(this.position(), newDirection); + } + + @Override + public String toString() { + return "DirectedPosition{" + + "position=" + position + + ", direction=" + direction + + '}'; + } + + } + @Override public String toString() { return "Player{" + diff --git a/src/ch/epfl/xblast/server/debug/GameStatePrinter.java b/src/ch/epfl/xblast/server/debug/GameStatePrinter.java index fe4c446..14b0b38 100644 --- a/src/ch/epfl/xblast/server/debug/GameStatePrinter.java +++ b/src/ch/epfl/xblast/server/debug/GameStatePrinter.java @@ -17,24 +17,6 @@ import java.util.Map; */ public final class GameStatePrinter { - private enum ANSIColor { - BLACK(0), RED(1), GREEN(2), YELLOW(3), BLUE(4), MAGENTA(5), CYAN(6), WHITE(7); - - private static final String CSI = "\u001b["; - private static final String END = "m"; - private static final int SET_COMMAND = 4; - - private final int code; - - ANSIColor(int code) { - this.code = code; - } - - public String coloredText(String t) { - return String.format("%s%d%d%s%s%s%s", CSI, SET_COMMAND, this.code, END, t, CSI, END); - } - } - private GameStatePrinter() { } @@ -79,6 +61,23 @@ public final class GameStatePrinter { p.lifeState().canMove() ? GameStatePrinter.charForDirection(p.direction()) : 'x')); } + private static String stringForBlock(Block b) { + switch (b) { + case INDESTRUCTIBLE_WALL: + return ANSIColor.BLACK.coloredText("##"); + case DESTRUCTIBLE_WALL: + return ANSIColor.BLACK.coloredText("??"); + case CRUMBLING_WALL: + return ANSIColor.BLACK.coloredText("¿¿"); + case BONUS_BOMB: + return ANSIColor.GREEN.coloredText("+b"); + case BONUS_RANGE: + return ANSIColor.GREEN.coloredText("+r"); + default: + return " "; + } + } + private static char charForDirection(Direction d) { switch (d) { case N: @@ -94,20 +93,21 @@ public final class GameStatePrinter { } } - private static String stringForBlock(Block b) { - switch (b) { - case INDESTRUCTIBLE_WALL: - return ANSIColor.BLACK.coloredText("##"); - case DESTRUCTIBLE_WALL: - return ANSIColor.BLACK.coloredText("??"); - case CRUMBLING_WALL: - return ANSIColor.BLACK.coloredText("¿¿"); - case BONUS_BOMB: - return ANSIColor.GREEN.coloredText("+b"); - case BONUS_RANGE: - return ANSIColor.GREEN.coloredText("+r"); - default: - return " "; + private enum ANSIColor { + BLACK(0), RED(1), GREEN(2), YELLOW(3), BLUE(4), MAGENTA(5), CYAN(6), WHITE(7); + + private static final String CSI = "\u001b["; + private static final String END = "m"; + private static final int SET_COMMAND = 4; + + private final int code; + + ANSIColor(int code) { + this.code = code; + } + + public String coloredText(String t) { + return String.format("%s%d%d%s%s%s%s", CSI, SET_COMMAND, this.code, END, t, CSI, END); } } -- cgit v1.2.3