19ef894e6fe9891ee8d9bb63c5383e70e0b98a8c
[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.game.GodModeManager;
11 import com.google.inject.Inject;
12 import com.google.inject.Provider;
13
14 public class Referee extends AbstractReferee {
15     @Inject private GameManager gameManager;
16     @Inject private GodModeManager gm;
17     @Inject private LeagueManager league;
18
19     @Inject private View view;
20     @Inject private Model model;
21
22     boolean disqual = false;
23
24     @Override
25     public void init() {
26         gm.init();
27         model.init();
28         gameManager.getPlayer(0).model = model.p0;
29         gameManager.getPlayer(1).model = model.p1;
30
31         for (Player p: gameManager.getPlayers()) {
32             p.gameInit(model.roadLength, model.initialStones,
33                        model.seed, gm.getSalt());
34         }
35
36         view.init(model);
37         gameManager.getPlayer(0).view = view.p0;
38         gameManager.getPlayer(1).view = view.p1;
39     }
40
41     private void disqualify(Player player, String popup, String message) {
42         player.deactivate(player.getNicknameToken() + " " + popup);
43         player.view.disqualify(message);
44         player.setScore(-1);
45     }
46
47     @Override
48     public void gameTurn(int turn) {
49         // System.err.println("Starting turn " + turn);
50
51         view.startTurn();
52
53         // Did I mention I hate Java? It didn't *have* to be this ugly!
54         if (disqual) { endGame(); return; }
55         if (model.exhausted()) { finishStones(); return ;}
56         if (model.haveWinner()) { endGame(); return; }
57
58         for (Player player : gameManager.getActivePlayers()) {
59             player.sendGameTurn();
60         }
61         // SDK @#%^&! arbitrary sequence point: last input < first output
62
63         /* Parse player actions and decide basic disqualifications.
64          * Display their optional message right now: if their action
65          * is ill-formed it could help them debug.  Or shame them, at
66          * least.
67          */
68         for (Player player : gameManager.getActivePlayers()) {
69             player.receiveGameTurn(); gm.transcend(player);
70             switch (player.type) {
71             case Timeout:
72                 disqualify(player, "T/O", "timed out!");
73                 player.view.markTimeout();
74                 disqual = true;
75                 break;
76             case Invalid:
77                 disqualify(player, "INVALID", "provided an ill-formed action");
78                 player.view.markIllegal();
79                 disqual = true;
80                 break;
81             case Throw:
82                 try { player.model.consumeStones(player.stoneThrow); }
83                 catch (Model.Player.ThrewMoreStonesThanHad e) {
84                     if (model.random.nextInt(10) > 0) {
85                         player.view.threwMoreStonesThanHad();
86                         player.stoneThrow = player.model.consumeMaxStones();
87                     }
88                     else {
89                         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.");
90                         player.view.markIllegal();
91                         disqual = true;
92                     }
93                 }
94                 catch (Model.Player.FailedToThrowStonesAndShouldHave e) {
95                     if (model.random.nextInt(10) > 0) {
96                         player.view.failedToThrowStonesAndShouldHave();
97                         player.stoneThrow = player.model.consumeMinStones();
98                     }
99                     else {
100                         disqualify(player, "ILLEGAL", "tried not throwing any stones.  They were then eaten by a grue.");
101                         disqual = true;
102                     }
103                 }
104                 break;
105             }
106             player.view.displayMessage(player.messageString);
107         }
108
109         /* Update game model and view, stones' part.
110          *
111          * As a special case, the "cheater" (sending out negative
112          * stones) handling is deferred here because we need to update
113          * its view for it to be funny.  In the end, they're still
114          * disqualified.
115          *
116          * Gather other game end scenarios (actual victory or stone
117          * exhaustion).
118          */
119         int delta = 0;
120         gm.update(gameManager.getPlayers());
121         for (Player player : gameManager.getActivePlayers()) {
122             player.view.throwStones(player.stoneThrow);
123             delta += player.model.getMultiplier() * player.stoneThrow;
124
125             if (player.stoneThrow < 0) {
126                 disqualify(player, "CHEAT", "cheated.  Banning account.");
127                 player.view.markCheat();
128                 disqual = true;
129             }
130             if (player.stoneThrow != 0) {
131                 player.view.animateStones(player.stoneThrow);
132                 player.view.updateStoneCounter();
133             }
134         }
135
136         /* Update game model and view, troll part.
137          *
138          * If a player cheated, delta is unusable as is.
139          * (Consider the case the player on the right sent
140          * INT_MIN.  INT_MIN * (-1) = INT_MIN, so that player
141          * would both glean the stones *and* push the troll away.
142          * It would be unfair to have a cheating player "win"
143          * (earn the opponent castle destruction animation) this
144          * way.
145          */
146         boolean cheat0 = gameManager.getPlayer(0).isActive()
147             && gameManager.getPlayer(0).stoneThrow < 0;
148         boolean cheat1 = gameManager.getPlayer(1).isActive()
149             && gameManager.getPlayer(1).stoneThrow < 0;
150         if (cheat0 && cheat1); // here we can actually keep delta's value
151         else if (cheat0) delta = -1;
152         else if (cheat1) delta =  1;
153
154         if (delta > 0) {
155             model.moveTroll(+1);
156             view.moveTroll(View.Dir.RIGHT);
157         }
158         else if (delta < 0) {
159             model.moveTroll(-1);
160             view.moveTroll(View.Dir.LEFT);
161         }
162         else {
163             view.moveTroll(View.Dir.STILL);
164             // XXX animate
165         }
166     }
167
168     // XXX very similar to main turn pendant
169     private void finishStones() {
170         boolean noStones = true;
171         int delta = 0;
172         for (Player player : gameManager.getActivePlayers()) {
173             if (model.haveWinner() && player.getIndex() == model.getLoser())
174                 continue;
175             player.stoneThrow = player.model.getStones();
176             player.model.setStones(0);
177             delta += player.stoneThrow * player.model.getMultiplier();
178             player.view.throwStones(player.stoneThrow);
179             if (player.stoneThrow != 0) {
180                 noStones = false;
181                 player.view.animateStones(player.stoneThrow);
182                 player.view.updateStoneCounter();
183             }
184         }
185         if (noStones) { endGame(); return; }
186         model.moveTroll(delta);
187         view.moveTroll();
188     }
189
190     private void endGame() {
191         gameManager.endGame();
192
193         if (model.haveWinner()) {
194             int loser = model.getLoser();
195             gameManager.getPlayer(loser).view.defeat();
196         }
197
198         Player p0 = gameManager.getPlayer(0);
199         Player p1 = gameManager.getPlayer(1);
200
201         int s0 = p0.getScore();
202         int s1 = p1.getScore();
203
204         if (s0 > s1) {
205             p0.view.victory();
206             p1.view.markLoser();
207         }
208         else if (s0 < s1) {
209             p1.view.victory();
210             p0.view.markLoser();
211         }
212         else if (s0 < 0) {
213             view.doubleDefeat();
214             p0.view.markLoser();
215             p1.view.markLoser();
216         }
217         else {
218             view.draw();
219         }
220     }
221 }