├── .gitignore
├── README.md
├── config
├── Boss.py
├── config.ini
├── level1
│ └── Boss.py
├── level2
│ ├── Boss.py
│ ├── welcome_en.html
│ └── welcome_fr.html
├── level3
│ ├── Boss.py
│ ├── Tuto_6.jpg
│ ├── welcome_en.html
│ └── welcome_fr.html
├── level4
│ ├── Tuto_7.jpg
│ ├── welcome_en.html
│ └── welcome_fr.html
├── statement_en.html.tpl
├── statement_fr.html.tpl
└── stub.txt
├── full_rules_en.pdf
├── full_rules_fr.pdf
├── pom.xml
├── src
├── main
│ ├── java
│ │ └── com
│ │ │ └── codingame
│ │ │ ├── endscreen
│ │ │ └── EndScreenModule.java
│ │ │ ├── event
│ │ │ ├── Animation.java
│ │ │ ├── AnimationData.java
│ │ │ └── EventData.java
│ │ │ ├── game
│ │ │ ├── Closest.java
│ │ │ ├── Collision.java
│ │ │ ├── CommandManager.java
│ │ │ ├── Drone.java
│ │ │ ├── Entity.java
│ │ │ ├── Fish.java
│ │ │ ├── FishType.java
│ │ │ ├── Game.java
│ │ │ ├── GameSummaryManager.java
│ │ │ ├── Player.java
│ │ │ ├── Referee.java
│ │ │ ├── Scan.java
│ │ │ ├── Serializer.java
│ │ │ ├── Ugly.java
│ │ │ ├── Vector.java
│ │ │ ├── action
│ │ │ │ ├── Action.java
│ │ │ │ ├── ActionException.java
│ │ │ │ ├── ActionType.java
│ │ │ │ ├── MoveAction.java
│ │ │ │ └── WaitAction.java
│ │ │ └── exception
│ │ │ │ ├── GameException.java
│ │ │ │ └── InvalidInputException.java
│ │ │ └── view
│ │ │ ├── FrameViewData.java
│ │ │ ├── GameDataProvider.java
│ │ │ ├── GlobalViewData.java
│ │ │ ├── PlayerDto.java
│ │ │ └── ViewModule.java
│ └── resources
│ │ └── view
│ │ ├── .eslintrc.js
│ │ ├── assets
│ │ ├── Background-derriere.jpg
│ │ ├── Background-devant-D.png
│ │ ├── Background-devant-G.png
│ │ ├── Background-plantes.png
│ │ ├── blue.json
│ │ ├── blue.png
│ │ ├── dial_arrow.png
│ │ ├── dial_mid.png
│ │ ├── dial_side.png
│ │ ├── disc_black.png
│ │ ├── feedback.json
│ │ ├── feedback.png
│ │ ├── green.json
│ │ ├── green.png
│ │ ├── logo.png
│ │ ├── other.json
│ │ ├── other.png
│ │ ├── pink.json
│ │ ├── pink.png
│ │ ├── scan_green.json
│ │ ├── scan_green.png
│ │ ├── uglies.json
│ │ ├── uglies.png
│ │ ├── yellow.json
│ │ └── yellow.png
│ │ ├── config.js
│ │ ├── demo.js
│ │ ├── endscreen-module
│ │ ├── EndScreenModule.js
│ │ └── errors
│ │ │ └── MissingImageError.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── ts
│ │ ├── Deserializer.ts
│ │ ├── MessageBoxes.ts
│ │ ├── TooltipManager.ts
│ │ ├── ViewModule.ts
│ │ ├── assetConstants.ts
│ │ ├── darkness.ts
│ │ ├── events.ts
│ │ ├── gameConstants.ts
│ │ ├── global
│ │ │ ├── core.d.ts
│ │ │ └── global.d.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ │ └── tsconfig.json
└── test
│ ├── java
│ └── Fall2023Main.java
│ └── resources
│ └── log4j2.properties
├── starterAIs
├── README.md
├── SS_Starter.java
├── SS_Starter.js
├── SS_Starter.py
├── SS_Starter.rb
└── SS_Starter.ts
└── typescript
├── polyfill.js
├── readline.js
└── readline
└── index.d.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.project
3 | /.classpath
4 | /bin/
5 | .factorypath
6 | /.settings/
7 | .pydevproject
8 | src/main/resources/view/node_modules/
9 | src/main/resources/view/graphics/
10 | statement_en.html
11 | statement_fr.html
12 | JulienMain.java
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FallChallenge2023-SeabedSecurity
2 |
3 | Source code for CodinGame's Fall Challenge 2023 event.
4 |
5 | https://www.codingame.com/contests/fall-challenge-2023
6 |
7 | Community starter AIs are located here:
8 |
9 | https://github.com/CodinGame/FallChallenge2023-SeabedSecurity/tree/main/starterAIs
10 |
--------------------------------------------------------------------------------
/config/Boss.py:
--------------------------------------------------------------------------------
1 | while True:
2 | print('WAIT 0')
3 |
--------------------------------------------------------------------------------
/config/config.ini:
--------------------------------------------------------------------------------
1 | min_players=2
2 | max_players=2
3 | type=multi
--------------------------------------------------------------------------------
/config/level1/Boss.py:
--------------------------------------------------------------------------------
1 | redacted
2 |
--------------------------------------------------------------------------------
/config/level2/Boss.py:
--------------------------------------------------------------------------------
1 | redacted
2 |
--------------------------------------------------------------------------------
/config/level2/welcome_en.html:
--------------------------------------------------------------------------------
1 |
2 |
You've made it to the next league.
3 |
4 | The game is now played in darkness, your drones can only see fish in their
5 | light radius.
6 |
7 |
See the updated statement for details.
8 |
--------------------------------------------------------------------------------
/config/level2/welcome_fr.html:
--------------------------------------------------------------------------------
1 |
2 |
Vous venez d'atteindre la ligue supérieure.
3 |
4 | Le jeu se déroule maintenant dans l'obscurité, vos drones ne peuvent voir que les poissons
5 | dans leur rayon de lumière.
6 |
7 |
Consultez l'énoncé mis à jour pour plus de détails.
8 |
--------------------------------------------------------------------------------
/config/level3/Boss.py:
--------------------------------------------------------------------------------
1 | redacted
2 |
--------------------------------------------------------------------------------
/config/level3/Tuto_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodinGame/FallChallenge2023-SeabedSecurity/cd73b1ff2e80a34114eb1c402cc94b24080a5bed/config/level3/Tuto_6.jpg
--------------------------------------------------------------------------------
/config/level3/welcome_en.html:
--------------------------------------------------------------------------------
1 |
2 |
You've made it to the next league.
3 |
Creatures will now flee from the noise of drone engines!
4 |
You will now control a team of two drones.
5 |
6 |
See the updated statement for details.
7 |
--------------------------------------------------------------------------------
/config/level3/welcome_fr.html:
--------------------------------------------------------------------------------
1 |
2 |
Vous venez d'atteindre la ligue supérieure.
3 |
Les créatures fuieront le son des moteurs des drones!
4 |
Vous controllez maintenant une équipe de deux drones.
5 |
6 |
Consultez l'énoncé mis à jour pour plus de détails.
7 |
--------------------------------------------------------------------------------
/config/level4/Tuto_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodinGame/FallChallenge2023-SeabedSecurity/cd73b1ff2e80a34114eb1c402cc94b24080a5bed/config/level4/Tuto_7.jpg
--------------------------------------------------------------------------------
/config/level4/welcome_en.html:
--------------------------------------------------------------------------------
1 |
2 |
You've made it to the next league.
3 |
Sea monsters will attack drones that shine their light too close!
4 |
5 |
See the updated statement for details.
6 |
--------------------------------------------------------------------------------
/config/level4/welcome_fr.html:
--------------------------------------------------------------------------------
1 |
2 |
Vous venez d'atteindre la ligue supérieure.
3 |
Des monstres marins s'attaqueront à vos drones s'ils dirigent leur lumière trop près !
4 |
5 |
Consultez l'énoncé mis à jour pour plus de détails.
6 |
--------------------------------------------------------------------------------
/config/stub.txt:
--------------------------------------------------------------------------------
1 | STATEMENT
2 | Score points by scanning valuable fish faster than your opponent.
3 |
4 | read creatureCount:int
5 | loop creatureCount read creatureId:int color:int type:int
6 |
7 | gameloop
8 |
9 | read myScore:int
10 | read foeScore:int
11 |
12 | read myScanCount:int
13 | loop myScanCount read creatureId:int
14 | read foeScanCount:int
15 | loop foeScanCount read creatureId:int
16 |
17 | read myDroneCount:int
18 | loop myDroneCount read droneId:int droneX:int droneY:int emergency:int battery:int
19 |
20 | read foeDroneCount:int
21 | loop foeDroneCount read droneId:int droneX:int droneY:int emergency:int battery:int
22 |
23 | read droneScanCount:int
24 | loop droneScanCount read droneId:int creatureId:int
25 |
26 | read visibleCreatureCount:int
27 | loop visibleCreatureCount read creatureId:int creatureX:int creatureY:int creatureVx:int creatureVy:int
28 |
29 | read radarBlipCount:int
30 | loop radarBlipCount read droneId:int creatureId:int radar:word(2)
31 |
32 | loop myDroneCount write WAIT 1
33 |
34 | OUTPUT
35 | MOVE | WAIT
--------------------------------------------------------------------------------
/full_rules_en.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodinGame/FallChallenge2023-SeabedSecurity/cd73b1ff2e80a34114eb1c402cc94b24080a5bed/full_rules_en.pdf
--------------------------------------------------------------------------------
/full_rules_fr.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodinGame/FallChallenge2023-SeabedSecurity/cd73b1ff2e80a34114eb1c402cc94b24080a5bed/full_rules_fr.pdf
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.codingame.game
6 | fall-2023-fish
7 | 1.0-SNAPSHOT
8 |
9 |
10 | 4.4.2
11 | 1.8
12 | 1.8
13 |
14 |
15 |
16 |
17 | com.codingame.gameengine
18 | core
19 | ${gamengine.version}
20 |
21 |
22 |
23 | com.codingame.gameengine
24 | runner
25 | ${gamengine.version}
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/endscreen/EndScreenModule.java:
--------------------------------------------------------------------------------
1 | package com.codingame.endscreen;
2 |
3 | import com.codingame.gameengine.core.AbstractPlayer;
4 | import com.codingame.gameengine.core.GameManager;
5 | import com.codingame.gameengine.core.Module;
6 | import com.google.inject.Inject;
7 | import com.google.inject.Singleton;
8 |
9 | /**
10 | * The EndScreen takes care of displaying and animating an end screen with the scores of the players at the end of the game.
11 | *
12 | */
13 | @Singleton
14 | public class EndScreenModule implements Module {
15 |
16 | private GameManager gameManager;
17 | private int[] scores;
18 | private String[] displayedText;
19 | private String titleRankingsSprite = "logo.png";
20 |
21 | @Inject
22 | EndScreenModule(GameManager gameManager) {
23 | this.gameManager = gameManager;
24 | gameManager.registerModule(this);
25 | }
26 |
27 | /**
28 | * Send scores to the module
29 | *
30 | * @param scores
31 | * the scores of the different players, the index matches the player.getIndex()
32 | */
33 | public void setScores(int[] scores) {
34 | this.scores = scores;
35 | }
36 |
37 | /**
38 | * Send scores to the module
39 | *
40 | * @param scores
41 | * the scores of the different players, the index matches the player.getIndex()
42 | * @param displayedText
43 | * the text displayed instead of the score of a player, if null or empty string for a player the score will still be displayed
44 | *
45 | */
46 | public void setScores(int[] scores, String[] displayedText) {
47 | this.scores = scores;
48 | this.displayedText = displayedText;
49 | }
50 |
51 | /**
52 | * Allows you to set the sprite used as the title of the ranking board
53 | *
54 | * @param spriteName
55 | * the name of the sprite you want to use default is "logo.png"
56 | */
57 | public void setTitleRankingsSprite(String spriteName) {
58 | this.titleRankingsSprite = spriteName;
59 | }
60 |
61 | /**
62 | *
63 | * @return the name of the sprite that will be used as the title of the ranking board
64 | */
65 | public String getTitleRankingsSprite() {
66 | return titleRankingsSprite;
67 | }
68 |
69 | @Override
70 | public final void onGameInit() {
71 | }
72 |
73 | @Override
74 | public final void onAfterGameTurn() {
75 | }
76 |
77 | @Override
78 | public final void onAfterOnEnd() {
79 | Object[] data = { scores, titleRankingsSprite, displayedText };
80 | gameManager.setViewData("endScreen", data);
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/src/main/java/com/codingame/event/Animation.java:
--------------------------------------------------------------------------------
1 | package com.codingame.event;
2 |
3 | import java.util.List;
4 |
5 | import com.google.inject.Singleton;
6 |
7 | @Singleton
8 | public class Animation {
9 | public static final int HUNDREDTH = 10;
10 | public static final int TWENTIETH = 50;
11 | public static final int TENTH = 100;
12 | public static final int THIRD = 300;
13 | public static final int HALF = 500;
14 | public static final int WHOLE = 1000;
15 |
16 | private int frameTime;
17 | private int endTime;
18 |
19 | public void reset() {
20 | frameTime = 0;
21 | endTime = 0;
22 | }
23 |
24 | public int wait(int time) {
25 | return frameTime += time;
26 | }
27 |
28 | public int getFrameTime() {
29 | return frameTime;
30 | }
31 |
32 | public void startAnim(List animData, int duration) {
33 | animData.add(new AnimationData(frameTime, duration));
34 | endTime = Math.max(endTime, frameTime + duration);
35 | }
36 |
37 | public void waitForAnim(List animData, int duration) {
38 | animData.add(new AnimationData(frameTime, duration));
39 | frameTime += duration;
40 | endTime = Math.max(endTime, frameTime);
41 | }
42 |
43 | public void chainAnims(int count, List animData, int duration, int separation) {
44 | chainAnims(count, animData, duration, separation, true);
45 | }
46 |
47 | public void chainAnims(int count, List animData, int duration, int separation, boolean waitForEnd) {
48 | for (int i = 0; i < count; ++i) {
49 | animData.add(new AnimationData(frameTime, duration));
50 |
51 | if (i < count - 1) {
52 | frameTime += separation;
53 | }
54 | }
55 | endTime = Math.max(endTime, frameTime + duration);
56 | if (waitForEnd && count > 0) {
57 | frameTime += duration;
58 | }
59 | }
60 |
61 | public void setFrameTime(int startTime) {
62 | this.frameTime = startTime;
63 | }
64 |
65 | public int getEndTime() {
66 | return endTime;
67 | }
68 |
69 | public void catchUp() {
70 | frameTime = endTime;
71 | }
72 |
73 | public int computeEvents() {
74 | int minTime = 1000;
75 |
76 | catchUp();
77 |
78 | int frameTime = Math.max(
79 | getFrameTime(),
80 | minTime
81 | );
82 | return frameTime;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/event/AnimationData.java:
--------------------------------------------------------------------------------
1 | package com.codingame.event;
2 |
3 | public class AnimationData {
4 | public int start, end;
5 |
6 | public AnimationData(int start, int duration) {
7 | this.start = start;
8 | this.end = start + duration;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/event/EventData.java:
--------------------------------------------------------------------------------
1 | package com.codingame.event;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.codingame.game.Vector;
7 |
8 | public class EventData {
9 | public static final int BUILD = 0;
10 | public static final int MOVE = 1;
11 |
12 | public int type;
13 | public List animData;
14 |
15 | public EventData() {
16 | animData = new ArrayList<>();
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Closest.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.List;
4 |
5 | public class Closest {
6 |
7 | List list;
8 | double distance;
9 |
10 | public Closest(List list, double distance) {
11 | this.list = list;
12 | this.distance = distance;
13 | }
14 |
15 | public T get() {
16 | if (hasOne()) {
17 | return list.get(0);
18 | }
19 | return null;
20 |
21 | }
22 |
23 | public boolean hasOne() {
24 | return list.size() == 1;
25 | }
26 |
27 | public Vector getPos() {
28 | if (!hasOne()) {
29 | return null;
30 | }
31 |
32 | return list.get(0).getPos();
33 | }
34 |
35 | public Vector getMeanPos() {
36 | if (hasOne()) {
37 | return getPos();
38 | }
39 | double x = 0;
40 | double y = 0;
41 |
42 | for (Entity entity : list) {
43 | x += entity.getPos().getX();
44 | y += entity.getPos().getY();
45 | }
46 | return new Vector(x / list.size(), y / list.size());
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Collision.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | public class Collision {
4 | final static Collision NONE = new Collision(-1);
5 |
6 | double t;
7 | Entity a;
8 | Entity b;
9 |
10 | Collision(double t) {
11 | this(t, null, null);
12 | }
13 |
14 | Collision(double t, Entity a) {
15 | this(t, a, null);
16 | }
17 |
18 | Collision(double t, Entity a, Entity b) {
19 | this.t = t;
20 | this.a = a;
21 | this.b = b;
22 | }
23 |
24 | public boolean happened() {
25 | return t >= 0;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/CommandManager.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.List;
4 | import java.util.regex.Matcher;
5 |
6 | import com.codingame.game.action.Action;
7 | import com.codingame.game.action.ActionType;
8 | import com.codingame.game.action.MoveAction;
9 | import com.codingame.game.action.WaitAction;
10 | import com.codingame.game.exception.InvalidInputException;
11 | import com.codingame.gameengine.core.GameManager;
12 | import com.codingame.gameengine.core.MultiplayerGameManager;
13 | import com.google.inject.Inject;
14 | import com.google.inject.Singleton;
15 |
16 | @Singleton
17 | public class CommandManager {
18 |
19 | @Inject private MultiplayerGameManager gameManager;
20 |
21 | public void parseCommands(Player player, List lines) {
22 |
23 | try {
24 | Matcher match;
25 | int droneIdx = 0;
26 | for (String command : lines) {
27 | boolean found = false;
28 | try {
29 | for (ActionType actionType : ActionType.values()) {
30 | match = actionType.getPattern().matcher(command.trim());
31 | if (match.matches()) {
32 | Action action;
33 | switch (actionType) {
34 | case MOVE: {
35 | int x = Integer.parseInt(match.group("x"));
36 | int y = Integer.parseInt(match.group("y"));
37 | int light = Integer.parseInt(match.group("light"));
38 | action = new MoveAction(x, y, light);
39 |
40 | Drone drone = player.drones.get(droneIdx);
41 | drone.move = new Vector(x, y);
42 | drone.lightSwitch = light == 1;
43 | matchMessage(drone, match);
44 | break;
45 | }
46 | case WAIT: {
47 | int light = Integer.parseInt(match.group("light"));
48 | action = new WaitAction(light);
49 | Drone drone = player.drones.get(droneIdx);
50 | drone.lightSwitch = light == 1;
51 | matchMessage(drone, match);
52 | break;
53 | }
54 | default:
55 | // Impossibru
56 | action = null;
57 | break;
58 | }
59 | // player.addAction(action);
60 |
61 | found = true;
62 | break;
63 | }
64 | }
65 | } catch (Exception e) {
66 | throw new InvalidInputException(Game.getExpected(command), e.toString());
67 | }
68 |
69 | if (!found) {
70 | throw new InvalidInputException(Game.getExpected(command), command);
71 | }
72 | droneIdx++;
73 | }
74 |
75 | } catch (InvalidInputException e) {
76 | deactivatePlayer(player, e.getMessage());
77 | gameManager.addToGameSummary(e.getMessage());
78 | gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + ": disqualified!"));
79 | }
80 | }
81 |
82 | public void deactivatePlayer(Player player, String message) {
83 | player.deactivate(escapeHTMLEntities(message));
84 | player.setScore(-1);
85 | }
86 |
87 | private void matchMessage(Drone drone, Matcher match) {
88 | String message = match.group("message");
89 | if (message != null) {
90 | if (Game.ALLOW_EMOJI) {
91 | drone.setMessage(message);
92 | } else {
93 | String characterFilter = "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]";
94 | String messageWithoutEmojis = message.replaceAll(characterFilter, "");
95 | drone.setMessage(messageWithoutEmojis);
96 | }
97 | }
98 | }
99 |
100 | private String escapeHTMLEntities(String message) {
101 | return message
102 | .replace("<", "<")
103 | .replace(">", ">");
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Drone.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class Drone implements Entity {
7 |
8 | Vector pos;
9 | Vector move;
10 | Vector speed;
11 |
12 | int light;
13 | int battery;
14 | List scans;
15 | List fishesScannedThisTurn;
16 | boolean lightSwitch;
17 | boolean lightOn;
18 | boolean dying;
19 | boolean dead;
20 | boolean didReport;
21 | int id;
22 | double dieAt;
23 | String message;
24 | Player owner;
25 |
26 | /* stats */
27 | int maxTurnsSpentWithScan;
28 | int turnsSpentWithScan;
29 | int maxY;
30 |
31 | public Drone(double x, int y, int id, Player owner) {
32 | this.id = id;
33 | this.owner = owner;
34 | pos = new Vector(x, y);
35 | battery = Game.DRONE_MAX_BATTERY;
36 | light = 0;
37 | scans = new ArrayList<>();
38 | lightSwitch = false;
39 | speed = Vector.ZERO;
40 | dying = false;
41 | dead = false;
42 | didReport = false;
43 | lightOn = false;
44 | fishesScannedThisTurn = new ArrayList<>();
45 | message = "";
46 | }
47 |
48 | @Override
49 | public Vector getPos() {
50 | return pos;
51 | }
52 |
53 | @Override
54 | public Vector getSpeed() {
55 | return speed;
56 | }
57 |
58 | public boolean isEngineOn() {
59 | return move != null;
60 | }
61 |
62 | public boolean isLightOn() {
63 | return lightOn;
64 | }
65 |
66 |
67 | public void drainBattery() {
68 | battery -= Game.LIGHT_BATTERY_COST;
69 | }
70 |
71 | public void rechargeBattery() {
72 | if (battery < Game.DRONE_MAX_BATTERY) {
73 | battery += Game.DRONE_BATTERY_REGEN;
74 | if (battery >= Game.DRONE_MAX_BATTERY) {
75 | battery = Game.DRONE_MAX_BATTERY;
76 | }
77 | }
78 |
79 | }
80 |
81 | public boolean isDeadOrDying() {
82 | return dying || dead;
83 | }
84 |
85 | public double getX() {
86 | return pos.getX();
87 | }
88 |
89 | public double getY() {
90 | return pos.getY();
91 | }
92 |
93 | public String scanSlotToString(int i) {
94 | if (scans.size() > i) {
95 | Scan scan = scans.get(i);
96 | return scan.toInputString();
97 | }
98 | return "-1 -1";
99 | }
100 |
101 | public void setMessage(String message) {
102 | this.message = message;
103 | if (message != null && message.length() > 48) {
104 | this.message = message.substring(0, 46) + "...";
105 | }
106 |
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Entity.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | public interface Entity {
4 | Vector getPos();
5 |
6 | Vector getSpeed();
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Fish.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | public class Fish implements Entity {
4 | FishType type;
5 | Vector pos;
6 | int color;
7 | double startY;
8 | Vector speed;
9 | int id;
10 | int lowY, highY;
11 | boolean isFleeing;
12 | /* stats */
13 | Integer fleeingFromPlayer;
14 |
15 | public Fish(double x, double y, FishType type, int color, int id, int lowY, int highY) {
16 | this.id = id;
17 | this.pos = new Vector(x, y);
18 | this.type = type;
19 | this.color = color;
20 | this.lowY = lowY;
21 | this.highY = highY;
22 | this.speed = Vector.ZERO;
23 | }
24 |
25 | @Override
26 | public Vector getPos() {
27 | return pos;
28 | }
29 |
30 | @Override
31 | public Vector getSpeed() {
32 | return speed;
33 | }
34 |
35 | public double getX() {
36 | return pos.getX();
37 | }
38 |
39 | public double getY() {
40 | return pos.getY();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/FishType.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | public enum FishType {
4 | JELLY, FISH, CRAB;
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/GameSummaryManager.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.stream.Collectors;
8 |
9 | import com.google.inject.Singleton;
10 |
11 | @Singleton
12 | public class GameSummaryManager {
13 | private List lines;
14 | private Map> playersErrors;
15 | private Map> playersSummary;
16 |
17 | public GameSummaryManager() {
18 | this.lines = new ArrayList<>();
19 | this.playersErrors = new HashMap<>();
20 | this.playersSummary = new HashMap<>();
21 | }
22 |
23 | public String getSummary() {
24 | return toString();
25 | }
26 |
27 | public void clear() {
28 | this.lines.clear();
29 | this.playersErrors.clear();
30 | this.playersSummary.clear();
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | return formatErrors() + "\n" + formatSummary() + "\n" + lines.stream().collect(Collectors.joining("\n"));
36 | }
37 |
38 | public void addError(Player player, String error) {
39 | String key = player.getNicknameToken();
40 | if (!playersErrors.containsKey(key)) {
41 | playersErrors.put(key, new ArrayList());
42 | }
43 | playersErrors.get(key).add(error);
44 | }
45 |
46 | public void addPlayerSummary(String key, String summary) {
47 | if (!playersSummary.containsKey(key)) {
48 | playersSummary.put(key, new ArrayList());
49 | }
50 | playersSummary.get(key).add(summary);
51 | }
52 |
53 | private String formatErrors() {
54 | return playersErrors.entrySet().stream().map(errorMap -> {
55 | List errors = errorMap.getValue();
56 | String additionnalErrorsMessage = errors.size() > 1 ? " + " + (errors.size() - 1) + " other error" + (errors.size() > 2 ? "s" : "") : "";
57 | return errorMap.getKey() + ": " + errors.get(0) + additionnalErrorsMessage;
58 | }).collect(Collectors.joining("\n"));
59 | }
60 |
61 | public String formatSummary() {
62 | return playersSummary.entrySet().stream().flatMap(summaryMap -> {
63 | return summaryMap.getValue().stream();
64 | }).collect(Collectors.joining("\n"));
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Player.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.ArrayList;
4 | import java.util.LinkedHashSet;
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 | import com.codingame.gameengine.core.AbstractMultiplayerPlayer;
9 |
10 | public class Player extends AbstractMultiplayerPlayer {
11 |
12 | String message;
13 | List drones;
14 | Set scans;
15 | Set visibleFishes;
16 |
17 | List countFishSaved;
18 | int points = 0;
19 |
20 | public Player() {
21 | drones = new ArrayList<>();
22 | visibleFishes = new LinkedHashSet<>();
23 | scans = new LinkedHashSet<>();
24 | countFishSaved = new ArrayList();
25 | }
26 |
27 | @Override
28 | public int getExpectedOutputLines() {
29 | return drones.size();
30 | }
31 |
32 | public String getMessage() {
33 | return message;
34 | }
35 |
36 | public void reset() {
37 | message = null;
38 | drones.forEach(d -> {
39 | d.move = null;
40 | d.fishesScannedThisTurn.clear();
41 | d.didReport = false;
42 | d.message = "";
43 | });
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Referee.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import com.codingame.gameengine.core.AbstractPlayer.TimeoutException;
4 | import com.codingame.gameengine.core.AbstractReferee;
5 | import com.codingame.gameengine.core.MultiplayerGameManager;
6 | import com.google.inject.Inject;
7 | import com.google.inject.Singleton;
8 |
9 | @Singleton
10 | public class Referee extends AbstractReferee {
11 |
12 | @Inject private MultiplayerGameManager gameManager;
13 | @Inject private CommandManager commandManager;
14 | @Inject private Game game;
15 |
16 | @Override
17 | public void init() {
18 | try {
19 |
20 | int leagueLevel = gameManager.getLeagueLevel();
21 | if (leagueLevel == 1) {
22 | Game.ENABLE_UGLIES = false;
23 | Game.FISH_WILL_FLEE = false;
24 | Game.DRONES_PER_PLAYER = 1;
25 | Game.SIMPLE_SCANS = true;
26 | Game.FISH_WILL_MOVE = true;
27 | } else if (leagueLevel == 2) {
28 | Game.ENABLE_UGLIES = false;
29 | Game.FISH_WILL_FLEE = false;
30 | Game.DRONES_PER_PLAYER = 1;
31 | } else if (leagueLevel == 3) {
32 | Game.ENABLE_UGLIES = false;
33 | } else {
34 |
35 | }
36 |
37 | game.init();
38 | sendGlobalInfo();
39 |
40 | gameManager.setFrameDuration(500);
41 | gameManager.setMaxTurns(Game.MAX_TURNS);
42 | gameManager.setTurnMaxTime(50);
43 | gameManager.setFirstTurnMaxTime(1000);
44 | } catch (Exception e) {
45 | e.printStackTrace();
46 | System.err.println("Referee failed to initialize");
47 | abort();
48 | }
49 | }
50 |
51 | private void abort() {
52 | gameManager.endGame();
53 |
54 | }
55 |
56 | private void sendGlobalInfo() {
57 | // Give input to players
58 | for (Player player : gameManager.getActivePlayers()) {
59 | for (String line : Serializer.serializeGlobalInfoFor(player, game)) {
60 | player.sendInputLine(line);
61 | }
62 | }
63 | }
64 |
65 | @Override
66 | public void gameTurn(int turn) {
67 | game.resetGameTurnData();
68 |
69 | // Give input to players
70 | for (Player player : gameManager.getActivePlayers()) {
71 | for (String line : Serializer.serializeFrameInfoFor(player, game)) {
72 | player.sendInputLine(line);
73 | }
74 | player.execute();
75 | }
76 | // Get output from players
77 | handlePlayerCommands();
78 |
79 | game.performGameUpdate(turn);
80 |
81 | if (gameManager.getActivePlayers().size() < 2) {
82 | abort();
83 | }
84 | }
85 |
86 | private void handlePlayerCommands() {
87 |
88 | for (Player player : gameManager.getActivePlayers()) {
89 | try {
90 | commandManager.parseCommands(player, player.getOutputs());
91 | } catch (TimeoutException e) {
92 | player.deactivate("Timeout!");
93 | gameManager.addToGameSummary(player.getNicknameToken() + " has not provided " + player.getExpectedOutputLines() + " lines in time");
94 | }
95 | }
96 |
97 | }
98 |
99 | @Override
100 | public void onEnd() {
101 | game.onEnd();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Scan.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.Objects;
4 |
5 | public class Scan {
6 | int fishId;
7 | FishType type;
8 | int color;
9 |
10 | public Scan(Fish fish) {
11 | this.fishId = fish.id;
12 | this.type = fish.type;
13 | this.color = fish.color;
14 | }
15 |
16 | public Scan(FishType type, int color) {
17 | this.type = type;
18 | this.color = color;
19 | }
20 |
21 | @Override
22 | public int hashCode() {
23 | return Objects.hash(color, type);
24 | }
25 |
26 | @Override
27 | public boolean equals(Object obj) {
28 | if (this == obj) return true;
29 | if (obj == null) return false;
30 | if (getClass() != obj.getClass()) return false;
31 | Scan other = (Scan) obj;
32 | return color == other.color && type == other.type;
33 | }
34 |
35 | public String toInputString() {
36 | return Serializer.join(fishId);
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return String.format(
42 | "%s (%d) %s (%d)",
43 | Game.COLORS[color],
44 | color,
45 | type.name().toLowerCase(),
46 | type.ordinal()
47 | );
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/codingame/game/Serializer.java:
--------------------------------------------------------------------------------
1 | package com.codingame.game;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Optional;
6 | import java.util.function.Function;
7 | import java.util.stream.Collectors;
8 | import java.util.stream.Stream;
9 |
10 | public class Serializer {
11 | public static final String MAIN_SEPARATOR = ";";
12 |
13 | static public String serialize(List list) {
14 | return list.stream().map(String::valueOf).collect(Collectors.joining(" "));
15 | }
16 |
17 | static public String serialize(Vector coord) {
18 | return coord.getX() + " " + coord.getY();
19 | }
20 |
21 | static public String join(Object... args) {
22 | return Stream.of(args)
23 | .map(String::valueOf)
24 | .collect(Collectors.joining(" "));
25 | }
26 |
27 | public static String serializeGlobalData(Game game) {
28 | List