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