001    package jagafa.ai;
002    
003    import jagafa.JassRound;
004    import jagafa.flags.TestingFlags;
005    import jagafa.naming.ESwissColorNames;
006    import jagafa.object.Board;
007    import jagafa.object.Card;
008    import jagafa.object.CardList;
009    import jagafa.object.Player;
010    import jagafa.rule.RuleSet;
011    import jagafa.stats.PlayerStats;
012    
013    /**
014     * AI - Yet only for Oben-, Unten- and Coiffeur-RuleSet
015     * Uses the ProbabilityTable for the Throw/Bring strategy only
016     * TODO: Extend probability table usage to other strategys
017     */
018    public class ProbabilityAI implements JassAI {
019    
020            private static final int FIRST_CARD = 0;
021    
022            private static final double COLORS = 4;
023    
024            private static final int PLAYERS = 4;
025    
026            private Player player_;
027    
028            private JassRound round_;
029    
030            private RuleSet rules_;
031    
032            private int trumpfColor_;
033    
034            private Board board_;
035    
036            private ProbabilityTable probTable_;
037    
038            private PlayerStats stats_;
039    
040            public Card computeCard() {
041                    this.stats_ = new PlayerStats(this.round_, this.player_);
042                    this.probTable_ = new ProbabilityTable(this.player_, this.round_);
043                    Card c = getCard();
044    
045                    if (TestingFlags.aiStrategyDump_)
046                            if (c != null) {
047                                    System.out.print("\t" + ESwissColorNames.getName(c.getColor()));
048                                    System.out.println("    \t" + this.round_.getRules().getPower(c,this.board_));
049                                    /*      System.out.println(" with (" + c + ") c="
050                                     + this.round_.getRules().getScore(c));*/
051                            }
052                    return c;
053            }
054    
055            /**
056             * Computes a card according to the strategy
057             */
058            private Card getCard() {
059                    if (TestingFlags.aiStrategyDump_) {
060                            System.out.println("Player\t" + this.player_.getName() + "...");
061                    }
062    
063                    this.stats_.update();
064                    if (this.round_.activeBoard().get(FIRST_CARD) != null) {
065                            Card firstCard = board_.get(FIRST_CARD);
066    
067                            CardList cardsOfFirst = stats_.getColorList()[firstCard.getColor()];
068    
069                            if (cardsOfFirst.size() == 0) {
070                                    if (TestingFlags.aiStrategyDump_)
071                                            System.out.print(" Throw: ");
072                                    return throwAway(); // Verrüärä
073                            } else {
074                                    if (TestingFlags.aiStrategyDump_)
075                                            System.out.print(" Color: ");
076                                    return sameColor(firstCard.getColor()); // Farben spielen
077                            }
078                    } else {
079                            if (hasBock(0)) {
080                                    if (TestingFlags.aiStrategyDump_)
081                                            System.out.print(" Bock:   ");
082                                    return getBock(); // Böcke spielen
083                            }
084    
085                            return tearOut(); // Farbe Anziehen bzw. dem Partner bringen
086                    }
087    
088            }
089    
090            /**
091             * This strategy is played 
092             * 1) if the player doesn't have any Card of firstcolor or
093             * 2) If he brings a color to his partner.
094             * In the second case the color with the highest partner-probability is played
095             */
096            private Card tearOut() {
097                    double highestProb = -100;
098                    int actHProb = -100;
099                    int secondHProb = -100;
100                    Player opp[] = round_.getOpponents(this.player_);
101    
102                    Player partner = round_.getPartner(this.player_);
103                    for (int col = 0; col < COLORS; col++) {
104                            float oppProb1 = probTable_.getColorProb(opp[0], col);
105                            float oppProb2 = probTable_.getColorProb(opp[1], col);
106                            float oppProb = (oppProb1 + oppProb2) / 8;
107                            float prob = probTable_.getColorProb(partner, col) - oppProb;
108                            if (TestingFlags.probAIDump_) {
109                                    System.out.println(" \tProb\t" + ESwissColorNames.values()[col] + "= "
110                                                    + prob);
111                            }
112                            if (prob > highestProb) {
113                                    highestProb = prob;
114                                    secondHProb = actHProb;
115                                    actHProb = col;
116                            }
117    
118                    }
119    
120                    for (int bockNth = 8; bockNth > 0; bockNth--) {
121                            if (hasBock(bockNth, actHProb)) {
122                                    Card b = getBock(bockNth, actHProb);
123                                    if (TestingFlags.aiStrategyDump_)
124                                            if (TestingFlags.aiStrategyDump_) {
125                                                    System.out.println("Using Probtable:\n");
126                                                    System.out.println(probTable_.toString());
127    
128                                                    System.out.print(" Bring first: ");
129                                            }
130                                    return b;
131                            }
132                    }
133    
134                    if (secondHProb != -100) {
135                            for (int bockNth = 8; bockNth > 0; bockNth--) {
136                                    if (hasBock(bockNth, secondHProb)) {
137                                            Card b = getBock(bockNth, secondHProb);
138                                            if (TestingFlags.aiStrategyDump_) {
139                                                    System.out.println("Using Probtable:\n");
140                                                    System.out.println(probTable_.toString());
141    
142                                                    System.out.print(" Bring second: ");
143                                            }
144                                            return b;
145                                    }
146                            }
147                    }
148    
149                    for (int bockNth = 8; bockNth > 0; bockNth--) {
150                            if (hasBock(bockNth)) {
151                                    if (TestingFlags.aiStrategyDump_)
152                                            System.out.print(" Tear: ");
153                                    return getBock(bockNth);
154                            }
155                    }
156                    return null;
157            }
158    
159            /**
160             * Gibt einen 0. Bock (wenn vorhanden, sonst zufälliger) der Farbe mit den 
161             * meisten Karten zurück  
162             */
163            private Card getBock() {
164                    Card resultCard = null;
165                    int colorWithMost = getColorWithMost(stats_.getColorList());
166                    if (colorWithMost != -1) {
167                            resultCard = getBock(0, colorWithMost); // stats_.getBockList()[colorWithMost].get(0);
168                            return resultCard;
169                    }
170                    int randomNr = (int) (Math.random() * COLORS);
171                    resultCard = stats_.getBockList()[randomNr].get(0);
172                    System.out.print("Random ");
173                    return resultCard;
174            }
175    
176            /** 
177             * Gibt einen n-ten Bock beliebiger Farbe zurück 
178             */
179            private Card getBock(int nth) {
180                    CardList bockI = stats_.getBockList()[nth];
181                    if (bockI.size() > 0) {
182                            for (int i = 0; i < bockI.size(); i++) {
183    
184                                    return bockI.get(i);
185    
186                            }
187    
188                    }
189                    return null;
190            }
191    
192            /**
193             * Gibt einen n-ten Bock der Farbe color zurück
194             */
195            private Card getBock(int nth, int color) {
196                    Card resultCard = null;
197                    CardList bockI = stats_.getBockList()[nth];
198                    if (bockI.size() > 0) {
199                            for (int i = 0; i < bockI.size(); i++) {
200                                    if (bockI.get(i).getColor() == color) {
201                                            return bockI.get(i);
202                                    }
203                            }
204    
205                    }
206                    return resultCard;
207            }
208    
209            /**
210             * @return
211             */
212            private int getColorWithMost(CardList cardL[]) {
213                    int mostNrColor = -1;
214                    int colorWithMost = -1;
215    
216                    for (int i = 0; i < cardL.length; i++) {
217                            CardList colori = cardL[i];
218                            int nrColorI = colori.size();
219                            if (nrColorI >= mostNrColor && hasBock(0, i)) {
220                                    mostNrColor = nrColorI;
221                                    colorWithMost = i;
222    
223                            }
224                    }
225                    return colorWithMost;
226            }
227    
228            /**
229             * Returns true if the player has a Bock of grade n(th)
230             */
231            private boolean hasBock(int nth) {
232                    for (int i = 0; i < COLORS; i++) {
233                            if (hasBock(nth, i)) {
234                                    return true;
235                            }
236    
237                    }
238                    return false;
239            }
240    
241            /**
242             * Returns true if the player has a Bock of grade n(th) and the Color given
243             */
244            private boolean hasBock(int nth, int color) {
245                    CardList bockI = stats_.getBockList()[nth];
246                    if (bockI.size() > 0) {
247                            for (int i = 0; i < bockI.size(); i++) {
248                                    if (bockI.get(i).getColor() == color) {
249                                            return true;
250                                    }
251                            }
252                    }
253                    return false;
254            }
255    
256            private boolean isBock(int nth, Card c) {
257                    int color = c.getColor();
258                    CardList bockList = this.stats_.getBockList()[nth];
259                    if (bockList.contains(c)) {
260                            return true;
261                    }
262    
263                    return false;
264    
265            }
266    
267            /**
268             * Play a card of the color specified
269             */
270            private Card sameColor(int color) {
271                    if (this.round_.getGoneHeap().turns() == 0) {
272                            if (this.board_.size() == 2) {
273                                    /* Spiele den höchsten der Farbe die Partner zuerst anspielt */
274                                    for (int bockNth = 0; bockNth < 8; bockNth++) {
275                                            if (hasBock(bockNth, color)) {
276                                                    return getBock(bockNth, color);
277                                            }
278                                    }
279    
280                            }
281                    }
282                    /* Wenn letzer des Zuges, dann kann er auch mit einem niedrigeren Stechen, 
283                     * falls vorhanden!
284                     */
285                    if (this.board_.size()==3) {
286                            for (int bockNth = 8; bockNth > 0; bockNth--) {
287                                    if (hasBock(bockNth, color)) {
288                                            if (this.rules_.compareHigher(getBock(bockNth,color),this.board_)){
289                                                    return getBock(bockNth, color); 
290                                            }
291                                    }
292                            }
293                            
294                            
295                    }
296                    
297    
298                    Card firstCard = this.board_.getFirstCard();
299                    if (hasBock(0, color)) {
300                            return getBock(0, color);
301                    } else {
302                            for (int bockNth = 8; bockNth > 0; bockNth--) {
303                                    if (hasBock(bockNth, color)) {
304    
305                                            return getBock(bockNth, color);
306                                    }
307                            }
308                    }
309                    return null;
310            }
311    
312            /**
313             * Throw away or bring a Card to the Partner 
314             */
315            private Card throwAway() {
316                    int throwAwayColor = -1;
317                    int maxColorValue = -1;
318    
319                    for (int c = 0; c < COLORS; c++) {
320                            CardList colorList = this.stats_.getColorList()[c];
321    
322                            if (colorList.size() == 1) {
323                                    if (!isBock(0, colorList.get(0))) {
324                                            return colorList.get(0);
325                                    }
326    
327                            }
328    
329                            int colorValue = getColorValue(c);
330                            if (colorValue > maxColorValue) {
331                                    maxColorValue = colorValue;
332                                    throwAwayColor = c;
333                            }
334                    }
335    
336                    for (int bockNth = 8; bockNth >= 0; bockNth--) {
337                            if (hasBock(bockNth, throwAwayColor)) {
338                                    return getBock(bockNth, throwAwayColor);
339                            }
340                    }
341                    for (int c = 0; c < COLORS; c++) {
342                            for (int bockNth = 8; bockNth >= 0; bockNth--) {
343                                    if (hasBock(bockNth, c)) {
344                                            return getBock(bockNth, c);
345                                    }
346                            }
347                    }
348                    return null;
349    
350            }
351    
352            /**
353             * @param c
354             * @return
355             */
356            private int getColorValue(int c) {
357                    int value = 0;
358                    for (int i = 0; i < 9; i++) {
359                            if (hasBock(i, c)) {
360                                    value += (i) * (i);
361                            }
362                    }
363                    return value;
364            }
365    
366            /*
367             * (non-Javadoc)
368             * 
369             * @see jass.JassAI#init(jass.JassGame)
370             */
371            public void init(Player p, JassRound game) {
372                    this.player_ = p;
373                    this.round_ = game;
374                    this.rules_ = game.getRules();
375                    this.board_ = round_.activeBoard();
376            }
377    
378            public RuleSet chooseRuleSet() {
379                    return RuleSetChoiceAI.chooseRuleSet(this.player_, this.round_);
380            }
381    
382    }