From ceb1ac5ca1e08095150c1dbb971540149a455673 Mon Sep 17 00:00:00 2001 From: Timothée Floure Date: Thu, 28 Apr 2016 14:16:41 +0200 Subject: Broken part 7 --- src/ch/epfl/xblast/RunLengthEncoder.java | 34 ++++++ src/ch/epfl/xblast/server/GameStateSerializer.java | 90 ++++++++++++++ src/ch/epfl/xblast/server/Level.java | 134 +++++++++++++++++++++ test/ch/epfl/xblast/GameStateSerializerTest.java | 39 ++++++ 4 files changed, 297 insertions(+) create mode 100644 src/ch/epfl/xblast/RunLengthEncoder.java create mode 100644 src/ch/epfl/xblast/server/GameStateSerializer.java create mode 100644 src/ch/epfl/xblast/server/Level.java create mode 100644 test/ch/epfl/xblast/GameStateSerializerTest.java diff --git a/src/ch/epfl/xblast/RunLengthEncoder.java b/src/ch/epfl/xblast/RunLengthEncoder.java new file mode 100644 index 0000000..a3c8a88 --- /dev/null +++ b/src/ch/epfl/xblast/RunLengthEncoder.java @@ -0,0 +1,34 @@ +package ch.epfl.xblast; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Timothée FLOURE (257420) + */ +public final class RunLengthEncoder { + + /** + * Encode the given Byte sequence using the run length encoding. + * + * @param input the given byte sequence + * @return the encoded byte sequence + */ + public static List encode(List input) { + List output = new ArrayList<>(); + + return output; + } + + /** + * Decode the given Byte sequence using the run length encoding. + * + * @param input the given encoded byte sequence + * @return the decoded byte sequence + */ + public static List decode(List input) { + List output = new ArrayList<>(); + + return output; + } +} diff --git a/src/ch/epfl/xblast/server/GameStateSerializer.java b/src/ch/epfl/xblast/server/GameStateSerializer.java new file mode 100644 index 0000000..4a133e5 --- /dev/null +++ b/src/ch/epfl/xblast/server/GameStateSerializer.java @@ -0,0 +1,90 @@ +package ch.epfl.xblast.server; + +import ch.epfl.xblast.Cell; +import ch.epfl.xblast.Direction; +import ch.epfl.xblast.RunLengthEncoder; +import ch.epfl.xblast.server.painter.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Timothée FLOURE (257420) + */ +public final class GameStateSerializer { + + /** + * @param painter + * @param board + * @return + */ + private static List serializeBoard(BoardPainter painter, Board board) { + return RunLengthEncoder.encode(Cell.SPIRAL_ORDER.stream() + .map(c -> painter.byteForCell(board, c)) + .collect(Collectors.toList())); + } + + private static byte serializeBlast(Set blastedCells, Cell cell) { + return ExplosionPainter.byteForBlast( + blastedCells.contains(cell.neighbor(Direction.N)), + blastedCells.contains(cell.neighbor(Direction.E)), + blastedCells.contains(cell.neighbor(Direction.S)), + blastedCells.contains(cell.neighbor(Direction.W))); + } + + private static byte serializeExplosion(Map bombedCells, Set blastedCells, Cell cell) { + if (bombedCells.containsKey(cell)) + return ExplosionPainter.byteForBomb(bombedCells.get(cell)); + else + return serializeBlast(blastedCells, cell); + } + + /** + * @param bombedCells + * @param blastedCells + * @return + */ + private static List serializeExplosions(Map bombedCells, Set blastedCells) { + return RunLengthEncoder.encode(Cell.ROW_MAJOR_ORDER.stream() + .map(c -> serializeExplosion(bombedCells, blastedCells, c)) + .collect(Collectors.toList())); + } + + /** + * Serialize a whole game state. + * + * @param boardPainter board painter related to the actual level + * @param gameState GameState to be serialized + * @return the serialized game state + */ + public static List serialize(BoardPainter boardPainter, GameState gameState) { + List output = new ArrayList<>(); + List data = new ArrayList<>(); + + // Board + data.addAll(serializeBoard(boardPainter, gameState.board())); + + // Blasts and Bombs + data.addAll(serializeExplosions(gameState.bombedCells(), gameState.blastedCells())); + + // Players + for (Player player : gameState.players()) { + List serializedPlayer = new ArrayList<>(); + serializedPlayer.add((byte) player.lives()); + serializedPlayer.add((byte) player.position().x()); + serializedPlayer.add((byte) player.position().y()); + serializedPlayer.add(PlayerPainter.byteForPlayer(player, gameState.ticks())); + + data.addAll(serializedPlayer); + } + + // Ticks + data.add((byte) (gameState.remainingTime() / 2)); + + // Build output + output.add((byte) data.size()); + output.addAll(data); + + return output; + } +} diff --git a/src/ch/epfl/xblast/server/Level.java b/src/ch/epfl/xblast/server/Level.java new file mode 100644 index 0000000..81bc85b --- /dev/null +++ b/src/ch/epfl/xblast/server/Level.java @@ -0,0 +1,134 @@ +package ch.epfl.xblast.server; + +import ch.epfl.xblast.*; +import ch.epfl.xblast.server.painter.*; + +import java.util.Arrays; +import java.util.List; +import java.util.HashMap; + +/** + * @author Timothée FLOURE (257420) + */ +public final class Level { + + /** Players' initial parameters **/ + private static final int PLAYER_INITIAL_LIVES = 5; + private static final int PLAYER_INITIAL_BOMB_MAXIMUM = 5; + private static final int PLAYER_INITIAL_BOMB_RANGE = 5; + + /** Players' initial positions (Ugly!) **/ + private static final Cell PLAYER_1_INITIAL_POSITION = new Cell(1,1); + private static final Cell PLAYER_2_INITIAL_POSITION = new Cell(16,1); + private static final Cell PLAYER_3_INITIAL_POSITION = new Cell(16,14); + private static final Cell PLAYER_4_INITIAL_POSITION = new Cell(1,14); + + /** Level values **/ + private final BoardPainter painter; + private final GameState initialState; + + /** + * Build the default board of the game. + * + * @return the default board + */ + private static BoardPainter buildDefaultBoardPainter() { + // Create the blocks map + HashMap blocksMap = new HashMap<>(); + + // Fill the blocks map + blocksMap.put(Block.FREE, BlockImage.IRON_FLOOR); + blocksMap.put(Block.DESTRUCTIBLE_WALL, BlockImage.EXTRA); + blocksMap.put(Block.CRUMBLING_WALL, BlockImage.EXTRA_O); + blocksMap.put(Block.INDESTRUCTIBLE_WALL, BlockImage.DARK_BLOCK); + blocksMap.put(Block.BONUS_BOMB, BlockImage.BONUS_BOMB); + blocksMap.put(Block.BONUS_RANGE, BlockImage.BONUS_RANGE); + + // Create and return the board painter + return new BoardPainter(blocksMap, BlockImage.IRON_FLOOR_S); + } + + /** + * Build the default game state of the game. + * + * @return the default game state + */ + private static GameState buildDefaultGameState() { + return new GameState(buildDefaultBoard(), buildDefaultPlayers()); + } + + /** + * Build the default board of the game. + * + * @return the default board. + */ + private static Board buildDefaultBoard() { + + // Ugly! + Block __ = Block.FREE; + Block XX = Block.INDESTRUCTIBLE_WALL; + Block xx = Block.DESTRUCTIBLE_WALL; + + return Board.ofQuadrantNWBlocksWalled( + Arrays.asList( + Arrays.asList(__, __, __, __, __, xx, __), + Arrays.asList(__, XX, xx, XX, xx, XX, xx), + Arrays.asList(__, xx, __, __, __, xx, __), + Arrays.asList(xx, XX, __, XX, XX, XX, XX), + Arrays.asList(__, xx, __, xx, __, __, __), + Arrays.asList(xx, XX, xx, XX, xx, XX, __))); + } + + /** + * Build the default players of the games. + * + * @return a list of the 4 players built using the default parameters. + */ + private static List buildDefaultPlayers() { + // Ugly! + return Arrays.asList( + new Player(PlayerID.PLAYER_1, PLAYER_INITIAL_LIVES, PLAYER_1_INITIAL_POSITION, + PLAYER_INITIAL_BOMB_MAXIMUM, PLAYER_INITIAL_BOMB_RANGE), + new Player(PlayerID.PLAYER_2, PLAYER_INITIAL_LIVES, PLAYER_2_INITIAL_POSITION, + PLAYER_INITIAL_BOMB_MAXIMUM, PLAYER_INITIAL_BOMB_RANGE), + new Player(PlayerID.PLAYER_3, PLAYER_INITIAL_LIVES, PLAYER_3_INITIAL_POSITION, + PLAYER_INITIAL_BOMB_MAXIMUM, PLAYER_INITIAL_BOMB_RANGE), + new Player(PlayerID.PLAYER_4, PLAYER_INITIAL_LIVES, PLAYER_4_INITIAL_POSITION, + PLAYER_INITIAL_BOMB_MAXIMUM, PLAYER_INITIAL_BOMB_RANGE) + ); + } + + /** + * Level build with the default images and the default players/explosions/board parameters. + */ + public static final Level DEFAULT_LEVEL = new Level(buildDefaultBoardPainter(), buildDefaultGameState()); + + /** + * Instantiates a new level. + * + * @param painter painter related to the level + * @param initialState initial game state of the level + */ + public Level(BoardPainter painter, GameState initialState) { + this.painter = painter; + this.initialState = initialState; + } + + /** + * Returns the painter related to the current level. + * + * @return the painter related to the current level + */ + public BoardPainter painter() { + return this.painter; + } + + /** + * Returns the initial game state ot the level. + * + * @return the initial game state ot the level + */ + public GameState initialState() { + return this.initialState; + } +} diff --git a/test/ch/epfl/xblast/GameStateSerializerTest.java b/test/ch/epfl/xblast/GameStateSerializerTest.java new file mode 100644 index 0000000..a701d2b --- /dev/null +++ b/test/ch/epfl/xblast/GameStateSerializerTest.java @@ -0,0 +1,39 @@ +package ch.epfl.xblast; + +import ch.epfl.xblast.server.*; +import ch.epfl.xblast.server.Level; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Timothée FLOURE (257420) + */ +public class GameStateSerializerTest { + + @Test + public void GameStateSerializerTest() { + List integerExpectedValues = Arrays.asList(121, -50, 2, 1, -2, 0, 3, 1, 3, 1, -2, 0, 1, 1, 3, 1, 3, + 1, 3, 1, 1, -2, 0, 1, 3, 1, 3, -2, 0, -1, 1, 3, 1, 3, 1, + 3, 1, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 1, 0, 0, 3, 1, 3, 1, 0, 0, 1, 1, 3, 1, 1, 0, 0, 1, 3, + 1, 3, 0, 0, -1, 1, 3, 1, 1, -5, 2, 3, 2, 3, -5, 2, 3, 2, + 3, 1, -2, 0, 3, -2, 0, 1, 3, 2, 1, 2, 4, -128, 16, -63, + 16, 3, 24, 24, 6, 3, -40, 24, 26, 3, -40, -72, 46, 3, 24, + -72, 66, 60); + List expectedValues = new ArrayList<>(); + + for (Integer i : integerExpectedValues) { + expectedValues.add((byte) i.intValue()); + } + + Assert.assertEquals( + expectedValues, + GameStateSerializer.serialize(Level.DEFAULT_LEVEL.painter(), Level.DEFAULT_LEVEL.initialState()) + ); + } +} -- cgit v1.2.3