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