aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPacien TRAN-GIRARD2016-05-06 14:55:41 +0200
committerPacien TRAN-GIRARD2016-05-06 14:55:41 +0200
commitcba582ddc6a77e0d1a2725c3f7ca079e66479888 (patch)
tree3cbbcb83a8bee62d1dff86ed0fcfac81801fea0d /src
parente8d654f41294d686dc5c5213fd49a7ecf121d3df (diff)
downloadxblast-cba582ddc6a77e0d1a2725c3f7ca079e66479888.tar.gz
Modularize next game state transition
Diffstat (limited to 'src')
-rw-r--r--src/ch/epfl/xblast/server/GameState.java373
-rw-r--r--src/ch/epfl/xblast/server/GameStateTransitioner.java349
2 files changed, 372 insertions, 350 deletions
diff --git a/src/ch/epfl/xblast/server/GameState.java b/src/ch/epfl/xblast/server/GameState.java
index b304a4d..564ef38 100644
--- a/src/ch/epfl/xblast/server/GameState.java
+++ b/src/ch/epfl/xblast/server/GameState.java
@@ -6,7 +6,6 @@ import ch.epfl.xblast.*;
6import java.util.*; 6import java.util.*;
7import java.util.function.Function; 7import java.util.function.Function;
8import java.util.stream.Collectors; 8import java.util.stream.Collectors;
9import java.util.stream.Stream;
10 9
11 10
12/** 11/**
@@ -59,329 +58,26 @@ public final class GameState {
59 } 58 }
60 59
61 /** 60 /**
62 * Maps bombs to their owning player ID. 61 * Maps the given bombs to their position.
63 *
64 * @param b the list of bombs
65 * @return the mapping
66 */
67 private static Map<PlayerID, List<Bomb>> mapBombsToPlayers(List<Bomb> b) {
68 return b.stream().collect(Collectors.groupingBy(Bomb::ownerId));
69 }
70
71 /**
72 * Computes the next state of a blast.
73 *
74 * @param blasts0 existing particles
75 * @param board0 the game's board
76 * @param explosions0 active explosions
77 * @return the position of the explosion's particles for the next state.
78 */
79 private static List<Sq<Cell>> nextBlasts(List<Sq<Cell>> blasts0, Board board0, List<Sq<Sq<Cell>>> explosions0) {
80 return Stream.concat(
81 blasts0.stream()
82 .filter(b -> board0.blockAt(b.head()).isFree())
83 .map(Sq::tail),
84 explosions0.stream()
85 .filter(e -> !e.isEmpty())
86 .map(Sq::head))
87 .filter(b -> !b.isEmpty())
88 .collect(Collectors.toList());
89 }
90
91 /**
92 * Computes and returns the next board state of the given board according to the given events.
93 *
94 * @param board0 the previous board
95 * @param consumedBonuses the set of consumed bonuses
96 * @param blastedCells1 the set of newly blasted cells
97 * @return the next board
98 */
99 private static Board nextBoard(Board board0, Set<Cell> consumedBonuses, Set<Cell> blastedCells1) {
100 return new Board(Cell.ROW_MAJOR_ORDER.stream()
101 .map(c -> GameState.nextBlockSeq(c, board0.blocksAt(c), consumedBonuses, blastedCells1))
102 .collect(Collectors.toList()));
103 }
104
105 /**
106 * Returns the next Block sequence for the given cell according to the current state and given events.
107 *
108 * @param c the Cell
109 * @param bs0 the previous Block sequence
110 * @param consumedBonuses the bonus consumption event
111 * @param blastedCells1 the new Cell blast events
112 * @return the new Block sequence
113 */
114 private static Sq<Block> nextBlockSeq(Cell c, Sq<Block> bs0, Set<Cell> consumedBonuses, Set<Cell> blastedCells1) {
115 Block b = bs0.head();
116
117 if (consumedBonuses.contains(c) && b.isBonus())
118 return Sq.constant(Block.FREE);
119
120 if (blastedCells1.contains(c))
121 if (b == Block.DESTRUCTIBLE_WALL)
122 return Sq.repeat(Ticks.WALL_CRUMBLING_TICKS, Block.CRUMBLING_WALL)
123 .concat(Sq.constant(Block.getRandomBonusBlock()));
124
125 else if (b.isBonus())
126 return Sq.repeat(Ticks.BONUS_DISAPPEARING_TICKS, b)
127 .concat(Sq.constant(Block.FREE));
128
129 return bs0.tail();
130 }
131
132 /**
133 * Computes and returns the next player list given the current one and the given events and states.
134 *
135 * @param players0 the previous player list
136 * @param playerBonuses the map of player bonuses
137 * @param bombedCells1 the set of newly bombed cells
138 * @param board1 the newly updated board
139 * @param blastedCells1 the set of newly blasted cells
140 * @param speedChangeEvents the speed change events
141 * @return the next player list
142 */
143 private static List<Player> nextPlayers(List<Player> players0, Map<PlayerID, Bonus> playerBonuses,
144 Set<Cell> bombedCells1, Board board1, Set<Cell> blastedCells1,
145 Map<PlayerID, Optional<Direction>> speedChangeEvents) {
146
147 return players0.stream()
148 .map(p -> GameState.nextPlayer(
149 p, playerBonuses.get(p.id()),
150 bombedCells1, board1, blastedCells1,
151 speedChangeEvents.get(p.id())))
152 .collect(Collectors.toList());
153 }
154
155 /**
156 * Computes and returns the next State of a Player from the given events.
157 *
158 * @param player0 the Player
159 * @param playerBonus the optional Bonus to apply to the Player
160 * @param bombedCells1 the Set of bombed Cells
161 * @param board1 the updated Board
162 * @param blastedCells1 the Set of blasted Cells
163 * @param requestedDirection the Player's new requested Direction
164 * @return the next state of the Player
165 */
166 private static Player nextPlayer(Player player0, Bonus playerBonus,
167 Set<Cell> bombedCells1, Board board1, Set<Cell> blastedCells1,
168 Optional<Direction> requestedDirection) {
169
170 // 1. Compute the new path to follow
171 Sq<Player.DirectedPosition> updatedPath = GameState.nextPath(player0.directedPositions(), requestedDirection);
172
173 // 2. Follow the path if the Player can (moving life state and no collision)
174 Sq<Player.DirectedPosition> directedPos1 = GameState.moveAhead(player0, updatedPath, board1, bombedCells1);
175
176 // 3. Apply damages and generate a new LifeState Sequence
177 Sq<Player.LifeState> lifeStates1 = GameState.nextLifeState(player0, directedPos1, blastedCells1);
178
179 // 4. Create the new player given the new parameters
180 Player p1 = new Player(player0.id(), lifeStates1, directedPos1, player0.maxBombs(), player0.bombRange());
181
182 // 5. Update the capacities of the player given the possible bonus
183 if (!Objects.isNull(playerBonus))
184 p1 = playerBonus.applyTo(p1);
185
186 return p1;
187 }
188
189 /**
190 * Computes the new path to follow according to the Player's wishes and the Board constraints.
191 *
192 * @param p0 the current path
193 * @param newDir the new requested Direction
194 * @return the new path
195 */
196 private static Sq<Player.DirectedPosition> nextPath(Sq<Player.DirectedPosition> p0, Optional<Direction> newDir) {
197 if (Objects.isNull(newDir))
198 return p0;
199
200 if (!newDir.isPresent())
201 return GameState.stopPath(p0);
202
203 if (p0.head().direction().isPerpendicularTo(newDir.get()))
204 return GameState.pivotPath(Player.DirectedPosition.moving(p0.head()), newDir.get());
205
206 return Player.DirectedPosition.moving(new Player.DirectedPosition(p0.head().position(), newDir.get()));
207 }
208
209 /**
210 * Builds and returns a path stopping at the next central SubCell.
211 *
212 * @param p0 the current path
213 * @return the stop path
214 */
215 private static Sq<Player.DirectedPosition> stopPath(Sq<Player.DirectedPosition> p0) {
216 return GameState
217 .pathToNextCentralPosition(p0)
218 .concat(Player.DirectedPosition.stopped(GameState.nextCentral(p0)));
219 }
220
221 /**
222 * Builds and returns a pivot path reaching the next pivot SubCell and then rotating to the given Direction.
223 *
224 * @param p0 the initial path
225 * @param newDir the new Direction to follow when possible
226 * @return the pivot path
227 */
228 private static Sq<Player.DirectedPosition> pivotPath(Sq<Player.DirectedPosition> p0, Direction newDir) {
229 SubCell nextCentralPos = GameState.nextCentral(p0).position();
230
231 return GameState
232 .pathToNextCentralPosition(p0)
233 .concat(Player.DirectedPosition.moving(new Player.DirectedPosition(nextCentralPos, newDir)));
234 }
235
236 /**
237 * Returns the path to the next central SubCell.
238 *
239 * @param p the path to follow
240 * @return the truncated path
241 */
242 private static Sq<Player.DirectedPosition> pathToNextCentralPosition(Sq<Player.DirectedPosition> p) {
243 return p.takeWhile(dp -> !dp.position().isCentral());
244 }
245
246 /**
247 * Searches for and returns the next central SubCell reachable following the given path.
248 *
249 * @param p the path to follow
250 * @return the next central SubCell
251 */
252 private static Player.DirectedPosition nextCentral(Sq<Player.DirectedPosition> p) {
253 return p.findFirst(dp -> dp.position().isCentral());
254 }
255
256 /**
257 * Checks for possible collisions and update the path if necessary.
258 *
259 * @param path the current path projection
260 * @param board1 the updated Board