diff options
-rw-r--r-- | src/ch/epfl/xblast/ArgumentChecker.java | 29 | ||||
-rw-r--r-- | src/ch/epfl/xblast/Lists.java | 39 | ||||
-rw-r--r-- | src/ch/epfl/xblast/PlayerAction.java | 32 | ||||
-rw-r--r-- | src/ch/epfl/xblast/PlayerID.java | 11 | ||||
-rw-r--r-- | src/ch/epfl/xblast/Time.java | 13 | ||||
-rw-r--r-- | src/ch/epfl/xblast/client/Client.java | 360 | ||||
-rw-r--r-- | src/ch/epfl/xblast/client/GameState.java | 2 | ||||
-rw-r--r-- | src/ch/epfl/xblast/client/KeyboardEventHandler.java | 29 | ||||
-rw-r--r-- | src/ch/epfl/xblast/client/Main.java | 28 | ||||
-rw-r--r-- | src/ch/epfl/xblast/client/XBlastComponent.java | 103 | ||||
-rw-r--r-- | src/ch/epfl/xblast/server/Bonus.java | 2 | ||||
-rw-r--r-- | src/ch/epfl/xblast/server/GameState.java | 18 | ||||
-rw-r--r-- | src/ch/epfl/xblast/server/GameStateTransitioner.java | 2 | ||||
-rw-r--r-- | src/ch/epfl/xblast/server/Main.java | 29 | ||||
-rw-r--r-- | src/ch/epfl/xblast/server/Server.java | 341 | ||||
-rw-r--r-- | src/ch/epfl/xblast/server/painter/PlayerPainter.java | 42 | ||||
-rw-r--r-- | test/ch/epfl/xblast/client/PlayerTest.java | 40 | ||||
-rw-r--r-- | test/ch/epfl/xblast/simulation/GraphicalSimulation.java | 19 |
18 files changed, 1102 insertions, 37 deletions
diff --git a/src/ch/epfl/xblast/ArgumentChecker.java b/src/ch/epfl/xblast/ArgumentChecker.java index 7e77b61..56f8acd 100644 --- a/src/ch/epfl/xblast/ArgumentChecker.java +++ b/src/ch/epfl/xblast/ArgumentChecker.java | |||
@@ -59,4 +59,33 @@ public final class ArgumentChecker { | |||
59 | return s; | 59 | return s; |
60 | } | 60 | } |
61 | 61 | ||
62 | /** | ||
63 | * Returns the element from the array at the requested index, or null if it cannot be retrieved. | ||
64 | * | ||
65 | * @param array the array | ||
66 | * @param index the index | ||
67 | * @param <T> the type of element | ||
68 | * @return the requested element, or null | ||
69 | */ | ||
70 | public static <T> T getOrNull(T[] array, int index) { | ||
71 | if (Objects.isNull(array) || index < 0 || index >= array.length) | ||
72 | return null; | ||
73 | else | ||
74 | return array[index]; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Parses and returns an integer, or return null on error. | ||
79 | * | ||
80 | * @param str the integer to parse | ||
81 | * @return the parsed integer, or null | ||
82 | */ | ||
83 | public static Integer parseIntOrNull(String str) { | ||
84 | try { | ||
85 | return Integer.parseInt(str); | ||
86 | } catch (NumberFormatException | NullPointerException e) { | ||
87 | return null; | ||
88 | } | ||
89 | } | ||
90 | |||
62 | } | 91 | } |
diff --git a/src/ch/epfl/xblast/Lists.java b/src/ch/epfl/xblast/Lists.java index 777fab2..9bd527b 100644 --- a/src/ch/epfl/xblast/Lists.java +++ b/src/ch/epfl/xblast/Lists.java | |||
@@ -2,7 +2,6 @@ package ch.epfl.xblast; | |||
2 | 2 | ||
3 | import java.util.*; | 3 | import java.util.*; |
4 | import java.util.stream.Collectors; | 4 | import java.util.stream.Collectors; |
5 | import java.util.stream.IntStream; | ||
6 | import java.util.stream.Stream; | 5 | import java.util.stream.Stream; |
7 | 6 | ||
8 | /** | 7 | /** |
@@ -207,10 +206,36 @@ public final class Lists { | |||
207 | if (Objects.isNull(kl) || Objects.isNull(vl) || kl.size() != vl.size()) | 206 | if (Objects.isNull(kl) || Objects.isNull(vl) || kl.size() != vl.size()) |
208 | throw new IllegalArgumentException(); | 207 | throw new IllegalArgumentException(); |
209 | 208 | ||
210 | return Collections.unmodifiableMap(IntStream | 209 | Map<K, V> m = new HashMap<>(); |
211 | .range(0, kl.size()).mapToObj(i -> i) | 210 | Iterator<K> ki = kl.iterator(); |
212 | .filter(i -> Objects.nonNull(vl.get(i))) | 211 | Iterator<V> vi = vl.iterator(); |
213 | .collect(Collectors.toMap(kl::get, vl::get))); | 212 | |
213 | while (ki.hasNext() && vi.hasNext()) | ||
214 | m.put(ki.next(), vi.next()); | ||
215 | |||
216 | return Collections.unmodifiableMap(m); | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * Maps linearly two lists, adjusting their respective size by truncating the key list or completing the value list | ||
221 | * with null values. | ||
222 | * | ||
223 | * @param kl the keys list | ||
224 | * @param vl the values list | ||
225 | * @param <K> the key type | ||
226 | * @param <V> the value type | ||
227 | * @return the map | ||
228 | */ | ||
229 | public static <K, V> Map<K, V> linearAdjustedMap(List<K> kl, List<V> vl) { | ||
230 | if (Objects.isNull(kl) || Objects.isNull(vl)) | ||
231 | throw new IllegalArgumentException(); | ||
232 | |||
233 | if (kl.size() <= vl.size()) | ||
234 | return Lists.linearMap(kl, vl.subList(0, kl.size())); | ||
235 | else | ||
236 | return Lists.linearMap( | ||
237 | kl, | ||
238 | concatenated(Arrays.asList(vl, Collections.nCopies(kl.size() - vl.size(), null)))); | ||
214 | } | 239 | } |
215 | 240 | ||
216 | /** | 241 | /** |
@@ -225,6 +250,8 @@ public final class Lists { | |||
225 | */ | 250 | */ |
226 | public static <K, IK, V> Map<K, V> traverseMaps(Map<K, IK> m1, Map<IK, V> m2) { | 251 | public static <K, IK, V> Map<K, V> traverseMaps(Map<K, IK> m1, Map<IK, V> m2) { |
227 | return Collections.unmodifiableMap(m1.entrySet().stream() | 252 | return Collections.unmodifiableMap(m1.entrySet().stream() |
253 | .filter(e -> Objects.nonNull(e.getValue())) | ||
254 | .filter(e -> Objects.nonNull(m2.get(e.getValue()))) | ||
228 | .collect(Collectors.toMap(Map.Entry::getKey, e -> m2.get(e.getValue())))); | 255 | .collect(Collectors.toMap(Map.Entry::getKey, e -> m2.get(e.getValue())))); |
229 | } | 256 | } |
230 | 257 | ||
@@ -238,6 +265,8 @@ public final class Lists { | |||
238 | */ | 265 | */ |
239 | public static <K, V> Map<K, V> invertMap(Map<V, K> m) { | 266 | public static <K, V> Map<K, V> invertMap(Map<V, K> m) { |
240 | return Collections.unmodifiableMap(m.entrySet().stream() | 267 | return Collections.unmodifiableMap(m.entrySet().stream() |
268 | .filter(e -> Objects.nonNull(e.getKey())) | ||
269 | .filter(e -> Objects.nonNull(e.getValue())) | ||
241 | .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))); | 270 | .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))); |
242 | } | 271 | } |
243 | 272 | ||
diff --git a/src/ch/epfl/xblast/PlayerAction.java b/src/ch/epfl/xblast/PlayerAction.java index 703bc9d..6ce12ba 100644 --- a/src/ch/epfl/xblast/PlayerAction.java +++ b/src/ch/epfl/xblast/PlayerAction.java | |||
@@ -1,5 +1,7 @@ | |||
1 | package ch.epfl.xblast; | 1 | package ch.epfl.xblast; |
2 | 2 | ||
3 | import java.util.Optional; | ||
4 | |||
3 | /** | 5 | /** |
4 | * The player action enum. | 6 | * The player action enum. |
5 | * | 7 | * |
@@ -14,6 +16,34 @@ public enum PlayerAction { | |||
14 | MOVE_S, | 16 | MOVE_S, |
15 | MOVE_W, | 17 | MOVE_W, |
16 | STOP, | 18 | STOP, |
17 | DROP_BOMB | 19 | DROP_BOMB; |
20 | |||
21 | public static PlayerAction fromByte(byte b) { | ||
22 | if ((int) b < 0 || (int) b >= PlayerAction.values().length) | ||
23 | throw new IllegalArgumentException(); | ||
24 | |||
25 | return PlayerAction.values()[(int) b]; | ||
26 | } | ||
27 | |||
28 | public byte toByte() { | ||
29 | return (byte) this.ordinal(); | ||
30 | } | ||
31 | |||
32 | public Optional<Direction> associatedSpeedChangeEvent() { | ||
33 | switch (this) { | ||
34 | case MOVE_N: | ||
35 | return Optional.of(Direction.N); | ||
36 | case MOVE_E: | ||
37 | return Optional.of(Direction.E); | ||
38 | case MOVE_S: | ||
39 | return Optional.of(Direction.S); | ||
40 | case MOVE_W: | ||
41 | return Optional.of(Direction.W); | ||
42 | case STOP: | ||
43 | return Optional.empty(); | ||
44 | default: | ||
45 | return null; | ||
46 | } | ||
47 | } | ||
18 | 48 | ||
19 | } | 49 | } |
diff --git a/src/ch/epfl/xblast/PlayerID.java b/src/ch/epfl/xblast/PlayerID.java index 9377fdf..72a48b9 100644 --- a/src/ch/epfl/xblast/PlayerID.java +++ b/src/ch/epfl/xblast/PlayerID.java | |||
@@ -28,4 +28,15 @@ public enum PlayerID { | |||
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | public static PlayerID fromByte(byte b) { | ||
32 | if ((int) b < 0 || (int) b >= PlayerAction.values().length) | ||
33 | throw new IllegalArgumentException(); | ||
34 | |||
35 | return PlayerID.values()[(int) b]; | ||
36 | } | ||
37 | |||
38 | public byte toByte() { | ||
39 | return (byte) this.ordinal(); | ||
40 | } | ||
41 | |||
31 | } | 42 | } |
diff --git a/src/ch/epfl/xblast/Time.java b/src/ch/epfl/xblast/Time.java index 7c84257..c53f1ef 100644 --- a/src/ch/epfl/xblast/Time.java +++ b/src/ch/epfl/xblast/Time.java | |||
@@ -28,4 +28,17 @@ public interface Time { | |||
28 | */ | 28 | */ |
29 | int NS_PER_S = 1000 * US_PER_S; | 29 | int NS_PER_S = 1000 * US_PER_S; |
30 | 30 | ||
31 | /** | ||
32 | * Pauses the current thread for the given duration. | ||
33 | * | ||
34 | * @param ns the sleep duration (ns) | ||
35 | */ | ||
36 | static void sleep(long ns) { | ||
37 | try { | ||
38 | Thread.sleep((long) (ns / 1E6), (int) (ns % 1E6)); | ||
39 | } catch (InterruptedException e) { | ||
40 | Thread.currentThread().interrupt(); | ||
41 | } | ||
42 | } | ||
43 | |||
31 | } | 44 | } |
diff --git a/src/ch/epfl/xblast/client/Client.java b/src/ch/epfl/xblast/client/Client.java new file mode 100644 index 0000000..24ca727 --- /dev/null +++ b/src/ch/epfl/xblast/client/Client.java | |||
@@ -0,0 +1,360 @@ | |||
1 | package ch.epfl.xblast.client; | ||
2 | |||
3 | import ch.epfl.xblast.Lists; | ||
4 | import ch.epfl.xblast.PlayerAction; | ||
5 | import ch.epfl.xblast.PlayerID; | ||
6 | import ch.epfl.xblast.Time; | ||
7 | import ch.epfl.xblast.server.Server; | ||
8 | |||
9 | import javax.swing.*; | ||
10 | import java.awt.*; | ||
11 | import java.io.IOException; | ||
12 | import java.lang.reflect.InvocationTargetException; | ||
13 | import java.net.InetSocketAddress; | ||
14 | import java.net.SocketAddress; | ||