aboutsummaryrefslogtreecommitdiff
path: root/src/ch/epfl/xblast/server/GameState.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/ch/epfl/xblast/server/GameState.java')
-rw-r--r--src/ch/epfl/xblast/server/GameState.java353
1 files changed, 264 insertions, 89 deletions
diff --git a/src/ch/epfl/xblast/server/GameState.java b/src/ch/epfl/xblast/server/GameState.java
index 1abe17a..0d381db 100644
--- a/src/ch/epfl/xblast/server/GameState.java
+++ b/src/ch/epfl/xblast/server/GameState.java
@@ -8,6 +8,7 @@ import java.util.function.Function;
8import java.util.stream.Collectors; 8import java.util.stream.Collectors;
9import java.util.stream.Stream; 9import java.util.stream.Stream;
10 10
11
11/** 12/**
12 * GameState representing the current game state. 13 * GameState representing the current game state.
13 * 14 *
@@ -102,12 +103,14 @@ public final class GameState {
102 private static List<Sq<Cell>> nextBlasts(List<Sq<Cell>> blasts0, Board board0, List<Sq<Sq<Cell>>> explosions0) { 103 private static List<Sq<Cell>> nextBlasts(List<Sq<Cell>> blasts0, Board board0, List<Sq<Sq<Cell>>> explosions0) {
103 return Stream.concat( 104 return Stream.concat(
104 blasts0.stream() 105 blasts0.stream()
105 .filter(blastSeq -> !blastSeq.tail().isEmpty()) 106 .filter(b -> !b.tail().isEmpty())
106 .filter(blastSeq -> board0.blockAt(blastSeq.head()).isFree()) 107 .filter(b -> board0.blockAt(b.head()).isFree())
107 .map(Sq::tail), 108 .map(Sq::tail),
108 explosions0.stream() 109 explosions0.stream()
110 .filter(e -> !e.isEmpty())
109 .map(Sq::head) 111 .map(Sq::head)
110 ).collect(Collectors.toList()); 112 .filter(b -> !b.isEmpty()))
113 .collect(Collectors.toList());
111 } 114 }
112 115
113 /** 116 /**
@@ -119,29 +122,36 @@ public final class GameState {
119 * @return the next board 122 * @return the next board
120 */ 123 */
121 private static Board nextBoard(Board board0, Set<Cell> consumedBonuses, Set<Cell> blastedCells1) { 124 private static Board nextBoard(Board board0, Set<Cell> consumedBonuses, Set<Cell> blastedCells1) {
122 List<Sq<Block>> blocks0 = board0.getBlocks(); 125 return new Board(Cell.ROW_MAJOR_ORDER.stream()
123 List<Sq<Block>> blocks1 = new ArrayList<>(); 126 .map(c -> GameState.nextBlockSeq(c, board0.blocksAt(c), consumedBonuses, blastedCells1))
124 127 .collect(Collectors.toList()));
125 int i = 0; 128 }
126 for (Sq<Block> blockSq : blocks0) {
127 int cellId = blocks0.get(i).hashCode();
128 Block block = blockSq.head();
129 if (((HashSet) consumedBonuses).contains(cellId) && block.isBonus()) {
130 blocks1.add(Sq.constant(Block.FREE));
131 } else if (((HashSet) blastedCells1).contains(cellId) && (block == Block.DESTRUCTIBLE_WALL || block.isBonus())) {
132 if (block == Block.DESTRUCTIBLE_WALL) {
133 Block bonus = randomBonus();
134 blocks1.add(Sq.repeat(Ticks.WALL_CRUMBLING_TICKS, Block.CRUMBLING_WALL).concat(Sq.constant(bonus)));
135 } else {
136 blocks1.add(Sq.repeat(Ticks.BONUS_DISAPPEARING_TICKS, block).concat(Sq.constant(Block.FREE)));
137 }
138 } else {
139 blocks1.add(blockSq.tail());
140 }
141 i++;
142 }
143 129
144 return new Board(blocks1); 130 /**
131 * Returns the next Block sequence for the given cell according to the current state and given events.
132 *
133 * @param c the Cell
134 * @param bs0 the previous Block sequence
135 * @param consumedBonuses the bonus consumption event
136 * @param blastedCells1 the new Cell blast events
137 * @return the new Block sequence
138 */
139 private static Sq<Block> nextBlockSeq(Cell c, Sq<Block> bs0, Set<Cell> consumedBonuses, Set<Cell> blastedCells1) {
140 Block b = bs0.head();
141
142 if (consumedBonuses.contains(c) && b.isBonus())
143 return Sq.constant(Block.FREE);
144
145 if (blastedCells1.contains(c))
146 if (b == Block.DESTRUCTIBLE_WALL)
147 return Sq.repeat(Ticks.WALL_CRUMBLING_TICKS, Block.CRUMBLING_WALL)
148 .concat(Sq.constant(GameState.randomBonus()));
149
150 else if (b.isBonus())
151 return Sq.repeat(Ticks.BONUS_DISAPPEARING_TICKS, b)
152 .concat(Sq.constant(Block.FREE));
153
154 return bs0.tail();
145 } 155 }
146 156
147 /** 157 /**
@@ -155,15 +165,142 @@ public final class GameState {
155 * @param speedChangeEvents the speed change events 165 * @param speedChangeEvents the speed change events
156 * @return the next player list 166 * @return the next player list
157 */ 167 */
158 private static List<Player> nextPlayers( 168 private static List<Player> nextPlayers(List<Player> players0, Map<PlayerID, Bonus> playerBonuses,
159 List<Player> players0, 169 Set<Cell> bombedCells1, Board board1, Set<Cell> blastedCells1,
160 Map<PlayerID, Bonus> playerBonuses, 170 Map<PlayerID, Optional<Direction>> speedChangeEvents) {
161 Set<Cell> bombedCells1, 171
162 Board board1, 172 return players0.stream()
163 Set<Cell> blastedCells1, 173 .map(p -> {
164 Map<PlayerID, Optional<Direction>> speedChangeEvents) { 174 Optional<Direction> speedChangeEvent = speedChangeEvents.get(p.id());
165 //ToDo 175 Direction requestedDirection = speedChangeEvent != null ? speedChangeEvent.orElse(null) : null;
166 return players0; 176 return GameState.nextPlayer(p, playerBonuses.get(p.id()), bombedCells1, board1, blastedCells1, requestedDirection);
177 })
178 .collect(Collectors.toList());
179 }
180
181 private static Player nextPlayer(Player players0, Bonus playerBonus,
182 Set<Cell> bombedCells1, Board board1, Set<Cell> blastedCells1,
183 Direction requestedDirection) {
184
185 Sq<Player.DirectedPosition> directedPositions1 = GameState.nextPath(players0, requestedDirection);
186
187 // Advance of one SubCell on the player's path
188 directedPositions1 = directedPositions1.tail();
189
190 //Check possible collisions and update the Sequence if necessary (kinda ugly right now)
191 directedPositions1 = GameState.handleCollisions(players0, directedPositions1, board1, bombedCells1);
192
193 // Apply damages and generate a new LifeState Sequence
194 Sq<Player.LifeState> lifeStates1 = GameState.nextLifeState(players0, directedPositions1, blastedCells1);
195
196 // Create the new player given the new parameters
197 Player p1 = new Player(players0.id(), lifeStates1, directedPositions1, players0.maxBombs(), players0.bombRange());
198
199 // Update the capacities of the player given the possible bonus
200 if (playerBonus != null)
201 p1 = playerBonus.applyTo(p1);
202
203 return p1;
204 }
205
206 /**
207 * Generate the new Sequence of Directed Positions.
208 *
209 * @param player0
210 * @param requestedDirection
211 * @return
212 */
213 private static Sq<Player.DirectedPosition> nextPath(Player player0, Direction requestedDirection) {
214 if (!player0.lifeState().canMove())
215 return Player.DirectedPosition.stopped(player0.directedPositions().head());
216
217 if (requestedDirection == null)
218 requestedDirection = player0.direction();
219
220 if (player0.direction().isParallelTo(requestedDirection))
221 return Player.DirectedPosition.moving(new Player.DirectedPosition(player0.position(), requestedDirection));
222
223 if (player0.direction().isPerpendicularTo(requestedDirection)) {
224 Player.DirectedPosition nextCentralSubCell = GameState.projectedDirectedPosition(player0, player0.directedPositions());
225 Sq<Player.DirectedPosition> toNextCentralSubCell = player0.directedPositions().takeWhile(dp -> !dp.position().isCentral());
226 Player.DirectedPosition centralSubCellDirectedPosition = new Player.DirectedPosition(nextCentralSubCell.position(), requestedDirection);
227 Sq<Player.DirectedPosition> pastNextCentralSubCell = Player.DirectedPosition.moving(centralSubCellDirectedPosition);
228 return toNextCentralSubCell.concat(pastNextCentralSubCell);
229 }
230
231 return player0.directedPositions();
232 }
233
234 /**
235 * Check possible collisions and update the Sequence if necessary (kinda ugly right now)
236 *
237 * @param player0
238 * @param projectedPath
239 * @param board1
240 * @param bombedCells1
241 * @return
242 */
243 private static Sq<Player.DirectedPosition> handleCollisions(Player player0,
244 Sq<Player.DirectedPosition> projectedPath,
245 Board board1, Set<Cell> bombedCells1) {
246
247 Cell projectedCell = GameState.projectedDirectedPosition(player0, projectedPath).position().containingCell();
248 if (GameState.isColliding(player0, projectedCell, board1, bombedCells1))
249 return Sq.repeat(1, player0.directedPositions().head())
250 .concat(projectedPath);
251
252 return projectedPath;
253 }
254
255 /**
256 * @param player0
257 * @param projectedPath
258 * @return
259 */
260
261 private static Player.DirectedPosition projectedDirectedPosition(Player player0, Sq<Player.DirectedPosition> projectedPath) {
262 if (!player0.lifeState().canMove())
263 return new Player.DirectedPosition(player0.position(), player0.direction());
264
265 return projectedPath.tail()
266 .findFirst(directedPos -> directedPos.position().isCentral());
267 }
268
269 /**
270 * @param player0
271 * @param projectedCell
272 * @param board1
273 * @param bombedCells1
274 * @return
275 */
276 private static boolean isColliding(Player player0, Cell projectedCell, Board board1, Set<Cell> bombedCells1) {
277 if (!board1.blockAt(projectedCell).canHostPlayer())
278 return true;
279
280 if (bombedCells1.contains(projectedCell) && projectedCell.equals(player0.position().containingCell()))
281 if (player0.position().distanceToCentral() <= Board.BOMB_BLOCKING_DISTANCE)
282 return true;
</