001 package jagafa.ai;
002
003 import jagafa.JassRound;
004 import jagafa.flags.AIFlags;
005 import jagafa.naming.ESwissColorNames;
006 import jagafa.object.Board;
007 import jagafa.object.Card;
008 import jagafa.object.GoneCardHeap;
009 import jagafa.object.Hand;
010 import jagafa.object.Player;
011 import jagafa.stats.PlayerStats;
012 import jagafa.stats.RoundStats;
013
014 import java.util.HashMap;
015 import java.util.LinkedList;
016 import java.util.List;
017 import java.util.Map;
018 import java.util.TreeMap;
019
020 /**
021 * ProbabylityTable provides functions to calculate probabilities
022 * for all players having cards of a color or having a specific card (all
023 * from the view of a Player)
024 * ProbabilityTable is the core of the ProbabilityAI AI implementation
025 * @see class ProbabilityAI
026 */
027 public class ProbabilityTable {
028
029 private static final int DECK_SIZE = 36;
030
031 private static final int MAX_HAND_SIZE = 9;
032
033 private static final int PLAYERS = 4;
034
035 private static final int COLORS = 4;
036
037 private JassRound round_;
038
039 private Player viewPlayer_;
040
041 private List<Map<Card, Float>> cardProb_;
042
043 /**
044 * colorProb_:
045 * ------------------------------------------------
046 * Stores the Color probabilities for each player
047 * % Map playerColorMap = colorProb_.get(playerNr);
048 * returns the probability map for player playerNr
049 */
050 private List<Map<Integer, Float>> colorProb_;
051
052 //private GoneCardHeap goneCards_;
053
054 private int playerNr;
055
056 // private int nthThrowColor[][];
057 private List<List<Integer>> throwColors_;
058
059 private boolean[][] canHaveColor;
060
061 private int[] othersAvailableOfColor_;
062
063 private int[] ownCardsOfColor;
064
065 private int[] goneOfColor_;
066
067 /**
068 * Constructor: Create the ProbabilityTable and init all values
069 * @param p The viewpoint Player
070 * @param game The game object
071 */
072 public ProbabilityTable(Player p, JassRound game) {
073 round_ = game;
074 viewPlayer_ = p;
075
076 playerNr = round_.getPlayerNr(p);
077
078 //goneCards_ = round_.getGoneHeap();
079
080 initMaps();
081
082 update();
083 }
084
085 /**
086 * Update the table
087 */
088 public void update() {
089 RoundStats roundStats = new RoundStats(this.round_);
090 PlayerStats playerStats = new PlayerStats(this.round_, viewPlayer_);
091
092 Hand playerHand = this.viewPlayer_.getHand();
093 /* goneOfColor[colorNr] holds the number of Cards
094 * in the GoneCardHeap of Color colorNr */
095 goneOfColor_ = new int[COLORS];
096
097 /* handSize[playerNr] holds the number of Cards
098 * in the Hand of Player playerNr */
099 int handSize[] = new int[PLAYERS];
100
101 /* cardsOfColorOwn[colorNr] holds number of Card
102 * of Color colorNr in viewPlayers Hand */
103 ownCardsOfColor = new int[COLORS];
104
105 //nthThrowColor = new int[PLAYERS][MAX_HAND_SIZE];
106 throwColors_ = new LinkedList<List<Integer>>();
107
108 for (int ply = 0; ply < PLAYERS; ply++) {
109 throwColors_.add(getThrowColorList(this.round_.getPlayer(ply)));
110 handSize[ply] = this.round_.getPlayer(ply).getHand().size();
111
112 }
113
114 /* Init some Basic calculation-helper variables */
115
116 for (int i = 0; i < COLORS; i++) {
117 goneOfColor_[i] = roundStats.getGoneList()[i].size();
118
119 ownCardsOfColor[i] = playerStats.getColorList()[i].size();
120 }
121
122 /*
123 * Cards left in the game without OWN
124 */
125 cardsWithoutOwn_ = DECK_SIZE - this.round_.getGoneHeap().size()
126 - handSize[this.playerNr];
127
128 /*
129 * Wieviele Karten von color sind noch im Spiel abgesehen von OWN
130 */
131 othersAvailableOfColor_ = new int[COLORS];
132 for (int color = 0; color < COLORS; color++) {
133 othersAvailableOfColor_[color] = MAX_HAND_SIZE - ownCardsOfColor[color]
134 - goneOfColor_[color];
135 }
136
137 canHaveColor = getCanHaveColorArray(this.viewPlayer_);
138
139 //System.out.println("View of player: " + this.player_.getName());
140
141 createColorProb();
142 createCardProb();
143 }
144
145 private int cardsWithoutOwn_;
146
147 /**
148 * Returns a 2 dimensional array of boolean values.
149 * canHaveColor[playerNr][colorNr] is false, if there is no
150 * chance that player playerNr has any cards of the color colorNr
151 */
152 private boolean[][] getCanHaveColorArray(Player viewPlayer) {
153 int viewPlayerNr = this.round_.getPlayerNr(viewPlayer);
154
155 boolean canHaveColor[][] = new boolean[PLAYERS][COLORS];
156 for (int plaNr = 0; plaNr < PLAYERS; plaNr++) {
157 for (int color = 0; color < COLORS; color++) {
158
159 canHaveColor[plaNr][color] = hasAlwaysPlayedColor(this.round_
160 .getPlayer(plaNr), color);
161
162 if (othersAvailableOfColor_[color] == 0 || goneOfColor_[color] == 9) {
163 if (plaNr != viewPlayerNr) {
164 canHaveColor[plaNr][color] = false;
165 }
166 }
167 }
168 }
169 return canHaveColor;
170 }
171
172 /**
173 * Create the ProbabilityTable's color probabilities
174 *
175 */
176 private void createColorProb() {
177
178 for (int ply = 0; ply < PLAYERS; ply++) {
179 Map<Integer, Float> colorMap = new HashMap<Integer, Float>();
180
181 for (int col = 0; col < COLORS; col++) {
182 /* If it's the viewpoint Player: continue with next player */
183 if (ply == playerNr) {
184 continue;
185 }
186
187 float prob = 0;
188 /* If the player has none of this color set prob to 0 */
189 if (!this.canHaveColor[ply][col]) {
190 prob = 0;
191
192 } else {
193 for (int k = 0; k < throwColors_.get(ply).size(); k++) {
194 /*
195 * if the player has thrown away the color this reduces
196 * the prob that he has some/good left (only count once)
197 */
198 if (col == throwColors_.get(ply).get(k).intValue()) {
199 prob -= (throwColors_.get(ply).size() - k)
200 * AIFlags.AI_THROWCOLOR_MULTIPLICATOR;
201 }
202
203 /*if (col == this.nthThrowColor[ply][k]) {
204 prob -= (MAX_HAND_SIZE - k) * AIFlags.AI_THROWCOLOR_MULTIPLICATOR;
205 break;
206 }*/
207
208 }
209 int othersOfColor = this.othersAvailableOfColor_[col];
210
211 int othersCardsInGame = cardsWithoutOwn_;
212 if (othersCardsInGame != 0) {
213 prob += ((double) othersOfColor / (double) othersCardsInGame);
214 } else {
215 prob = 0;
216 }
217 }
218
219 float roundedProb = ((float) Math.rint(prob * 1000.0f)) / 1000.0f;
220
221 colorMap.put(new Integer(col), new Float(roundedProb));
222 }
223
224 this.colorProb_.add(colorMap);
225 }
226
227 }
228
229 /**
230 * Create the ProbabilityTable's card probabilities
231 *
232 */
233 private void createCardProb() {
234
235 }
236
237 /**
238 * Liefert true, wenn player bei color immer Farbe gespielt hat
239 * false, falls player color einmal nicht Gefarbt hat (eine andere
240 * Farbe verworfen hat)
241 */
242 private boolean hasAlwaysPlayedColor(Player player, int color) {
243 GoneCardHeap goneCards = this.round_.getGoneHeap();
244 boolean colorPlayed = true;
245 /* for all played turns */
246 for (int i = 0; i < goneCards.turns(); i++) {
247 Board bo = goneCards.getBoard(i);
248 int firstColor = (int) bo.get(0).getColor();
249
250 /* Ist diese Runde von der Farbe color (relevante Farbe)? */
251 if (firstColor == color) {
252 Card playedCard = goneCards.getPlayedCard(player, bo);
253
254 /* Hat der spieler nicht gefarbt? */
255 if (!(playedCard.getColor() == color)) {
256 return false;
257 }
258 }
259
260 }
261 return true;
262 }
263
264 private List<Integer> getThrowColorList(Player player) {
265 List<Integer> throwList = new LinkedList<Integer>();
266 GoneCardHeap goneCards = this.round_.getGoneHeap();
267
268 int nthThrow[] = new int[MAX_HAND_SIZE];
269
270 for (int nth = 0; nth < MAX_HAND_SIZE; nth++) {
271 nthThrow[nth] = -1;
272 }
273
274 /* For all played turns */
275 for (int turn = 0; turn < goneCards.turns(); turn++) {
276 Board bo = goneCards.getBoard(turn);
277 int firstColor = bo.get(0).getColor();
278 Card playedCard = goneCards.getPlayedCard(player, bo);
279
280 /* Hat der Spieler hier nicht gefarbt? */
281 if (!(playedCard.getColor() == firstColor)) {
282 throwList.add(Integer.valueOf(playedCard.getColor()));
283 }
284 }
285
286 return throwList;
287
288 //return nthThrow;
289 }
290
291 private void initMaps() {
292 colorProb_ = new LinkedList<Map<Integer, Float>>();
293 cardProb_ = new LinkedList<Map<Card, Float>>();
294
295 for (int i = 0; i < COLORS; i++) {
296 TreeMap<Integer, Float> colprobi = new TreeMap<Integer, Float>();
297 }
298 }
299
300 /**
301 * Get the probability of a Player having cards of a specific color
302 *
303 * @param p The relevant Player
304 * @param color The relevant color
305 * @return A double representing the chance of player p having a card of color
306 */
307 public float getColorProb(Player p, int color) {
308 int colorNr = round_.getPlayerNr(p);
309 Map<Integer, Float> playerMap = colorProb_.get(colorNr);
310 return Math.round(1000.0f*playerMap.get(new Integer(color)).floatValue())/1000.0f;
311 }
312
313 /**
314 * Get the probability of a Player having a specific card
315 *
316 * @param p The relevant Player
317 * @param c The relevant card
318 * @return A double value representing the chance of player p having c in his hand
319 */
320 public float getCardProb(Player p, Card c) {
321 int playerNr = round_.getPlayerNr(p);
322 Map<Card, Float> playerMap = cardProb_.get(playerNr);
323 return playerMap.get(c).floatValue();
324 }
325
326 public String toString() {
327 String res = new String();
328 res += ("Color prob: Player " + this.playerNr + "'s view:\n");
329 res += "Player: \t";
330 for (int ply = 0; ply < 4; ply++) {
331 if (ply != this.playerNr) {
332
333 res += (ply + "\t");
334 }
335 }
336 res += "\n";
337 for (int col = 0; col < 4; col++) {
338 res += (ESwissColorNames.getName(col)) + " =\t";
339 for (int ply = 0; ply < 4; ply++) {
340 if (ply != this.playerNr) {
341
342 Float prob = this.getColorProb(this.round_.getPlayer(ply),
343 new Integer(col));
344 res += prob + "\t";
345
346 }
347
348 }
349 res += "\n";
350 }
351
352 int ply = this.round_.getPartner(this.viewPlayer_).getID();
353 res += ("\nPartner Throws: ");
354 for (int i = 0; i < this.throwColors_.get(ply).size(); i++) {
355 int color = this.throwColors_.get(ply).get(i).intValue();
356 res += (i + ". " + ESwissColorNames.getName(color) + ", ");
357
358 }
359
360 res += "\n";
361
362 return res;
363 }
364 }