6e291bed99b51812faaf700e06f692a806663403
[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                         player.view.threwMoreStonesThanHad();
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                         player.view.failedToThrowStonesAndShouldHave();
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                 player.view.throwStones(player.stoneThrow);
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                 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                 model.trollPosition++;
148                 view.moveTroll(View.Dir.RIGHT);
149             }
150             else if (delta < 0) {
151                 model.trollPosition--;
152                 view.moveTroll(View.Dir.LEFT);
153             }
154             else {
155                 view.moveTroll(View.Dir.STILL);
156                 // XXX animate
157             }
158
159             for (Player player : gameManager.getActivePlayers()) {
160                 player.model.adjustScore(model.trollPosition);
161             }
162
163             if (model.haveWinner()) {
164                 int loser = model.getLoser();
165                 gameManager.getPlayer(loser).view.destroy();
166                 victory = true;
167             }
168             else if (model.exhausted()) exhausted = true;
169         }
170
171         if (disqual || victory || exhausted) endGame();
172     }
173
174     private void endGame() {
175         gameManager.endGame();
176
177         Player p0 = gameManager.getPlayer(0);
178         Player p1 = gameManager.getPlayer(1);
179
180         int s0 = p0.getScore();
181         int s1 = p1.getScore();
182
183         if (s0 > s1) {
184             p0.view.victory();
185             p1.view.markLoser();
186         }
187         else if (s0 < s1) {
188             p1.view.victory();
189             p0.view.markLoser();
190         }
191         else if (s0 < 0) {
192             view.doubleDefeat();
193             p0.view.markLoser();
194             p1.view.markLoser();
195         }
196         else {
197             view.draw();
198         }
199     }
200 }