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