Clarify one-stone rule and timings
[troll.git] / src / main / java / com / codingame / game / Referee.java
1 package com.codingame.game;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Random;
7
8 import com.codingame.gameengine.core.AbstractPlayer.TimeoutException;
9 import com.codingame.gameengine.core.AbstractReferee;
10 import com.codingame.gameengine.core.GameManager;
11 import com.codingame.gameengine.core.MultiplayerGameManager;
12 import com.codingame.gameengine.module.entities.GraphicEntityModule;
13 import com.codingame.gameengine.module.entities.Rectangle;
14 import com.codingame.gameengine.module.entities.Sprite;
15 import com.codingame.gameengine.module.entities.Text;
16 import com.codingame.gameengine.module.entities.Curve;
17 import com.google.inject.Inject;
18 import com.google.inject.Provider;
19
20 public class Referee extends AbstractReferee {
21     @Inject private MultiplayerGameManager<Player> gameManager;
22     @Inject private GraphicEntityModule graphicEntityModule;
23
24     Random random;
25
26     int roadLength;
27     int initialStones;
28     int trollPosition;
29     Player p0, p1;
30     Sprite troll;
31     Text trollPositionGauge;
32     
33     @Override
34     public void init() {
35         random = new Random(gameManager.getSeed());
36         switch (random.nextInt(4)) {
37         case 0:
38             roadLength = 6;
39             initialStones = 15;
40             break;
41         case 1:
42             roadLength = 6;
43             initialStones = 30;
44             break;
45         case 2:
46             roadLength = 14;
47             initialStones = 30;
48             break;
49         case 3:
50             roadLength = 14;
51             initialStones = 50;
52             break;
53         }
54
55         trollPosition = roadLength / 2;
56
57         p0 = gameManager.getPlayer(0);
58         p0.setCastlePosition(0);
59         p0.setMultiplier(1);
60         p0.adjustScore(trollPosition);
61         p0.sendInputLine(String.format("%d %d", roadLength, initialStones));
62
63         p1 = gameManager.getPlayer(1);
64         p1.setCastlePosition(roadLength-1);
65         p1.setMultiplier(-1);
66         p1.adjustScore(trollPosition);
67         p1.sendInputLine(String.format("%d %d", roadLength, initialStones));
68
69         drawBackground();
70         drawPlayer();
71         drawTroll();
72
73         // result in text display, so do last:
74         p0.setStones(initialStones);
75         p1.setStones(initialStones);
76
77         gameManager.setFrameDuration(2000);
78     }
79
80     private void drawBackground() {
81         graphicEntityModule.createSprite()
82                 .setImage("background.png")
83                 .setAnchor(0);
84     }
85
86     private void drawPlayer() {
87         for (Player player : gameManager.getPlayers()) {
88             boolean p0 = player.getIndex() == 0;
89             int x = p0 ? 280 : 1920 - 280;
90             int y = 220;
91
92             Rectangle border1 = graphicEntityModule
93                     .createRectangle()
94                     .setWidth(140)
95                     .setHeight(140)
96                     .setX(x - 70)
97                     .setY(y - 70)
98                     .setLineWidth(0)
99                     .setFillColor(player.getColorToken());
100
101             Rectangle border2 = graphicEntityModule
102                     .createRectangle()
103                     .setWidth(120)
104                     .setHeight(120)
105                     .setX(x - 60)
106                     .setY(y - 60)
107                     .setLineWidth(0)
108                     .setFillColor(0xffffff);
109
110             Sprite avatarSprite = graphicEntityModule.createSprite()
111                     .setX(x)
112                     .setY(y)
113                     .setZIndex(20)
114                     .setImage(player.getAvatarToken())
115                     .setAnchor(0.5)
116                     .setBaseHeight(116)
117                     .setBaseWidth(116);
118
119             player.avatar = graphicEntityModule.createGroup(border1, border2, avatarSprite);
120
121             Text text = graphicEntityModule.createText(player.getNicknameToken())
122                     .setX(x)
123                     .setY(y + 120)
124                     .setZIndex(20)
125                     .setFontSize(40)
126                     .setFillColor(0x7f3f00)
127                     .setAnchor(0.5);
128
129             player.stoneCounter = graphicEntityModule.createText("S")
130                 .setX(x)
131                 .setY(y+200)
132                 .setZIndex(20)
133                 .setFontSize(40)
134                 .setFillColor(0x7f3f00)
135                 .setAnchor(0.5);
136
137             player.message = graphicEntityModule.createText()
138                 .setX(p0 ? 15 : 1920-15)
139                 .setY(680)
140                 .setZIndex(1)
141                 .setFontSize(40)
142                 .setStrokeColor(0x000000)
143                 .setFillColor(0xffbf7f)
144                 .setAnchorX(p0 ? 0 : 1)
145                 .setAnchorY(1);
146
147             player.castle = graphicEntityModule.createSprite()
148                 .setImage("castle.png")
149                 .setTint(player.getColorToken())
150                 .setX(p0 ? 160 : 1920-160)
151                 .setY(p0 ? 890 : 880)
152                 .setZIndex(1)
153                 .setAnchorX(0.5)
154                 .setAnchorY(1)
155                 .setScaleX(p0 ? 1 : -1);
156
157             player.stone = graphicEntityModule.createText()
158                 .setZIndex(3)
159                 .setFontSize(150)
160                 .setFillColor(0x12322a)
161                 .setAnchor(0.5)
162                 .setAlpha(0);
163         }
164     }
165
166     private void drawTroll() {
167         troll = graphicEntityModule.createSprite()
168             .setImage("troll.png")
169             .setAnchorX(0.5)
170             .setAnchorY(1)
171             .setX(1920/2)
172             .setY(880)
173             .setZIndex(2);
174         trollPositionGauge = graphicEntityModule.createText()
175             .setZIndex(2)
176             .setAnchor(0.5)
177             .setFontSize(40)
178             .setX(1980/2)
179             .setY(980)
180             .setFillColor(0xffffff);
181     }
182
183     private void moveTroll() {
184         graphicEntityModule.commitEntityState(0.5, troll, trollPositionGauge);
185         int x0 = p0.castle.getX(), x1 = p1.castle.getX();
186         int y0 = p0.castle.getY(), y1 = p1.castle.getY();
187         troll.setX(x0 + trollPosition * (x1-x0) / roadLength,
188                    Curve.ELASTIC);
189         troll.setY(y0 + trollPosition * (y1-y0) / roadLength,
190                    Curve.ELASTIC);
191
192         trollPositionGauge.setX((trollPositionGauge.getX() + troll.getX()) / 2);
193         int delta = trollPosition - roadLength / 2;
194         if (delta < 0) {
195             trollPositionGauge.setText("← " + Math.abs(delta));
196         }
197         else if (delta > 0) {
198             trollPositionGauge.setText(Math.abs(delta) + " →");
199         }
200         else {
201             trollPositionGauge.setText("↔");
202         }
203         graphicEntityModule.commitEntityState(0.75, trollPositionGauge);
204         trollPositionGauge.setX(troll.getX());
205     }
206
207     @Override
208     public void gameTurn(int turn) {
209
210         p0.sendInputLine(String.format("%d %d %d", p0.getScore(), p0.getStones(), p1.getStones()));
211         p1.sendInputLine(String.format("%d %d %d", p1.getScore(), p1.getStones(), p0.getStones()));
212
213         for (Player player : gameManager.getActivePlayers()) {
214             player.execute();
215         }
216
217         int delta = 0;
218         for (Player player : gameManager.getActivePlayers()) {
219             try {
220                 int stones = player.getAction();
221                 if (stones == 0 && player.getStones() > 0) {
222                     if (random.nextInt(10) > 0) {
223                         gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " tried not throwing stones.  Fixing that for them because I'm in a good mood today."));
224                         stones = 1;
225                     }
226                     else {
227                         throw new InvalidAction("tried not throwing any stone.  They were then eaten by a grue.");
228                     }
229                 }
230                 player.consumeStones(stones);
231                 gameManager.addToGameSummary(String.format("%s throws %d stone%s at the troll.", player.getNicknameToken(), stones, stones == 1 ? "" : "s"));
232                 delta += player.getMultiplier() * stones;
233
234                 if (stones < 0) {
235                     player.deactivate(player.getNicknameToken() + " CHEAT");
236                     gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " cheated.  Banning account."));
237                     player.setScore(-1);
238                     endGame();
239                 }
240                 else if (stones > 0) {
241                     player.stone.setX(player.castle.getX());
242                     player.stone.setY(player.castle.getY() - 100);
243                     player.stone.setText(new Integer(stones).toString());
244                     player.stone.setAlpha(1);
245                     graphicEntityModule.commitEntityState(0, player.stone);
246     
247                     int peakX = (player.castle.getX() + troll.getX()) / 2;
248                     int peakY = 540;
249                     player.stone.setX(peakX);
250                     player.stone.setY(peakY, Curve.EASE_OUT);
251                     graphicEntityModule.commitEntityState(0.25, player.stone,
252                                                           player.stoneCounter);
253     
254                     player.stone.setX(troll.getX());
255                     player.stone.setY(troll.getY() - 50, Curve.EASE_IN);
256                     player.stone.setAlpha(0, Curve.EASE_IN);
257                     graphicEntityModule.commitEntityState(0.5, player.stone);
258                 }
259             }
260             catch (InvalidAction e) {
261                 player.deactivate(player.getNicknameToken() + " INVALID");
262                 gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " " + e.getMessage()));
263                 player.setScore(-1);
264                 endGame();
265             }
266             catch (NumberFormatException e) {
267                 player.deactivate(player.getNicknameToken() + " ERROR");
268                 gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " provided malformed input!"));
269                 player.setScore(-1);
270                 endGame();
271             }
272             catch (TimeoutException e) {
273                 gameManager.addToGameSummary(player.getNicknameToken() + " timed out!");
274                 player.deactivate(player.getNicknameToken() + " T/O");
275                 player.setScore(-1);
276                 endGame();
277             }
278
279             player.message
280                 .setText(player.getMessageString());
281             //  .setAnchorX(/*player == p0 ? 0 : */ 1);
282             graphicEntityModule.commitEntityState(0, player.message);
283         }
284
285         if (delta > 0) {
286             gameManager.addToGameSummary("Troll walks right.");
287             trollPosition++;
288             moveTroll();
289         }
290         else if (delta < 0) {
291             gameManager.addToGameSummary("Troll walks left.");
292             trollPosition--;
293             moveTroll();
294         }
295         else {
296             gameManager.addToGameSummary("Troll stands still.");
297         }
298
299         for (Player player : gameManager.getActivePlayers()) {
300             player.adjustScore(trollPosition);
301             if (trollPosition == player.getCastlePosition()) {
302                 gameManager.addToGameSummary(GameManager.formatErrorMessage("Troll destroys " + player.getNicknameToken()));
303                 endGame();
304             }
305         }
306
307         if (p0.getStones() <= 0 && p1.getStones() <= 0) {
308             endGame();
309         }
310     }
311
312     private void destroyPlayer(Player player) {
313         player.avatar.setRotation(170*Math.PI/180, Curve.ELASTIC);
314
315         graphicEntityModule.commitEntityState(0.5, player.castle);
316         player.castle.setX(player.castle.getX(), Curve.ELASTIC);
317         player.castle.setScaleY(-0.2, Curve.EASE_IN);
318     }
319
320     private void endGame() {
321         if (! gameManager.isGameEnd()) {
322             gameManager.endGame();
323
324             if (p0.getScore() > p1.getScore()) {
325                 gameManager.addToGameSummary(GameManager.formatSuccessMessage(p0.getNicknameToken() + " wins"));
326                 destroyPlayer(p1);
327             }
328             else if (p0.getScore() < p1.getScore()) {
329                 gameManager.addToGameSummary(GameManager.formatSuccessMessage(p1.getNicknameToken() + " wins"));
330                 destroyPlayer(p0);
331             }
332             else if (p0.getScore() < 0) {
333                 gameManager.addToGameSummary(GameManager.formatErrorMessage("Everybody loses!"));
334                 destroyPlayer(p0);
335                 destroyPlayer(p1);
336             }
337             else {
338                 gameManager.addToGameSummary("Draw.");
339             }
340         }
341     }
342 }