Make game parameters overridable through game settings
[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         buf = ps.getProperty("initialStones");
116         if (buf != null) {
117             try {
118                 int i = Integer.parseInt(buf);
119                 if (i > 50) {
120                     gameManager.addToGameSummary(GameManager.formatErrorMessage("Ignoring invalid initial stone count: " + buf));
121                 }
122                 else {
123                     initialStones = i;
124                     gameManager.addToGameSummary("Initial stone count overridden to " + buf);
125                 }
126             }
127             catch (NumberFormatException e) {
128                 gameManager.addToGameSummary(GameManager.formatErrorMessage("Ill-formed initial stone count: " + buf));
129             }
130         }
131
132         trollPosition = roadLength / 2;
133
134         p0 = new Player(0);
135         p0.gp = gameManager.getPlayer(0);
136         p0.setCastlePosition(0);
137         p0.setMultiplier(1);
138         p0.adjustScore(trollPosition);
139         p0.setStones(initialStones);
140
141         p1 = new Player(1);
142         p1.gp = gameManager.getPlayer(1);
143         p1.setCastlePosition(roadLength);
144         p1.setMultiplier(-1);
145         p1.adjustScore(trollPosition);
146         p1.setStones(initialStones);
147     }
148
149     private int winner;
150     boolean haveWinner() {
151         if (trollPosition == 0) {
152             winner = 1;
153             return true;
154         }
155         else if (trollPosition == roadLength) {
156             winner = 0;
157             return true;
158         }
159         else {
160             return false;
161         }
162     }
163     int getWinner() { return winner; }
164     int getLoser() { return 1 - winner; }
165
166     boolean exhausted() {
167         return p0.getStones() <= 0 && p1.getStones() <= 0;
168     }
169 }