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