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    }