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