View Javadoc
1   /******************************************************************************
2    * Board.java - Define a backgammon board 
3    * $Id$
4    * 
5    * BuckoFIBS - Backgammon by BuckoSoft
6    * Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.
7    * 
8    * $Log$
9    * Revision 1.16  2013/09/12 06:40:41  dick
10   * static xoToTurn().
11   *
12   * Revision 1.15  2011/07/04 03:36:01  dick
13   * Add getCanMove().
14   *
15   * Revision 1.14  2011/06/19 04:14:31  dick
16   * Define turnO and turnX.
17   *
18   * Revision 1.13  2011/06/13 04:38:42  dick
19   * Add parseFibsBoard(s, bool) for debugging boards.
20   *
21   * Revision 1.12  2011/06/10 05:59:32  dick
22   * Add isOpponentMayDouble().
23   *
24   * Revision 1.11  2011/06/02 19:04:37  dick
25   * Add attributes and methods for dealing with a player resigning.
26   *
27   * Revision 1.10  2011/05/21 20:19:09  dick
28   * If setSortDice(true) then sort any existing dice.
29   *
30   * Revision 1.9  2011/05/21 04:54:40  dick
31   * happenings about doubles goes in Board, not Document.
32   *
33   * Revision 1.8  2011/05/18 05:50:46  dick
34   * Javadoc.
35   *
36   * Revision 1.7  2011/05/17 23:55:25  dick
37   * Add the clone() method.
38   *
39   * Revision 1.6  2011/05/17 23:14:04  dick
40   * getDirectionFromName() does that.
41   *
42   * Revision 1.5  2011/05/16 21:20:43  dick
43   * Javadoc.
44   *
45   * Revision 1.4  2011/05/16 11:35:43  dick
46   * getXOFromName determines the direction from an event.
47   *
48   * Revision 1.3  2011/05/15 18:16:52  dick
49   * Javadoc link fix.
50   *
51   * Revision 1.2  2011/05/14 05:19:46  dick
52   * Still need work on the doubles handling for board/document split.
53   *
54   * Revision 1.1  2011/05/14 04:43:01  dick
55   * I needed to deal with some lightweight Boards.
56   * So finally make the primary document Document
57   * and demote just the Board handling to a domain object.
58   *
59   * Revision 1.10  2011/05/13 18:23:25  dick
60   * Commentality.
61   *
62   * Revision 1.9  2011/05/13 14:18:15  dick
63   * Define constants Home=0 and Bar=25.
64   *
65   * Revision 1.8  2011/05/10 20:34:22  dick
66   * Javadoc.
67   *
68   * Revision 1.7  2011/01/01 06:10:25  dick
69   * Javadoc.
70   *
71   * Revision 1.6  2010/12/29 07:42:24  dick
72   * Sorting dice is optional.
73   *
74   * Revision 1.5  2010/12/24 06:12:07  dick
75   * Handle the onMatchOver message correctly.
76   *
77   * Revision 1.4  2010/03/03 13:12:22  inim
78   * Replaced (c) sign in comment mangled by CVS default encoding back to UTF-8
79   *
80   * Revision 1.3  2010/03/03 12:19:49  inim
81   * Moved source to UTF8 encoding from CP1252 encoding. To this end all source files' (c) message was updated to "Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.". This replaces the (c) sign to UTF8, and adds the new year 2010.
82   *
83   * Revision 1.2  2010/02/08 09:12:35  dick
84   * isRace() determines if a game is race mode.
85   *
86   * Revision 1.1  2010/02/04 05:57:53  inim
87   * Mavenized project folder layout
88   *
89   * Revision 1.35  2010/01/23 06:13:06  dick
90   * removeSavedMatch() removes a match from the saved (unfinished) matches list.
91   *
92   * Revision 1.34  2009/02/24 07:12:35  dick
93   * Correctly parse the match score onMatchOver().
94   *
95   * Revision 1.33  2009/02/20 10:20:47  dick
96   * Use YourName and OpponentName where possible, instead of just "getName".
97   *
98   * Revision 1.32  2009/02/17 14:44:08  dick
99   * Turn off DEBUG.
100  *
101  * Revision 1.31  2009/02/14 12:04:30  dick
102  * BuckoFIBS is released under the GNU license.
103  *
104  * Revision 1.30  2009/02/12 06:05:26  dick
105  * Javadoc.
106  *
107  * Revision 1.29  2009/02/11 08:59:24  dick
108  * Better beginning and ending your turn.
109  *
110  * Revision 1.28  2009/02/06 07:56:49  dick
111  * Working on doubles.
112  *
113  * Revision 1.27  2009/02/01 21:21:01  dick
114  * Add savedMatches and missManners lists to track other players' behavior.
115  *
116  * Revision 1.26  2009/01/29 08:26:39  dick
117  * Fix the pip count calculation.
118  *
119  * Revision 1.25  2009/01/28 19:42:37  dick
120  * Prettier cvs link in the javadoc.
121  *
122  * Revision 1.24  2009/01/26 07:31:24  dick
123  * Sort the dice high to low.
124  *
125  * Revision 1.23  2009/01/24 17:04:21  dick
126  * When parsing the board, i tried to normalize the data so that the player was always playing 24-1.
127  * That didn't really work out, great for watching, tough for playing.
128  * So get rid of it.
129  * Also, lots of javadoc.
130  *
131  * Revision 1.22  2009/01/22 05:01:26  dick
132  * add getXO().
133  *
134  * Revision 1.21  2009/01/20 07:41:54  dick
135  * Send a string to the parser to set the initial positions.
136  *
137  * Revision 1.20  2009/01/18 05:26:24  dick
138  * Javadoc.
139  *
140  * Revision 1.19  2009/01/18 04:43:41  dick
141  * Javadoc.
142  *
143  * Revision 1.18  2009/01/10 05:20:36  dick
144  * Turn off DEBUG.
145  *
146  * Revision 1.17  2009/01/10 05:02:27  dick
147  * Totally cleanup who is who.  I parse the board so that You is always Player0 and playing 24 to 1.
148  * Get rid of unneeded setters.  Only parseFibsBoard can set attributes.
149  *
150  * Revision 1.16  2009/01/09 06:56:07  dick
151  * Change whosTurn parsing.
152  * Turn off DEBUG.
153  *
154  * Revision 1.15  2009/01/08 18:25:26  dick
155  * Add getMatchLength
156  *
157  * Revision 1.14  2009/01/08 01:28:13  dick
158  * getPlayerName returns the list of players in this match.
159  *
160  * Revision 1.13  2009/01/06 08:05:07  dick
161  * Javadoc.
162  *
163  * Revision 1.12  2008/12/20 23:01:39  dick
164  * Support for Own Info.
165  *
166  * Revision 1.11  2008/12/17 04:37:11  dick
167  * Add the direction that the user is playing in.
168  *
169  * Revision 1.10  2008/12/13 06:15:33  dick
170  * Parse home and the bar.
171  *
172  * Revision 1.9  2008/12/12 14:44:22  dick
173  * Fibs board parsing.
174  *
175  * Revision 1.8  2008/12/12 01:19:52  dick
176  * Start reworking for a point based board,  not a checker based board.
177  *
178  * Revision 1.7  2008/12/11 20:24:23  dick
179  * Early parsing of FIBS board.
180  *
181  * Revision 1.6  2008/12/10 21:55:14  dick
182  * Add dice attributes.
183  *
184  * Revision 1.5  2008/12/09 01:47:05  dick
185  * Define WHITE and BLACK.
186  *
187  * Revision 1.4  2008/12/08 10:16:31  dick
188  * Add setStartPositions().
189  *
190  * Revision 1.3  2008/12/08 06:44:07  dick
191  * checkers is an array of int.
192  *
193  * Revision 1.2  2008/03/30 05:38:51  dick
194  * More skeleton checkins.
195  *
196  * Revision 1.1  2008/03/29 08:57:43  dick
197  * BuckoFIBS skeleton checkin.
198  */
199 
200 /* 
201  * This program is free software: you can redistribute it and/or modify
202  * it under the terms of the GNU General Public License as published by
203  * the Free Software Foundation, either version 3 of the License, or
204  * (at your option) any later version.
205  *
206  * This program is distributed in the hope that it will be useful,
207  * but WITHOUT ANY WARRANTY; without even the implied warranty of
208  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
209  * GNU General Public License for more details.
210  *
211  * You should have received a copy of the GNU General Public License
212  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
213  *
214  * The Original Code is BuckoFIBS, <http://www.buckosoft.com/BuckoFIBS/>.
215  * The Initial Developer of the Original Code is Dick Balaska and BuckoSoft, Corp.
216  * 
217  */
218 package com.buckosoft.fibs.domain;
219 
220 
221 
222 /** Define a backgammon board. 
223  * This object parses the fibs board command and returns various attributes from the parse.
224  * @author Dick Balaska
225  * @since 2008/03/29
226  * @version $Revision$ <br> $Date$
227  * @see <a href="http://cvs.buckosoft.com/Projects/BuckoFIBS/BuckoFIBS/src/main/java/com/buckosoft/fibs/domain/Board.java">cvs Board.java</a>
228  * @see <a href="http://www.fibs.com/fibs_interface.html#board_state" target="_top">FIBS Client Protocol Detailed Specification</a>
229  */
230 public class Board implements Cloneable {
231 	private final static boolean DEBUG = false;
232 
233 	private int canMove;
234 	
235 
236 	private	int	xo;
237 	private int matchLength = 0;
238 	private	int matchScore[] = new int[2];
239 	private	static String	initialPositions = "board:Player0:Player1:3:0:0:0:-2:0:0:0:0:5:0:3:0:0:0:-5:5:0:0:0:-3:0:-5:0:0:0:0:2:0:1:0:0:0:0:1:1:1:0:1:-1:0:25:0:0:0:0:2:0:0:0";
240 //	private	boolean	gameOver = true;
241 	private	int[][] dice = new int[2][2];
242 	private	int direction;
243 	private	String[] playerName = new String[2];
244 	private int[] points = new int[26];		// 0 and 25 are unused.  See bar
245 	private int[] bar = new int[2];
246 	private int[] home = new int [2];
247 	private int[] pipCount = new int[2];
248 
249 	/** The player playing the 'O' pieces.  The value is 0. */
250 	public final static int O = 0;
251 	/** The player playing the 'X' pieces.  The value is 1. */
252 	public final static int X = 1;
253 	/** X's turn is marked with -1 */
254 	public final static int turnX = -1;
255 	/** O's turn is marked with 1 */
256 	public final static int turnO =  1;
257 
258 	/** We don't know if it is player O or player X */
259 	public final static int XOnot = -2;
260 	/** When dealing with pointArrays, the special value Home is 0 */
261 	public final static int Home = 0;
262 	/** When dealing with pointArrays, the special value Bar is 25 */ 
263 	public final static int Bar = 25;
264 	
265 	/** Convert {@link Board#X} to {@link Board#turnX} and {@link Board#O} to {@link Board#turnO}.
266 	 * @param xo The board player.
267 	 * @return The turn.
268 	 */
269 	public static int xoToTurn(int xo) {
270 		return (xo == Board.X ? Board.turnX : Board.turnO);
271 	}
272 
273 	
274 	private	int whosTurn = 0;
275 	private	int	cube = 1;
276 
277 	private	boolean	sortDice = true;
278 
279 	/** Who has the doubling cube?<br>
280 	 * -1 = noone, X = X, O = O */
281 	private	int	hasCube = 0;
282 	private	int[] mayDouble = new int[2];
283 	private boolean[] wasDoubled = new boolean[2];
284 	
285 
286 	/* "External" attributes.  That is, not derived by parseBoard */
287 	
288 	private	boolean	yourTurnToRollOrDouble = false;
289 	private boolean acceptDeclineResign = false;
290 	private	int		whoIsResigning = -1;
291 	private int		resigningPoints = -1;
292 
293 	/** Create an empty board */
294 	public Board() { }
295 
296 	/** Clone this board
297 	 * @return A new copy of this board.
298 	 */
299 	public Board clone() {
300 		Board b = new Board();
301 		b.xo = this.xo;
302 		b.matchLength = this.matchLength;
303 		b.matchScore[0] = this.matchScore[0];
304 		b.matchScore[1] = this.matchScore[1];
305 		b.dice[0][0] = this.dice[0][0];
306 		b.dice[0][1] = this.dice[0][1];
307 		b.dice[1][0] = this.dice[1][0];
308 		b.dice[1][1] = this.dice[1][1];
309 		b.direction = this.direction;
310 		b.playerName[0] = this.playerName[0];
311 		b.playerName[1] = this.playerName[1];
312 		for (int i=0; i<26; i++)
313 			b.points[i] = this.points[i];
314 		b.bar[0] = this.bar[0];
315 		b.bar[1] = this.bar[1];
316 		b.home[0] = this.home[0];
317 		b.home[1] = this.home[1];
318 		b.whosTurn = this.whosTurn;
319 		b.cube = this.cube;
320 		b.sortDice = this.sortDice;
321 		b.hasCube = this.hasCube;
322 		b.mayDouble[0] = this.mayDouble[0];
323 		b.mayDouble[1] = this.mayDouble[1];
324 		b.wasDoubled[0] = this.wasDoubled[0];
325 		b.wasDoubled[1] = this.wasDoubled[1];
326 		b.yourTurnToRollOrDouble = this.yourTurnToRollOrDouble;
327 		b.acceptDeclineResign = this.acceptDeclineResign;
328 		b.whoIsResigning = this.whoIsResigning;
329 		b.resigningPoints = this.resigningPoints;
330 		return(b);
331 	}
332 	
333 	/** Set the flag saying we want sorted dice or not
334 	 * @param sortDice true = sort the dice, false = deal with them as received
335 	 */
336 	public void setSortDice(boolean sortDice) {
337 		this.sortDice = sortDice;
338 		if (sortDice) {
339 			if (this.dice[0][0] < this.dice[0][1]) {
340 				int x = dice[0][0];
341 				dice[0][0] = dice[0][1];
342 				dice[0][1] = x;
343 			}
344 			if (this.dice[1][0] < this.dice[1][1]) {
345 				int x = dice[1][0];
346 				dice[1][0] = dice[1][1];
347 				dice[1][1] = x;
348 			}
349 		}
350 	}
351 
352 	/** Is it your turn?
353 	 * @return the yourTurnToRollOrDouble
354 	 */
355 	public boolean isYourTurnToRollOrDouble() {
356 		return yourTurnToRollOrDouble;
357 	}
358 
359 	/** Set your turn to roll or double
360 	 * @param yourTurnToRollOrDouble the yourTurnToRollOrDouble to set
361 	 */
362 	public void setYourTurnToRollOrDouble(boolean yourTurnToRollOrDouble) {
363 		this.yourTurnToRollOrDouble = yourTurnToRollOrDouble;
364 	}
365 
366 	/** We have been doubled and need to accept or decline
367 	 */
368 	public void setAcceptDeclineDouble() {
369 		this.getWasDoubled()[1] = true;
370 	}
371 
372 	/** Are you in a state where you are required to accept or decline a double?
373 	 * @return true = opponent has doubled
374 	 */
375 	public boolean isAcceptDeclineDouble() {
376 		return(this.getWasDoubled()[1]);
377 	}
378 
379 	/** Are you in a state where you are required to accept or decline a resign?
380 	 * @return true = opponent has offered to resign
381 	 */
382 	public boolean isAcceptDeclineResign() {
383 		return(this.acceptDeclineResign);
384 	}
385 
386 	public void setAcceptDeclineResign(boolean enabled) {
387 		this.acceptDeclineResign = enabled;
388 	}
389 
390 	/** Someone wants to resign, this is the player
391 	 * @param xo Board.X or Board.O wants to resign
392 	 */
393 	public void setWhoIsResigning(int xo) {
394 		this.whoIsResigning = xo;
395 	}
396 
397 	public int	getWhoIsResigning() {
398 		return(this.whoIsResigning);
399 	}
400 
401 	public void setResigningPoints(int resigningPoints) {
402 		this.resigningPoints = resigningPoints;
403 	}
404 	
405 	public int getResigningPoints() {
406 		return(this.resigningPoints);
407 	}
408 
409 	/** Fetch the points array, the checkers on the board.
410 	 * 1-24 are used. 0 and 25 are ununsed (see home and bar).
411 	 * @return The points array.
412 	 */
413 	public int[] getPoints() {
414 		return(points);
415 	}
416 
417 	/** Get the number of checkers on the bar for both players.
418 	 * @return The bar
419 	 */
420 	public int[] getBar() {
421 		return(bar);
422 	}
423 
424 	/** Get the number of checkers in both player's homes.
425 	 * @return The home array
426 	 */
427 	public int[] getHome() {
428 		return(home);
429 	}
430 
431 	/** Is there a pending double on the table?
432 	 * @return an array of wasDoubled
433 	 */
434 	public boolean[] getWasDoubled() {
435 		return(this.wasDoubled);
436 	}
437 
438 	/** Is there a pending double on the table?
439 	 * @param xo {@link Board#X} or {@link Board#O}
440 	 */
441 	public void setWasDoubled(int xo) {
442 		wasDoubled[Board.O] = false;
443 		wasDoubled[Board.X] = false;
444 		if (xo == Board.O)
445 			wasDoubled[Board.O] = true;
446 		if (xo == Board.X)
447 			wasDoubled[Board.X] = true; 
448 	}
449 
450 	/** Are You allowed to double?
451 	 * @return true is yes.
452 	 */
453 	public boolean isYouMayDouble() {
454 		return (this.mayDouble[Board.O] == 1);
455 	}
456 
457 	public boolean isOpponentMayDouble() {
458 		return (this.mayDouble[Board.X] == 1);
459 		
460 	}
461 	/** Are you playing or just watching?
462 	 * @return true if playing
463 	 */ 
464 	public boolean isYouPlaying() {
465 		return(this.playerName[0].equals("You"));
466 	}
467 
468 	/** Is it your turn to move?  That is, have you rolled and should move checkers?
469 	 * @return whether there is valid dice on the table.
470 	 */
471 	public boolean isYourMove() {
472 		return(dice[0][0] != 0);
473 	}
474 
475 	/** Get the list of player names who are playing this game.
476 	 * @return The player Names
477 	 */
478 	public String[] getPlayerName() {
479 		return(playerName);
480 	}
481 
482 	/** Set the value of one of the playerNames.
483 	 * @param which Which player to set {@link Board#X} or {@link Board#O}
484 	 * @param name The name of the player.
485 	 */
486 	public void setPlayerName(int which, String name) {
487 		this.playerName[which] = name;
488 	}
489 
490 	/** Get the number of points in the match
491 	 * @return The matchLength
492 	 */
493 	public int	getMatchLength() {
494 		return(matchLength);
495 	}
496 
497 	/** Get the score for both players in this match
498 	 * @return the score array
499 	 */
500 	public int[] getMatchScore() {
501 		return(matchScore);
502 	}
503 	
504 	/** Place all checkers on their start positions
505 	 */
506 	public void setStartPositions() {
507 		this.parseFibsBoard(initialPositions);
508 	}
509 
510 	/** Get whether you are playing as X or O
511 	 * @return -1 if you are X,  1 if you are O <br>({@link Board#turnX} or {@link Board#turnO})
512 	 */
513 	public int	getXO() {
514 		return(xo);
515 	}
516 
517 	/** Get XO as text. Just a devel function
518 	 * @return "O" or "X"
519 	 */
520 	public String getXOAsText() {
521 		return(xo == Board.O ? "O" : "X");
522 	}
523 	
524 	/** Get XO as text. Just a devel function
525 	 * @return "O" or "X"
526 	 */
527 	public static String getXOAsText(int xo) {
528 		return(xo == Board.O ? "O" : "X");
529 	}
530 	
531 	/** Get turnXO as text. Just a devel function
532 	 * @return "O" or "X"
533 	 */
534 	public static String getTurnAsText(int turn) {
535 		return(turn == Board.turnO ? "turnO" : "turnX");
536 	}
537 	
538 	/** When you pick up the dice, 0 them out so there is a visual cue.
539 	 * Sometimes it takes fibs a while to send a new board. 
540 	 */
541 	public void clearDice() {
542 		this.dice[0][0] = 0;
543 		this.dice[0][1] = 0;
544 	}
545 
546 	/** Get who's turn it is.  -1 = X, 1 = O, 0 = game over
547 	 * @return the whosTurn {@link Board#turnX} or{@link Board#turnO}
548 	 */
549 	public int getWhosTurn() {
550 		return whosTurn;
551 	}
552 	
553 	/** Given a playerName, return whether he is playing {@link Board#X} or {@link Board#O} 
554 	 * @param name The player's name to check
555 	 * @return Board.X or Board.O for a match, {@link Board#XOnot} for non-match
556 	 */
557 	public int	getXOFromName(String name) {
558 		if (name.equals(playerName[Board.X]))
559 			return(Board.X);
560 		else if (name.equals(playerName[Board.O]))
561 			return(Board.O);
562 		return(XOnot);
563 	}
564 	
565 	/** Get the playing direction for this player
566 	 * @param name The player name to check
567 	 * @return -1 or 1
568 	 */
569 	public int	getDirectionFromName(String name) {
570 		if (name.equals(playerName[Board.O]))
571 			return(direction);
572 		return(-direction);
573 	}
574 
575 	/** Get the number displayed on the double cube
576 	 * @return the cube
577 	 */
578 	public int getCube() {
579 		return cube;
580 	}
581 
582 	/** Who has the doubling cube?
583 	 * -1 = noone, X = X, O = O 
584 	 * @return who has the cube
585 	 */
586 	public int getHasCube() {
587 		return hasCube;
588 	}
589 
590 	/** -1 If you play from position 24 to position 1.<br>
591 	 *   1 If you play from position 1 to position 24.
592 	 * @return the direction
593 	 */
594 	public int getDirection() {
595 		return direction;
596 	}
597 
598 	/** Get the 2x2 array of both player's both dice
599 	 * @return the dice
600 	 */
601 	public int[][] getDice() {
602 		return dice;
603 	}
604 
605 	/** Return the number of pieces the player can move this turn.
606 	 * @return The canMove from this board.
607 	 */
608 	public int getCanMove() {
609 		return(canMove);
610 	}
611 
612 	/** Handle the '* wins the match' message. <br>
613 	 * Fibs doesn't send a final board, which should have the final score.
614 	 * So we have to derive the match over scenario.
615 	 */
616 	public void onMatchOver(String winner, String score) {
617 		String[] ss = score.split("\\-");
618 		int s0 = Integer.parseInt(ss[0]);
619 		int s1 = Integer.parseInt(ss[1]);
620 		if (winner.equals("You") || winner.equals(this.playerName[0])) {
621 			matchScore[0] = s0;
622 			matchScore[1] = s1;
623 		} else {
624 			matchScore[0] = s1;
625 			matchScore[1] = s0;
626 		}
627 		whosTurn = 0;
628 	}
629 
630 	/** Calculate and return the number of pips for both players.
631 	 * Used by the {@link com.buckosoft.fibs.BuckoFIBS.gui.boardTab.MatchStatusPanel}.
632 	 * @return A reference to our local pipCount (reuse object).
633 	 */
634 	public int[] getPipCount() {
635 		int i;
636 		this.pipCount[O] = 0;
637 		this.pipCount[X] = 0;
638 		for (i=1; i<=24; i++) {
639 			if (this.points[i] < 0)
640 				pipCount[O] += ((this.getDirection() == -1 ? i : (25 - i)) * -this.points[i]);
641 			else if (this.points[i] > 0)
642 				pipCount[X] += ((this.getDirection() == 1 ? i : (25 - i)) * this.points[i]);
643 		}
644 		pipCount[O] += (bar[O]*25);
645 		pipCount[X] += (bar[X]*25);
646 		
647 		return(this.pipCount);
648 	}
649 
650 	/** Is this game a race?
651 	 * Determine whether all of your checkers are past the opponent's checkers
652 	 * @return true if this game has turned into a race.
653 	 */
654 	public boolean isRace() {
655 		int i;
656 		int k = 0;
657 		if (bar[O] > 0 || bar[X] > 0)
658 			return(false);
659 		boolean oppositeSeen = false;
660 		for (i=1; i<=24; i++) {
661 			if (this.points[i] == 0)
662 				continue;
663 			if (k == 0) {
664 				k = this.points[i];
665 				continue;
666 			}
667 			if (!oppositeSeen) {
668 				if (k < 0 && this.points[i] > 0) {
669 					oppositeSeen = true;
670 					continue;
671 				}
672 				if (k > 0 && this.points[i] < 0) {
673 					oppositeSeen = true;
674 					continue;
675 				}
676 			} else {
677 				if (k < 0 && this.points[i] < 0)
678 					return(false);
679 				if (k > 0 && this.points[i] > 0)
680 					return(false);
681 			}
682 		}
683 		return(true);
684 	}
685 	// positions of the fields in a board line
686 	private final static int YOU = 1;
687 	private final static int SOMEPLAYER = 2;
688 	private final static int MATCHLENGTH = 3;
689 	private final static int CURRENTSCORES = 4;
690 	private final static int BOARD = 6;
691 	private final static int TURN = 32;
692 	private final static int DICE = 33;
693 	private final static int CUBE = 37;
694 	private final static int MAYDOUBLE = 38;
695 //	private final static int WASDOUBLED = 40;
696 	private final static int XO = 41;
697 	private final static int DIRECTION = 42;
698 	private final static int ONHOME = 45;
699 	private final static int ONBAR = 47;
700 	private final static int CANMOVE = 49;
701 
702 	/** Parse the board state from Fibs.
703 	 * Opening board looks like this:<br>
704 	 * board:You:someplayer:3:0:0:0:-2:0:0:0:0:5:0:3:0:0:0:-5:5:0:0:0:-3:0:-5:0:0:0:0:2:0:1:6:2:0:0:1:1:1:0:1:-1:0:25:0:0:0:0:2:0:0:0
705 	 * @param s The board
706 	 * @see <a href="http://www.fibs.com/fibs_interface.html#board_state" target="_top">FIBS Client Protocol Detailed Specification</a>
707 	 * <pre>
708 	 * 0                                   1                    2                     3                   4                     5
709 	 * 0     1   2          3 4 5 6 7  8 9 0 1 2 3 4 5 6 7 8  9 0 1 2 3  4 5  6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2  3 4  5 6 7 8 9 0 1 2 
710 	 * board:You:someplayer:3:0:0:0:-2:0:0:0:0:5:0:3:0:0:0:-5:5:0:0:0:-3:0:-5:0:0:0:0:2:0:1:6:2:0:0:1:1:1:0:1:-1:0:25:0:0:0:0:2:0:0:0
711 	 * </pre>
712 	 */
713 	public void parseFibsBoard(String s) {
714 		int i;
715 		String[] t = s.split(":");
716 		xo = Integer.parseInt(t[XO]);
717 		direction = Integer.parseInt(t[DIRECTION]);
718 		playerName[0] = t[YOU];
719 		playerName[1] = t[SOMEPLAYER];
720 		matchLength = Integer.parseInt(t[MATCHLENGTH]);
721 		matchScore[0] = Integer.parseInt(t[CURRENTSCORES+0]);
722 		matchScore[1] = Integer.parseInt(t[CURRENTSCORES+1]);
723 		for (i=1; i<=24; i++) {
724 			this.points[i] = Integer.parseInt(t[BOARD+i]) * -xo;
725 		}
726 		this.whosTurn = Integer.parseInt(t[TURN]);
727 		setDice(dice[O], Integer.parseInt(t[DICE+0]), Integer.parseInt(t[DICE+1]));
728 		setDice(dice[X], Integer.parseInt(t[DICE+2]), Integer.parseInt(t[DICE+3]));
729 		cube = Integer.parseInt(t[CUBE]);
730 		mayDouble[0] = Integer.parseInt(t[MAYDOUBLE+0]);
731 		mayDouble[1] = Integer.parseInt(t[MAYDOUBLE+1]);
732 //		wasDoubled[1] = t[WASDOUBLED].equals("1") ? true : false;
733 		if (DEBUG)
734 			System.out.println("mayDouble[" + mayDouble[0] + "][" + mayDouble[1] + "]");
735 		if (mayDouble[0] == mayDouble[1])
736 			hasCube = -1;
737 		else if (mayDouble[0] == 1)
738 			hasCube = X;
739 		else if (mayDouble[1] == 1)
740 			hasCube = O;
741 		home[O] = Integer.parseInt(t[ONHOME+0]);
742 		home[X] = Integer.parseInt(t[ONHOME+1]);
743 		bar[O] = Integer.parseInt(t[ONBAR+0]);
744 		bar[X] = Integer.parseInt(t[ONBAR+1]);
745 		canMove = Integer.parseInt(t[CANMOVE]);
746 		if (DEBUG)
747 			System.out.println("xo=" + xo + " direction=" + direction + " canMove=" + canMove
748 					+ " wasDoubled[1]=" + wasDoubled[1] + " turn=" + this.whosTurn);
749 	}
750 
751 	/** Parse a board for debug analysis.
752 	 * Basically this includes points[0] and points[25] which we usually ignore.
753 	 * @param s The board string
754 	 * @param debugMode If true then actually parse. 
755 	 */
756 	public void parseFibsBoard(String s, boolean debugMode) {
757 		if (debugMode) {
758 			parseFibsBoard(s);
759 			String[] t = s.split(":");
760 			this.points[0] = Integer.parseInt(t[BOARD]);
761 			this.points[25] = Integer.parseInt(t[BOARD+25]);
762 		}
763 	}
764 
765 	/** Sort the dice and set them in the player's dice array
766 	 * @param d The dice array to store in.
767 	 * @param d0 value of die 0
768 	 * @param d1 value of die 1
769 	 */
770 	private void setDice(int[]d, int d0, int d1) {
771 		d[0] = d0;
772 		d[1] = d1;
773 		if (sortDice && d1 > d0) {
774 			d[0] = d1;
775 			d[1] = d0;
776 		}
777 	}
778 
779 }