b907739ea141e6592399632e507adf028532f68f
[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     @Inject private View view;
25     @Inject private Model model;
26
27     @Override
28     public void init() {
29         model.init(gameManager.getSeed());
30         gameManager.getPlayer(0).model = model.p0;
31         gameManager.getPlayer(1).model = model.p1;
32
33         for (Player p: gameManager.getPlayers()) {
34             p.gameInit(model.roadLength, model.initialStones);
35         }
36
37         view.init(model);
38         gameManager.getPlayer(0).view = view.p0;
39         gameManager.getPlayer(1).view = view.p1;
40         gameManager.setFrameDuration(2000);
41     }
42
43     private void disqualify(Player player, String popup, String message) {
44         player.deactivate(player.getNicknameToken() + " " + popup);
45         gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " " + message));
46         player.setScore(-1);
47     }
48
49     @Override
50     public void gameTurn(int turn) {
51         // System.err.println("Starting turn " + turn);
52
53         view.startTurn();
54
55         for (Player player : gameManager.getActivePlayers()) {
56             player.sendGameTurn();
57         }
58         // SDK @#%^&! arbitrary sequence point: last input < first output
59
60         /* Parse player actions and decide basic disqualifications.
61          * Display their optional message right now: if their action
62          * is ill-formed it could help them debug.  Or shame them, at
63          * least.
64          */
65         boolean disqual = false;
66         for (Player player : gameManager.getActivePlayers()) {
67             player.receiveGameTurn();
68             switch (player.type) {
69             case Timeout:
70                 disqualify(player, "T/O", "timed out!");
71                 disqual = true;
72                 break;
73             case Invalid:
74                 disqualify(player, "INVALID", "provided an ill-formed action");
75                 disqual = true;
76                 break;
77             case Throw:
78                 try { player.model.consumeStones(player.stoneThrow); }
79                 catch (Model.Player.ThrewMoreStonesThanHad e) {
80                     if (model.random.nextInt(10) > 0) {
81                         gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " tried to throw more stones than they had.  I'll let it slide for this time.  (But not let them throw that much!)"));
82                         player.stoneThrow = player.model.consumeMaxStones();
83                     }
84                     else {
85                         disqualify(player, "ILLEGAL", "tried to throw more stones than they had.  They went into debt trying to provide.  The economy tanked, recession and famine ensued; even the troll wouldn't have wanted to bash them anymore.  But that's no victory.");
86                         disqual = true;
87                     }
88                 }
89                 catch (Model.Player.FailedToThrowStonesAndShouldHave e) {
90                     if (model.random.nextInt(10) > 0) {
91                         gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " tried not throwing any stones.  Fixing that for them because I'm in a good mood today."));
92                         player.stoneThrow = player.model.consumeMinStones();
93                     }
94                     else {
95                         disqualify(player, "ILLEGAL", "tried not throwing any stones.  They were then eaten by a grue.");
96                         disqual = true;
97                     }
98                 }
99                 break;
100             }
101             player.view.displayMessage(player.messageString);
102         }
103
104         /* Update game model and view.
105          *
106          * As a special case, the "cheater" (sending out negative
107          * stones) handling is deferred here because we need to update
108          * its view for it to be funny.  In the end, they're still
109          * disqualified.
110          *
111          * Gather other game end scenarios (actual victory or stone
112          * exhaustion).
113          */
114         int delta = 0;
115         boolean victory = false;
116         boolean exhausted = false;
117         if (! disqual) {
118             for (Player player : gameManager.getActivePlayers()) {
119                 gameManager.addToGameSummary(String.format("%s throws %d stone%s at the troll.", player.getNicknameToken(), player.stoneThrow, player.stoneThrow == 1 ? "" : "s"));
120                 delta += player.model.getMultiplier() * player.stoneThrow;
121
122                 if (player.stoneThrow < 0) {
123                     disqualify(player, "CHEAT", "cheated.  Banning account.");
124                     disqual = true;
125                 }
126                 else if (player.stoneThrow > 0) {
127                     player.view.animateStones(player.stoneThrow);
128                     player.view.updateStoneCounter();
129                 }
130             }
131
132             /* If a player cheated, delta is unusable as is.
133              * (Consider the case the player on the right sent
134              * INT_MIN.  INT_MIN * (-1) = INT_MIN, so that player
135              * would both glean the stones *and* push the troll away.
136              * It would be unfair to have a cheating player "win"
137              * (earn the opponent castle destruction animation) this
138              * way.
139              */
140             boolean cheat0 = gameManager.getPlayer(0).stoneThrow < 0;
141             boolean cheat1 = gameManager.getPlayer(1).stoneThrow < 0;
142             if (cheat0 && cheat1); // here we can actually keep delta's value
143             else if (cheat0) delta = -1;
144             else if (cheat1) delta =  1;
145
146             if (delta > 0) {
147                 gameManager.addToGameSummary("Troll walks right.");
148                 model.trollPosition++;
149             }
150             else if (delta < 0) {
151                 gameManager.addToGameSummary("Troll walks left.");
152                 model.trollPosition--;
153             }
154             else {
155                 gameManager.addToGameSummary("Troll stands still.");
156                 // XXX animate
157             }
158             view.moveTroll();
159
160             for (Player player : gameManager.getActivePlayers()) {
161                 player.model.adjustScore(model.trollPosition);
162             }
163
164             if (model.haveWinner()) {
165                 int loser = model.getLoser();
166                 gameManager.addToGameSummary(GameManager.formatErrorMessage("Troll destroys " + gameManager.getPlayer(loser).getNicknameToken()) + ".");
167                 gameManager.getPlayer(loser).view.destroy();
168                 victory = true;
169             }
170             else if (model.exhausted()) exhausted = true;
171         }
172
173         if (disqual || victory || exhausted) endGame();
174     }
175
176     private void endGame() {
177         gameManager.endGame();
178
179         Player p0 = gameManager.getPlayer(0);
180         Player p1 = gameManager.getPlayer(1);
181
182         int s0 = p0.getScore();
183         int s1 = p1.getScore();
184
185         if (s0 > s1) {
186             gameManager.addToGameSummary(GameManager.formatSuccessMessage(p0.getNicknameToken() + " wins."));
187             p1.view.markLoser();
188         }
189         else if (s0 < s1) {
190             gameManager.addToGameSummary(GameManager.formatSuccessMessage(p1.getNicknameToken() + " wins."));
191             p0.view.markLoser();
192         }
193         else if (s0 < 0) {
194             gameManager.addToGameSummary(GameManager.formatErrorMessage("Everybody loses!"));
195             p0.view.markLoser();
196             p1.view.markLoser();
197         }
198         else {
199             gameManager.addToGameSummary("Draw.");
200         }
201     }
202 }