|
1 /** |
|
2 * $Id: ChessBoard.java 152 2008-04-27 02:04:31Z mbroeker $ |
|
3 * $URL: http://localhost/svn/eclipse/Schachspiel/trunk/org/homelinux/largo/games/board/chessboard/ChessBoard.java $ |
|
4 */ |
|
5 |
|
6 package org.homelinux.largo.games.board.chessboard; |
|
7 |
|
8 import java.awt.Image; |
|
9 |
|
10 import org.homelinux.largo.games.board.Board; |
|
11 import org.homelinux.largo.games.board.Piece; |
|
12 import org.homelinux.largo.utils.ImgComponent; |
|
13 |
|
14 public class ChessBoard extends Board { |
|
15 static final long serialVersionUID = 140208; |
|
16 |
|
17 static final int ROOK = 1; |
|
18 static final int KNIGHT = 2; |
|
19 static final int BISHOP = 3; |
|
20 static final int QUEEN = 4; |
|
21 static final int KING = 5; |
|
22 static final int PAWN = 6; |
|
23 |
|
24 final Piece white_queen = new Piece(new ImgComponent("images/white_queen.png").getImage(), |
|
25 "white", QUEEN, 90); |
|
26 final Piece black_queen = new Piece(new ImgComponent("images/black_queen.png").getImage(), |
|
27 "black", QUEEN, 90); |
|
28 |
|
29 boolean white_rochades_small; |
|
30 boolean white_rochades_big; |
|
31 boolean black_rochades_small; |
|
32 boolean black_rochades_big; |
|
33 |
|
34 void initBoard () { |
|
35 add (new ImgComponent ("images/black_rook.png").getImage (), 0, "black", ROOK); |
|
36 add (new ImgComponent ("images/black_knight.png").getImage (), 1, "black", KNIGHT); |
|
37 add (new ImgComponent ("images/black_bishop.png").getImage (), 2, "black", BISHOP); |
|
38 add (new ImgComponent ("images/black_queen.png").getImage (), 3, "black", QUEEN); |
|
39 add (new ImgComponent ("images/black_king.png").getImage (), 4, "black", KING); |
|
40 add (new ImgComponent ("images/black_bishop.png").getImage (), 5, "black", BISHOP); |
|
41 add (new ImgComponent ("images/black_knight.png").getImage (), 6, "black", KNIGHT); |
|
42 add (new ImgComponent ("images/black_rook.png").getImage (), 7, "black", ROOK); |
|
43 |
|
44 for (int i = 0; i < 8; i++) |
|
45 add (new ImgComponent ("images/black_pawn.png").getImage (), 8 + i, "black", PAWN); |
|
46 |
|
47 add (new ImgComponent ("images/white_rook.png").getImage (), 56, "white", ROOK); |
|
48 add (new ImgComponent ("images/white_knight.png").getImage (), 57, "white", KNIGHT); |
|
49 add (new ImgComponent ("images/white_bishop.png").getImage (), 58, "white", BISHOP); |
|
50 add (new ImgComponent ("images/white_queen.png").getImage (), 59, "white", QUEEN); |
|
51 add (new ImgComponent ("images/white_king.png").getImage (), 60, "white", KING); |
|
52 add (new ImgComponent ("images/white_bishop.png").getImage (), 61, "white", BISHOP); |
|
53 add (new ImgComponent ("images/white_knight.png").getImage (), 62, "white", KNIGHT); |
|
54 add (new ImgComponent ("images/white_rook.png").getImage (), 63, "white", ROOK); |
|
55 |
|
56 for (int i = 0; i < 8; i++) |
|
57 add (new ImgComponent ("images/white_pawn.png").getImage (), 55 - i, "white", PAWN); |
|
58 } |
|
59 |
|
60 /** |
|
61 * The init method initializes a complete chess board with figures and a history. |
|
62 */ |
|
63 public void init() { |
|
64 super.init(); |
|
65 initBoard(); |
|
66 board_pieces = getPieces(); |
|
67 repaint(); |
|
68 } |
|
69 |
|
70 public ChessBoard (int w, int h) { |
|
71 super(w, h); |
|
72 } |
|
73 |
|
74 void add (Image img, int i, String c, int t) { |
|
75 int v = 0; |
|
76 |
|
77 switch (t) { |
|
78 case ROOK: |
|
79 v = 40; |
|
80 break; |
|
81 case KNIGHT: |
|
82 v = 30; |
|
83 break; |
|
84 case BISHOP: |
|
85 v = 30; |
|
86 break; |
|
87 case QUEEN: |
|
88 v = 90; |
|
89 break; |
|
90 case KING: |
|
91 v = 500; |
|
92 break; |
|
93 case PAWN: |
|
94 v = 10; |
|
95 break; |
|
96 } |
|
97 |
|
98 setPiece(i, new Piece(img, c, t, v)); |
|
99 } |
|
100 |
|
101 /** |
|
102 * returns true, when the white king is at pieces[i] |
|
103 */ |
|
104 public boolean isWhiteKing(int i) { |
|
105 if ( isWhite(i) && getType(i) == KING) |
|
106 return true; |
|
107 return false; |
|
108 } |
|
109 |
|
110 /** |
|
111 * returns true, when the black king is at pieces[i] |
|
112 */ |
|
113 public boolean isBlackKing(int i) { |
|
114 if ( isBlack(i) && getType(i) == KING) |
|
115 return true; |
|
116 return false; |
|
117 } |
|
118 |
|
119 /** |
|
120 * Returns the score of the current position |
|
121 * Every field controlled by [color] gives one point |
|
122 * A King, controlled by [color], gives 10 extra points |
|
123 */ |
|
124 public int controls(String color) { |
|
125 int t, o; |
|
126 int value = 0; |
|
127 |
|
128 for ( o=0;o<64;o++) { |
|
129 if (color.equals(getColor(o))) { |
|
130 for (t=0;t<64;t++) { |
|
131 if(validMove(t, o)) { |
|
132 if ( getType(t) == KING ) |
|
133 value+=10; |
|
134 value++; |
|
135 } |
|
136 } |
|
137 } |
|
138 } |
|
139 return value; |
|
140 } |
|
141 |
|
142 /** |
|
143 * Checks, wether this move is possible or not. |
|
144 */ |
|
145 public boolean validMove (int t, int o) { |
|
146 int steps; |
|
147 int rows; |
|
148 int dx; |
|
149 |
|
150 /* Must be here */ |
|
151 white_rochades_small = false; |
|
152 white_rochades_big = false; |
|
153 black_rochades_small = false; |
|
154 black_rochades_big = false; |
|
155 |
|
156 if ( t == o ) |
|
157 return false; |
|
158 |
|
159 if (isSamePiece(t, o)) |
|
160 return false; |
|
161 |
|
162 if (getType(o) == EMPTY) |
|
163 return false; |
|
164 |
|
165 /* |
|
166 * 00 01 02 03 04 05 06 07 |
|
167 * 08 09 10 11 12 13 14 15 |
|
168 * 16 17 18 19 20 21 22 23 |
|
169 * 24 25 26 27 28 29 30 31 |
|
170 * 32 33 34 35 36 37 38 39 |
|
171 * 40 41 42 43 44 45 46 47 |
|
172 * 48 49 50 51 52 53 54 55 |
|
173 * 56 57 58 59 60 61 62 63 |
|
174 */ |
|
175 |
|
176 steps = Math.abs(t-o); |
|
177 rows = Math.abs(t/8 - o/8); |
|
178 |
|
179 switch( getType(o) ) { |
|
180 case ROOK: |
|
181 if (steps < 8 && rows == 0 ) { |
|
182 if(t>o) |
|
183 for ( dx = o+1; dx < t; dx++ ) { |
|
184 if ( getColor(dx) != null ) { |
|
185 return false; |
|
186 } |
|
187 } |
|
188 else |
|
189 for ( dx = o-1; dx > t; dx-- ) { |
|
190 if ( getColor(dx) != null ) { |
|
191 return false; |
|
192 } |
|
193 } |
|
194 return true; |
|
195 } |
|
196 if (steps % 8 == 0 ) { |
|
197 if ( t>o ) { |
|
198 for ( dx = o+8; dx < t; dx+=8 ) { |
|
199 if (getColor(dx) != null) |
|
200 return false; |
|
201 } |
|
202 } else { |
|
203 for ( dx = o-8; dx > t; dx-=8 ) { |
|
204 if (getColor(dx) != null) |
|
205 return false; |
|
206 } |
|
207 } |
|
208 if (steps == 8 && rows == 1) |
|
209 return true; |
|
210 if (steps == 16 && rows == 2) |
|
211 return true; |
|
212 if (steps == 24 && rows == 3) |
|
213 return true; |
|
214 if (steps == 32 && rows == 4) |
|
215 return true; |
|
216 if (steps == 40 && rows == 5) |
|
217 return true; |
|
218 if (steps == 48 && rows == 6) |
|
219 return true; |
|
220 if (steps == 56 && rows == 7) |
|
221 return true; |
|
222 } |
|
223 break; |
|
224 case KNIGHT: |
|
225 /* works fine */ |
|
226 if (steps == 6 && rows == 1) |
|
227 return true; |
|
228 if (steps == 10 && rows == 1) |
|
229 return true; |
|
230 if (steps == 15 && rows == 2) |
|
231 return true; |
|
232 if (steps == 17 && rows == 2) |
|
233 return true; |
|
234 break; |
|
235 case BISHOP: |
|
236 if (steps % 7 == 0 ) { |
|
237 if ( t>o ) { |
|
238 for ( dx = o+7; dx < t; dx+=7 ) { |
|
239 if (getColor(dx) != null) |
|
240 return false; |
|
241 } |
|
242 } else { |
|
243 for ( dx = o-7; dx > t; dx-=7 ) { |
|
244 if (getColor(dx) != null) |
|
245 return false; |
|
246 } |
|
247 } |
|
248 if (steps == 7 && rows == 1) |
|
249 return true; |
|
250 if (steps == 14 && rows == 2) |
|
251 return true; |
|
252 if (steps == 21 && rows == 3) |
|
253 return true; |
|
254 if (steps == 28 && rows == 4) |
|
255 return true; |
|
256 if (steps == 35 && rows == 5) |
|
257 return true; |
|
258 if (steps == 42 && rows == 6) |
|
259 return true; |
|
260 if (steps == 49 && rows == 7) |
|
261 return true; |
|
262 } |
|
263 if (steps % 9 == 0 ) { |
|
264 if ( t>o ) { |
|
265 for ( dx = o+9; dx < t; dx+=9 ) { |
|
266 if (getColor(dx) != null) |
|
267 return false; |
|
268 } |
|
269 } else { |
|
270 for ( dx = o-9; dx > t; dx-=9 ) { |
|
271 if (getColor(dx) != null) |
|
272 return false; |
|
273 } |
|
274 } |
|
275 if (steps == 9 && rows == 1) |
|
276 return true; |
|
277 if (steps == 18 && rows == 2) |
|
278 return true; |
|
279 if (steps == 27 && rows == 3) |
|
280 return true; |
|
281 if (steps == 36 && rows == 4) |
|
282 return true; |
|
283 if (steps == 45 && rows == 5) |
|
284 return true; |
|
285 if (steps == 54 && rows == 6) |
|
286 return true; |
|
287 if (steps == 63 && rows == 7) |
|
288 return true; |
|
289 } |
|
290 break; |
|
291 |
|
292 case QUEEN: |
|
293 if (steps < 8 && rows == 0 ) { |
|
294 if(t>o) |
|
295 for ( dx = o+1; dx < t; dx++ ) { |
|
296 if ( getColor(dx) != null ) |
|
297 return false; |
|
298 } |
|
299 else |
|
300 for ( dx = o-1; dx > t; dx-- ) { |
|
301 if ( getColor(dx) != null ) |
|
302 return false; |
|
303 } |
|
304 return true; |
|
305 } |
|
306 |
|
307 if (steps % 8 == 0 ) { |
|
308 if ( t>o ) { |
|
309 for ( dx = o+8; dx < t; dx+=8 ) { |
|
310 if (getColor(dx) != null) |
|
311 return false; |
|
312 } |
|
313 } else { |
|
314 for ( dx = o-8; dx > t; dx-=8 ) { |
|
315 if (getColor(dx) != null) |
|
316 return false; |
|
317 } |
|
318 } |
|
319 |
|
320 if (steps == 8 && rows == 1) |
|
321 return true; |
|
322 if (steps == 16 && rows == 2) |
|
323 return true; |
|
324 if (steps == 24 && rows == 3) |
|
325 return true; |
|
326 if (steps == 32 && rows == 4) |
|
327 return true; |
|
328 if (steps == 40 && rows == 5) |
|
329 return true; |
|
330 if (steps == 48 && rows == 6) |
|
331 return true; |
|
332 if (steps == 56 && rows == 7) |
|
333 return true; |
|
334 } |
|
335 if (steps % 7 == 0 ) { |
|
336 if ( t>o ) { |
|
337 for ( dx = o+7; dx < t; dx+=7 ) { |
|
338 if (getColor(dx) != null) |
|
339 return false; |
|
340 } |
|
341 } else { |
|
342 for ( dx = o-7; dx > t; dx-=7 ) { |
|
343 if (getColor(dx) != null) |
|
344 return false; |
|
345 } |
|
346 } |
|
347 if (steps == 7 && rows == 1) |
|
348 return true; |
|
349 if (steps == 14 && rows == 2) |
|
350 return true; |
|
351 if (steps == 21 && rows == 3) |
|
352 return true; |
|
353 if (steps == 28 && rows == 4) |
|
354 return true; |
|
355 if (steps == 35 && rows == 5) |
|
356 return true; |
|
357 if (steps == 42 && rows == 6) |
|
358 return true; |
|
359 if (steps == 49 && rows == 7) |
|
360 return true; |
|
361 } |
|
362 |
|
363 if (steps % 9 == 0 ) { |
|
364 if ( t>o ) { |
|
365 for ( dx = o+9; dx < t; dx+=9 ) { |
|
366 if (getColor(dx) != null) |
|
367 return false; |
|
368 } |
|
369 } else { |
|
370 for ( dx = o-9; dx > t; dx -=9 ) { |
|
371 if (getColor(dx) != null) |
|
372 return false; |
|
373 } |
|
374 } |
|
375 if (steps == 9 && rows == 1) |
|
376 return true; |
|
377 if (steps == 18 && rows == 2) |
|
378 return true; |
|
379 if (steps == 27 && rows == 3) |
|
380 return true; |
|
381 if (steps == 36 && rows == 4) |
|
382 return true; |
|
383 if (steps == 45 && rows == 5) |
|
384 return true; |
|
385 if (steps == 54 && rows == 6) |
|
386 return true; |
|
387 if (steps == 63 && rows == 7) |
|
388 return true; |
|
389 } |
|
390 break; |
|
391 |
|
392 case KING: |
|
393 if ( (steps == 1) && (rows == 0) ) |
|
394 return true; |
|
395 |
|
396 if ( (steps == 8) && (rows == 1) ) |
|
397 return true; |
|
398 |
|
399 if ( (steps == 7) && (rows == 1) ) |
|
400 return true; |
|
401 |
|
402 if ( (steps == 9) && (rows == 1) ) |
|
403 return true; |
|
404 |
|
405 if ( (steps == 2) && (rows == 0) ) { |
|
406 if ( isWhiteKing(o) ) { /* White: Rochade */ |
|
407 if ( isWhiteKing(60) && isEmpty(61) && isEmpty(62) && (t==62) ) { |
|
408 if ( (getType(63) == ROOK) && isWhite(63) ) { |
|
409 white_rochades_small = true; |
|
410 return true; |
|
411 } |
|
412 } |
|
413 |
|
414 if ( isWhiteKing(60) && isEmpty(59) && isEmpty(58) && isEmpty(57) && (t==58) ) { |
|
415 if ( (getType(56) == ROOK) && isWhite(56) ) { |
|
416 white_rochades_big = true; |
|
417 return true; |
|
418 } |
|
419 } |
|
420 } |
|
421 |
|
422 if ( isBlackKing(o) ) { /* Black: Rochade */ |
|
423 if ( isBlackKing(4) && isEmpty(5) && isEmpty(6) && (t==6) ) { |
|
424 if ( (getType(7) == ROOK) && isBlack(7) ) { |
|
425 black_rochades_small = true; |
|
426 return true; |
|
427 } |
|
428 } |
|
429 |
|
430 if ( isBlackKing(4) && isEmpty(3) && isEmpty(2) && isEmpty(1) && (t==2) ) { |
|
431 if ( (getType(0) == ROOK) && isBlack(0) ) { |
|
432 black_rochades_big = true; |
|
433 return true; |
|
434 } |
|
435 } |
|
436 } |
|
437 } |
|
438 break; |
|
439 |
|
440 case PAWN: |
|
441 if (getColor(o).equals("white")) { |
|
442 if (steps == 7 && rows == 1 && isEnemy(t, o) && t<o) |
|
443 return true; |
|
444 |
|
445 if (steps == 9 && rows == 1 && isEnemy(t, o) && t<o) |
|
446 return true; |
|
447 } else { |
|
448 if (steps == 7 && rows == 1 && isEnemy(t, o) && t>o) |
|
449 return true; |
|
450 |
|
451 if (steps == 9 && rows == 1 && isEnemy(t, o) && t>o) |
|
452 return true; |
|
453 } |
|
454 |
|
455 if (steps % 8 == 0 ) { |
|
456 if ( t>o ) { |
|
457 for ( dx = o+8; dx <= t; dx+=8 ) { |
|
458 if (getColor(dx) != null) |
|
459 return false; |
|
460 } |
|
461 } else { |
|
462 for ( dx = o-8; dx >= t; dx-=8 ) { |
|
463 if (getColor(dx) != null) |
|
464 return false; |
|
465 } |
|
466 } |
|
467 |
|
468 if (steps == 8 && rows == 1) { |
|
469 if ( getColor(o).equals("white") && t < o ) |
|
470 return true; |
|
471 if ( getColor(o).equals("black") && t > o ) |
|
472 return true; |
|
473 } |
|
474 |
|
475 if (steps == 16 && rows == 2 && (o>= 8 && o <=15) ) { |
|
476 if ( getColor(o).equals("white") && t < o ) |
|
477 return true; |
|
478 if ( getColor(o).equals("black") && t > o ) |
|
479 return true; |
|
480 } |
|
481 |
|
482 if (steps == 16 && rows == 2 && (o>=48 && o <=55) ) { |
|
483 if ( getColor(o).equals("white") && t < o ) |
|
484 return true; |
|
485 if ( getColor(o).equals("black") && t > o ) |
|
486 return true; |
|
487 } |
|
488 } |
|
489 break; |
|
490 } |
|
491 return false; |
|
492 } |
|
493 |
|
494 /** |
|
495 * This method must be called immediately after isValidMove(t, o) |
|
496 */ |
|
497 boolean rochade() { |
|
498 if (white_rochades_small) { |
|
499 setPiece(61, getPiece(63)); |
|
500 setPiece(63, new Piece(null, null, EMPTY, 0)); |
|
501 return true; |
|
502 } |
|
503 |
|
504 if (white_rochades_big) { |
|
505 setPiece(59, getPiece(56)); |
|
506 setPiece(56, new Piece(null, null, EMPTY, 0)); |
|
507 return true; |
|
508 } |
|
509 |
|
510 if (black_rochades_small) { |
|
511 setPiece(5, getPiece(7)); |
|
512 setPiece(7, new Piece(null, null, EMPTY, 0)); |
|
513 return true; |
|
514 } |
|
515 |
|
516 if (black_rochades_big) { |
|
517 setPiece(3, getPiece(0)); |
|
518 setPiece(0, new Piece(null, null, EMPTY, 0)); |
|
519 return true; |
|
520 } |
|
521 |
|
522 return false; |
|
523 } |
|
524 |
|
525 /** |
|
526 * checks, whether color is in check or not. |
|
527 */ |
|
528 public boolean isCheck(String color) { |
|
529 int i; |
|
530 int wking; |
|
531 int bking; |
|
532 |
|
533 wking = bking = -1; |
|
534 |
|
535 for (i=0;i<64;i++) { |
|
536 if (isWhiteKing(i)) { |
|
537 wking = i; |
|
538 } |
|
539 if (isBlackKing(i)) { |
|
540 bking = i; |
|
541 } |
|
542 } |
|
543 |
|
544 // returns 64 false positives |
|
545 if (wking == -1 || bking == -1) |
|
546 return true; |
|
547 |
|
548 if (color.equals("white")) { |
|
549 for (i=0;i<64;i++) |
|
550 if (validMove(wking, i)) { |
|
551 return true; |
|
552 } |
|
553 |
|
554 return false; |
|
555 } |
|
556 |
|
557 if (color.equals("black")) { |
|
558 for (i=0;i<64;i++) |
|
559 if (validMove(bking, i)) { |
|
560 return true; |
|
561 } |
|
562 |
|
563 return false; |
|
564 } |
|
565 return false; |
|
566 } |
|
567 |
|
568 /** |
|
569 * simulates a "valid" move or returns false. |
|
570 * all changes are relative to pieces and will not be painted. |
|
571 * This method sets internal variables for the rochade() method, which will be overwritten. |
|
572 */ |
|
573 public boolean simulateMove(int t, int o) { |
|
574 if ( !validMove(t, o) ) { |
|
575 return false; |
|
576 } |
|
577 |
|
578 push(getPiece(t), t, getPiece(o), o); |
|
579 |
|
580 if ( getType(o) == PAWN ) { |
|
581 if(isBlack(o) && t >=56) |
|
582 setPiece(o, new Piece(black_queen)); |
|
583 |
|
584 if(isWhite(o) && t <=7) |
|
585 setPiece(o, new Piece(white_queen)); |
|
586 } |
|
587 |
|
588 setPiece(t, new Piece(getPiece(o))); |
|
589 setPiece(o, new Piece(null, null, EMPTY, 0)); |
|
590 |
|
591 if (isCheck(getColor(t))) { |
|
592 /* restore current position */ |
|
593 if(UNDO_DEBUG) |
|
594 print("UNDO", t, o, 0); |
|
595 undo(); |
|
596 return false; |
|
597 } |
|
598 |
|
599 return true; |
|
600 } |
|
601 |
|
602 /** |
|
603 * performs a "valid" move or returns false. |
|
604 * all changes are relative to board_pieces and will be painted. |
|
605 */ |
|
606 public boolean doMove(int t, int o) { |
|
607 if ( !validMove(t, o) ) { |
|
608 return false; |
|
609 } |
|
610 |
|
611 push(getPiece(t), t, getPiece(o), o); |
|
612 |
|
613 if ( getType(o) == PAWN ) { |
|
614 if(isBlack(o) && t >=56) |
|
615 setPiece(o, new Piece(black_queen)); |
|
616 |
|
617 if(isWhite(o) && t <=7) |
|
618 setPiece(o, new Piece(white_queen)); |
|
619 } |
|
620 |
|
621 setPiece(t, new Piece(getPiece(o))); |
|
622 setPiece(o, new Piece(null, null, EMPTY, 0)); |
|
623 |
|
624 if (rochade()) |
|
625 System.out.println("Rochade"); |
|
626 |
|
627 if (isCheck(getColor(t))) { |
|
628 // restore current positions |
|
629 if(UNDO_DEBUG) |
|
630 print("UNDO", t, o, 0); |
|
631 undo(); |
|
632 return false; |
|
633 } |
|
634 |
|
635 board_pieces = getPieces(); |
|
636 repaint(); |
|
637 |
|
638 moveNr = stack.size(); |
|
639 |
|
640 return true; |
|
641 } |
|
642 |
|
643 /** |
|
644 * converts the internal representation into normal chess notation and writes it to stdout |
|
645 */ |
|
646 public void print(String s, int t, int o, int value) { |
|
647 int row1, col1, row2, col2; |
|
648 |
|
649 row1 = o/8; |
|
650 col1 = o-(8*row1); |
|
651 |
|
652 row2 = t/8; |
|
653 col2 = t-(8*row2); |
|
654 |
|
655 System.out.printf("%s: %C%d-%c%d = %3d\n", s, |
|
656 ('A')+col1, 8-row1, |
|
657 ('A')+col2, 8-row2, value); |
|
658 } |
|
659 } |