FIX: IT belongs in a MODEL!
[troll.git] / src / main / java / com / codingame / game / Model.java
1 package com.codingame.game;
2
3 import java.util.Random;
4 import java.util.Properties;
5
6 import com.codingame.gameengine.core.GameManager;
7 import com.codingame.gameengine.core.MultiplayerGameManager;
8 import com.google.inject.Inject;
9
10 class Model {
11     @Inject private MultiplayerGameManager<com.codingame.game.Player> gameManager;
12     @Inject private LeagueManager league;
13     long seed;
14     Random random;
15     int roadLength;
16     int initialStones;
17     int trollPosition;
18     Player p0, p1;
19
20     class Player {
21         com.codingame.game.Player gp;
22         int index;
23         boolean hit;
24
25         Player(int i) {
26             index = i;
27             hit = false;
28         }
29
30         void loseRound() {
31             hit = true;
32             winner = 1 - index;
33         }
34
35         private int castlePosition;
36         public int getCastlePosition() { return castlePosition; }
37         public void setCastlePosition(int pos) { castlePosition = pos; }
38
39         private int multiplier;
40         public int getMultiplier() { return multiplier; }
41         public void setMultiplier(int m) { multiplier = m; }
42
43         class FailedToThrowStonesAndShouldHave extends Exception {}
44         class ThrewMoreStonesThanHad extends Exception {}
45
46         private int stones;
47         public int getStones() { return stones; }
48         public void consumeStones(int n)
49             throws ThrewMoreStonesThanHad,
50                    FailedToThrowStonesAndShouldHave
51         {
52             if (n > stones) {
53                 throw new ThrewMoreStonesThanHad();
54             }
55             if (n == 0 && stones > 0) {
56                 throw new FailedToThrowStonesAndShouldHave();
57             }
58             setStones(stones - n);
59         }
60         public int consumeMaxStones() {
61             int r = stones;
62             stones = 0;
63             return r;
64         }
65         public int consumeMinStones() {
66             if (stones < 1) {
67                 throw new Error("Internal error: tried to consume min stones on an empty heap.");
68             }
69             stones--;
70             return 1;
71         }
72         public void setStones(int n) {
73             stones = n;
74         }
75         public int getOppStones() {
76             return p0.stones + p1.stones - stones;
77         }
78
79         public void adjustScore(int trollPosition) {
80             if (gp.isActive()) {
81                 gp.setScore(Math.abs(castlePosition - trollPosition));
82             }
83         }
84
85         public int getTrollDistance() {
86             return Math.abs(castlePosition - trollPosition);
87         }
88     }
89
90     void init() {
91         seed = gameManager.getSeed();
92         random = new Random(seed);
93
94         switch(league.mapLevel) {
95         case SINGLE:
96             roadLength = 6;
97             initialStones = 15;
98             break;
99         case DISCRETE:
100             int i = random.nextInt(4);
101             switch (i) {
102             case 0:
103                 roadLength = 6;
104                 initialStones = 15;
105                 break;
106             case 1:
107                 roadLength = 6;
108                 initialStones = 30;
109                 break;
110             case 2:
111                 roadLength = 14;
112                 initialStones = 30;
113                 break;
114             case 3:
115                 roadLength = 14;
116                 initialStones = 50;
117                 break;
118             }
119             break;
120         case CONTINUOUS:
121             roadLength = 2 * (3 + random.nextInt(7-3+1));
122             initialStones = 15 + random.nextInt(50-15+1);
123             break;
124         }
125
126         Properties ps = gameManager.getGameParameters();
127         String buf = ps.getProperty("roadLength");
128         if (buf != null) {
129             try {
130                 int i = Integer.parseInt(buf);
131                 if (i < 0 || i > 20 || (i & 1) != 0) {
132                     gameManager.addToGameSummary(GameManager.formatErrorMessage("Ignoring invalid road length: " + buf));
133                 }
134                 else {
135                     roadLength = i;
136                     gameManager.addToGameSummary("Road length overridden to " + i);
137                 }
138             }
139             catch(NumberFormatException e) {
140                 gameManager.addToGameSummary(GameManager.formatErrorMessage("Ill-formed road length: " + buf));
141             }
142         }
143         ps.setProperty("roadLength", new Integer(roadLength).toString());
144
145         buf = ps.getProperty("initialStones");
146         if (buf != null) {
147             try {
148                 int i = Integer.parseInt(buf);
149                 if (i > 50) {
150                     gameManager.addToGameSummary(GameManager.formatErrorMessage("Ignoring invalid initial stone count: " + buf));
151                 }
152                 else {
153                     initialStones = i;
154                     gameManager.addToGameSummary("Initial stone count overridden to " + buf);
155                 }
156             }
157             catch (NumberFormatException e) {
158                 gameManager.addToGameSummary(GameManager.formatErrorMessage("Ill-formed initial stone count: " + buf));
159             }
160         }
161         ps.setProperty("initialStones", new Integer(initialStones).toString());
162
163         trollPosition = roadLength / 2;
164
165         p0 = new Player(0);
166         p0.gp = gameManager.getPlayer(0);
167         p0.setCastlePosition(0);
168         p0.setMultiplier(1);
169         p0.adjustScore(trollPosition);
170         p0.setStones(initialStones);
171
172         p1 = new Player(1);
173         p1.gp = gameManager.getPlayer(1);
174         p1.setCastlePosition(roadLength);
175         p1.setMultiplier(-1);
176         p1.adjustScore(trollPosition);
177         p1.setStones(initialStones);
178     }
179
180     void moveTroll(int delta) {
181         trollPosition += delta;
182         if (trollPosition <= 0) {
183             trollPosition = 0;
184             winner = 1;
185         }
186         if (trollPosition >= roadLength) {
187             trollPosition = roadLength;
188             winner = 0;
189         }
190
191         p0.adjustScore(trollPosition);
192         p1.adjustScore(trollPosition);
193     }
194
195     boolean FIX_IT() {
196         switch (league.fixLevel) {
197             case SOMETIMES: return random.nextInt(10) > 0;
198             case NEVER: return false;
199             default: throw new JavaLimitationError();
200         }
201     }
202
203     private Integer winner;
204     boolean haveWinner() {
205         return winner != null;
206     }
207
208     int getWinner() { return winner; }
209     int getLoser() { return 1 - winner; }
210
211     boolean exhausted() {
212         return p0.getStones() <= 0 || p1.getStones() <= 0;
213     }
214 }