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 }