From 2165f60e83fa4e36183c2821955dbd77d86af3f0 Mon Sep 17 00:00:00 2001 From: Timothée Floure Date: Mon, 7 Mar 2016 15:04:33 +0100 Subject: Basics of the third week (Player & Bomb) --- src/ch/epfl/xblast/ArgumentChecker.java | 23 +++ src/ch/epfl/xblast/PlayerID.java | 13 ++ src/ch/epfl/xblast/server/Bomb.java | 116 +++++++++++++ src/ch/epfl/xblast/server/Player.java | 291 ++++++++++++++++++++++++++++++++ 4 files changed, 443 insertions(+) create mode 100644 src/ch/epfl/xblast/ArgumentChecker.java create mode 100644 src/ch/epfl/xblast/PlayerID.java create mode 100644 src/ch/epfl/xblast/server/Bomb.java create mode 100644 src/ch/epfl/xblast/server/Player.java (limited to 'src/ch') diff --git a/src/ch/epfl/xblast/ArgumentChecker.java b/src/ch/epfl/xblast/ArgumentChecker.java new file mode 100644 index 0000000..8e7ba76 --- /dev/null +++ b/src/ch/epfl/xblast/ArgumentChecker.java @@ -0,0 +1,23 @@ +package ch.epfl.xblast; + +/** + * ArgumentChecker. + * + * @author Timothée FLOURE (257420) + */ +public final class ArgumentChecker { + /** + * Return the given value if it is non-negative + * + * @param value the tested value + * @throws IllegalArgumentException if the value is inferior to 0 + * @return the given value if non-negative + */ + public static int requireNonNegative(int value) { + if (value >= 0) { + return value; + } else { + throw new IllegalArgumentException(); + } + } +} diff --git a/src/ch/epfl/xblast/PlayerID.java b/src/ch/epfl/xblast/PlayerID.java new file mode 100644 index 0000000..05a280b --- /dev/null +++ b/src/ch/epfl/xblast/PlayerID.java @@ -0,0 +1,13 @@ +package ch.epfl.xblast; + +/** + * IDs the 4 different players. + * + * @author Timothée FLOURE (257420) + */ +public enum PlayerID { + PLAYER_1, + PLAYER_2, + PLAYER_3, + PLAYER_4 +} diff --git a/src/ch/epfl/xblast/server/Bomb.java b/src/ch/epfl/xblast/server/Bomb.java new file mode 100644 index 0000000..3f49f64 --- /dev/null +++ b/src/ch/epfl/xblast/server/Bomb.java @@ -0,0 +1,116 @@ +package ch.epfl.xblast.server; + +import ch.epfl.xblast.PlayerID; +import ch.epfl.xblast.Cell; +import ch.epfl.cs108.Sq; +import ch.epfl.xblast.ArgumentChecker; +import ch.epfl.xblast.Direction; + +import java.util.Objects; +import java.util.List; +import java.util.ArrayList; + +/** + * @author Timothée FLOURE (257420) + */ +public final class Bomb { + private PlayerID ownerId; + private Cell position; + private Sq fuseLengths; + private int range; + + /** + * Generate 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); + } + + /** + * Instanciates a new Bomb. + * + * @param ownerId id of the owner of the bomb + * @param position position of the bomb + * @param fuseLengths length of the bomb's fuse + * @param range range of the bomb + * @throws IllegalArguementException if range is negative or fuseLenghts is empty + * @throws NullPointerException if ownerId, position or fuseLengths is null + */ + public Bomb(PlayerID ownerId, Cell position, Sq fuseLengths, int range) { + this.ownerId = Objects.requireNonNull(ownerId); + this.position = Objects.requireNonNull(position); + if (fuseLengths.isEmpty()) { + throw new IllegalArgumentException(); + } else { + this.fuseLengths = Objects.requireNonNull(fuseLengths); + } + this.range = ArgumentChecker.requireNonNegative(range); + } + + /** + * Instanciates a new Bomb. + * + * @param ownerId id of the owner of the bomb + * @param position position of the bomb + * @param fuseLengths length of the bomb's fuse + * @param range range of the bomb + * @throws IllegalArguementException if range or fuseLengths is negative + * @throws NullPointerException if ownerId, position or fuseLengths is null + */ + public Bomb(PlayerID ownerId, Cell position, int fuseLength, int range) { + this.ownerId = Objects.requireNonNull(ownerId); + this.position = Objects.requireNonNull(position); + if (fuseLength == 0) { + throw new IllegalArgumentException(); + } else { + fuseLengths = Sq.iterate(fuseLength, fuseLengths -> fuseLength - 1 ); + } + this.range = ArgumentChecker.requireNonNegative(range); + } + + /** + * @return the ID of the owner of the bomb + */ + public PlayerID ownerId() { + return ownerId; + } + + /** + * @return the position of the bomb + */ + public Cell position() { + return position; + } + + /** + * @return the length of the fuse + */ + public Sq fuseLengths() { + return fuseLengths; + } + + /** + * @return the remaining time before the explosion + */ + public int fuseLength() { + return fuseLengths.head(); + } + + /** + * @return the range of the Bomb + */ + public int range() { + return range; + } + + /** + * @return the explosion + */ + public List>> explosion() { + List>> explosion = new ArrayList<>(); + for (Direction dir : Direction.values()) { + explosion.add(explosionArmTowards(dir)); + } + return explosion; + } +} diff --git a/src/ch/epfl/xblast/server/Player.java b/src/ch/epfl/xblast/server/Player.java new file mode 100644 index 0000000..b3ae851 --- /dev/null +++ b/src/ch/epfl/xblast/server/Player.java @@ -0,0 +1,291 @@ +package ch.epfl.xblast.server; + +import ch.epfl.xblast.ArgumentChecker; +import ch.epfl.xblast.Direction; +import ch.epfl.xblast.Cell; +import ch.epfl.xblast.SubCell; +import ch.epfl.xblast.PlayerID; +import ch.epfl.cs108.Sq; + +import java.util.Objects; + +/** + * Player. + * + * @author Timothée FLOURE (257420) + */ +public final class Player { + /** + * The life state of a player. + */ + public static final class LifeState { + /** + * Enum containing all the possible states. + */ + public enum State { + INVULNERABLE, + VULNERABLE, + DYING, + DEAD + } + + private final int lives; + private final State state; + + /** + * Instanciates a new LifeSate. + * + * @param lives the number of lifes + * @param state the state + * @throws IllegalArgumentException if lives is negative + */ + public LifeState(int lives, State state) { + this.lives = ArgumentChecker.requireNonNegative(lives); + this.state = state; + } + + /** + * @return the number of lives + */ + public int lives() { + return lives; + } + + /** + * @return the state + */ + public State state() { + return state; + } + + /** + * @return true if the actual state allow to move + */ + public boolean canMove() { + return (state() == State.INVULNERABLE || state() == State.VULNERABLE); + } + } + + /** + * The "directed" position of a player. + */ + public static final class DirectedPosition { + private final SubCell position; + private final Direction direction; + + /** + * @return an infinite sequence of directed positions corresponding to a stopped player. + */ + public static Sq stopped(DirectedPosition p) { + return Sq.constant(p); + } + + /** + * @return an infinite sequence of directed position corresponding to a moving player. + */ + public static Sq moving(DirectedPosition p) { + return Sq.iterate(p, x -> x.withPosition(x.position().neighbor(x.direction()))); + } + + /** + * Instanciates a new DirectedPos + * + * @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); + } + + /** + * @return the position + */ + public SubCell position() { + return position; + } + + /** + * @return a new directed position with the given position and the previous direction + */ + public DirectedPosition withPosition(SubCell newPosition) { + return new DirectedPosition(newPosition, direction); + } + + /** + * @return the direction + */ + public Direction direction() { + return direction; + } + + /** + * @return a new directed position with the previous position and the given direction + */ + public DirectedPosition withDirection(Direction newDirection) { + return new DirectedPosition(position, newDirection); + } + } + + private final PlayerID id; + private final Sq lifeStates; + private final Sq directedPos; + private final int maxBombs; + private final int bombRange; + + /** + * Instanciates a new Player. + * + * @param id + * @param lifeStates + * @param directedPos + * @param maxBombs + * @param bombRange + * @throws IllegalArfuementException + * @throws NullPointerExeption + */ + 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); + } + + /** + * Instanciates a new Player. + * + * @param id + * @param lives + * @param position + * @param maxBombs + * @param bombRange + * @throws IllegalArgumentException + * @throws NullPointerExeption + */ + public Player(PlayerID id, int lives, Cell position, int maxBombs, int bombRange) { + this.id = Objects.requireNonNull(id); + DirectedPosition newDirectedPos = new DirectedPosition(SubCell.centralSubCellOf(Objects.requireNonNull(position)), Direction.S); + this.directedPos = DirectedPosition.stopped(newDirectedPos); + LifeState invulnerability = new LifeState(ArgumentChecker.requireNonNegative(lives), LifeState.State.INVULNERABLE); + LifeState vulnerability = new LifeState(ArgumentChecker.requireNonNegative(lives), LifeState.State.VULNERABLE); + this.lifeStates = Sq.repeat(Ticks.PLAYER_INVULNERABLE_TICKS,invulnerability).concat(Sq.constant(vulnerability)); + this.maxBombs = ArgumentChecker.requireNonNegative(maxBombs); + this.bombRange = ArgumentChecker.requireNonNegative(bombRange); + } + + /** + * @return the player's ID + */ + public PlayerID id() { + return id(); + } + + /** + * @return the player's life states + */ + public Sq lifeStates() { + return lifeStates; + } + + /** + * @return the sequence related to the player's next life + */ + public Sq statesForNextLife() { + LifeState dying = new LifeState(lives(), LifeState.State.DYING); + Sq nextLifeState = Sq.repeat(Ticks.PLAYER_DYING_TICKS, dying); + + int newLives = lives() - 1; + + if (newLives >= 0) { + LifeState dead = new LifeState(newLives, LifeState.State.DEAD); + nextLifeState = nextLifeState.concat(Sq.constant(dead)); + } else { + LifeState invulnerable = new LifeState(newLives, LifeState.State.INVULNERABLE); + LifeState vulnerable = new LifeState(newLives, LifeState.State.VULNERABLE); + + nextLifeState = nextLifeState.concat(Sq.repeat(Ticks.PLAYER_INVULNERABLE_TICKS,invulnerable)); + nextLifeState = nextLifeState.concat(Sq.constant(vulnerable)); + + } + return nextLifeState; + } + + /** + * @return the current life state of the player + */ + public LifeState lifeState() { + return lifeStates.head(); + } + + /** + * @return the current number of lifes of the player + */ + public int lives() { + return lifeStates.head().lives(); + } + + /** + * @return true is the player has more than 0 lives + */ + public boolean isAlive() { + return lives() >= 0; + } + + /** + * @return the directed position sequence of the player + */ + public Sq directedPositions() { + return directedPos; + } + + /** + * @return the position of the player + */ + public SubCell position() { + return directedPos.head().position(); + } + + /** + * @return the current direction of the player + */ + public Direction direction() { + return directedPos.head().direction(); + } + + /** + * @return the maximum number of bombs that the player can use + */ + public int maxBombs() { + return maxBombs; + } + + /** + * @return a new Player with the new maximum of bombs + */ + public Player withMaxBombs(int newMaxBombs) { + return new Player(id, lifeStates, directedPos, newMaxBombs, bombRange); + } + + /** + * @return the range of the player's bomb + */ + public int bombRange() { + return bombRange; + } + + /** + * @return a new Player with the new bomb range + */ + public Player withBombRange(int newBombRange) { + return new Player(id, lifeStates, directedPos, maxBombs, newBombRange); + } + + /** + * @return a new bomb posed by the Player + */ + public Bomb newBomb() { + return new Bomb(id, position().containingCell(), Ticks.BOMB_FUSE_TICKS, bombRange); + } +} -- cgit v1.2.3