// Game of Fanorona // David Eppstein, UC Irvine, 11 Jun 1997 // // Keep track of the moves of the game import java.util.*; import java.awt.*; import gui.*; class MoveLog extends TextPane { Game game; int moveNumber; // initialize MoveLog(Game g) { game = g; showMoves(game); } // make TextArea look like List // synchronized public void addItem(String s) { // appendText(s + System.getProperty("line.separator")); // } // public void clear() { setText(""); } // public boolean isEditable() { return true; } // show who is about to play void showPlayer(Board b, boolean verbose) { if (b.gameOver()) { if (!verbose) { addItem(showMoveBuffer.toString()); showMoveBuffer.setLength(0); } if (b.whiteWins()) showMoveBuffer.append("White"); else showMoveBuffer.append("Black"); showMoveBuffer.append(" wins with ").append( Bits.count((b.myPieces | b.opponentPieces) & Bits.ON_BOARD)).append(" pieces"); if (verbose) addItem(showMoveBuffer.toString()); return; } if (!verbose) { if (b.whiteToMove() != game.getParameter(Options.WHITE_GOES_FIRST)) return; if (moveNumber != 0) addItem(showMoveBuffer.toString()); showMoveBuffer.setLength(0); moveNumber++; showMoveBuffer.append(moveNumber).append("."); return; } String s; if (b.previousPosition != null) addItem(""); // blank line to separate from prev move showMoveBuffer.setLength(0); if (b.whiteToMove() == game.getParameter(Options.WHITE_GOES_FIRST)) { moveNumber++; showMoveBuffer.append(moveNumber).append(". "); if (moveNumber < 10) showMoveBuffer.append(" "); // extra blank to line up #s } else showMoveBuffer.append(" "); if (b.whiteToMove()) showMoveBuffer.append("White"); else showMoveBuffer.append("Black"); if (game.humanToMove(b)) showMoveBuffer.append(" (Human):"); else showMoveBuffer.append(" (Computer):"); addItem(showMoveBuffer.toString()); } // find position number (in Fox's notation) of given bit static final int bitNumbers[] = makeBitNumbers(); static final int[] makeBitNumbers() { int[] a = new int[65]; for (int i = 0; i < 65; i++) a[i] = -1; for (int i = 0; i < 5; i++) for (int j = 0; j < 9; j++) { long x = Bits.at(i,j); a[Bits.count(x ^ (x-1))] = 9*i+j+1; } return a; } static int bitNumber(long bit) { int n = bitNumbers[Bits.count(bit ^ (bit-1))]; if (n >= 0) return n; throw new IllegalArgumentException("Move log: can't find position of bit 0x" + Long.toString(bit,16)); } static char files[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' }; static void putPos(StringBuffer buffer, int bitNo, boolean alg) { if (alg) { bitNo--; // make zero-based buffer.append(files[bitNo % 9]).append(5-(bitNo/9)); } else buffer.append(bitNo); } // make string for move itself, append to given buffer static void stringForMove(StringBuffer buffer, Board b, boolean alg, boolean verbose, boolean firstMove) { if (b.wasPass()) { if (firstMove) buffer.append("pass"); return; } Board prev = b.previousPosition; long occupied = b.myPieces | b.opponentPieces; long captures = prev.opponentPieces & ~occupied & Bits.ON_BOARD; long from = prev.myPieces & ~occupied & Bits.ON_BOARD; long to = occupied & ~prev.myPieces & ~prev.opponentPieces & Bits.ON_BOARD; if ((to & (to - 1)) != 0 || (from & (from - 1)) != 0) { // bogus pv buffer.append(Long.toString(from | to | captures, 16)); // at least avoid crashing return; } if (!verbose) { if (!firstMove && (!prev.midCapture())) { buffer.append(" "); firstMove = true; } if (firstMove) putPos(buffer,bitNumber(from),alg); if (captures == 0) buffer.append("-"); else { long nearStart = from; nearStart |= (nearStart << Bits.SHIFT_VERTICAL) | (nearStart >>> Bits.SHIFT_VERTICAL); nearStart |= (nearStart << Bits.SHIFT_HORIZONTAL) | (nearStart >>> Bits.SHIFT_HORIZONTAL); if ((nearStart & captures) != 0) buffer.append("<"); else buffer.append(">"); } putPos(buffer,bitNumber(to),alg); } else { putPos(buffer,bitNumber(from),alg); buffer.append("-"); putPos(buffer,bitNumber(to),alg); if (captures != 0) { buffer.append(" x "); boolean firstCapture = true; String cap = null; while (captures != 0) { if (!firstCapture) buffer.append(", "); firstCapture = false; long bit = Bits.lastBit(captures); putPos(buffer,bitNumber(bit),alg); captures &=~ bit; } } } } // set up move log to end at the given move static StringBuffer showMoveBuffer = new StringBuffer(); void showMove(Board b,boolean alg,boolean verbose) { boolean firstMove = false; if (b.previousPosition == null) { clear(); // no move, don't show anything showMoveBuffer.setLength(0); moveNumber = 0; showPlayer(b,verbose); // other than who is to move } else { showMove(b.previousPosition,alg,verbose); if (!verbose) stringForMove(showMoveBuffer,b,alg,verbose,false); else if (!b.wasPass()) { showMoveBuffer.setLength(0); showMoveBuffer.append(" "); stringForMove(showMoveBuffer,b,alg,verbose,false); addItem(showMoveBuffer.toString()); } if (!b.midCapture()) showPlayer(b,verbose); } } void showMoves(Game game) { boolean verbose = game.getParameter(Options.NOTATION_LONG); showMove(game.getBoard(),game.getParameter(Options.NOTATION_ALGEBRAIC),verbose); if (!verbose) addItem(showMoveBuffer.toString()); } // gross hack to interface with TabPanel public boolean postEvent(Event e) { if (e.id == Event.WINDOW_EXPOSE) showMoves(game); return super.postEvent(e); } }