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 }