diff options
Diffstat (limited to 'src/ch/epfl/xblast/server/GameState.java')
-rw-r--r-- | src/ch/epfl/xblast/server/GameState.java | 353 |
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; | |||
8 | import java.util.stream.Collectors; | 8 | import java.util.stream.Collectors; |
9 | import java.util.stream.Stream; | 9 | import 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; | ||