package openingBook;
import java.io.IOException;
import java.io.InputStream;
/**
* There are 3 different opning-books available:
* 1. Opening book with all positions with 8 pieces (win/draw/loss)
* 2. Opening book with all positions with 12 pieces (win/draw/loss)
* 3. Opening book with all positions with 12 pieces (win/draw/loss with
* exact distance)
*
* One of these books can be selected by setting the bookNr to 0,1 or 2.
*
* @author Markus Thill
*/
public class Book {
// Constants
private static final String BOOKPATH[] = { "book.dat", "bookDeep.dat",
"bookDeepDist.dat" };
private static final int BOOKSIZE[] = { 34286, 1735945, 4200899 };
private static final int STONENUM[] = { 8, 12, 12 };
private static final int MASKPOSITION = 0xFFFFFFFC;
private static final int MASKVALUE = 0x3;
private static final long MSBINT = 0x80000000L;
public static final int NORMALBOOK = 0;
public static final int DEEPBOOK = 1;
public static final int DISTDEEPBOOK = 2;
// Selected book-Nr
private int bookNr;
// Input-stream for reading the book
private InputStream file = null;
// All rows of the opening-book. Each row is coded in a special format
// (exact 24- or 32-Bit)
private int book[];
// Only for Deep-book with Exact Distance
byte vals[];
/**
* @param bookNr
* Selected book
*/
public Book(int bookNr) {
this.bookNr = bookNr;
}
/**
* Open the selected book from the selected path
*
* @throws IOException
*/
public void openBook() throws IOException {
file = getClass().getResourceAsStream(BOOKPATH[bookNr]);
if (file == null)
throw (new IOException("Could not open File"));
}
/**
* Close the selected book
*
* @throws IOException
*/
public void closeBook() throws IOException {
file.close();
}
/**
* Read the book from the HDD and save in the RAM.
*
* @throws IOException
*/
public void readBook() throws IOException {
book = new int[BOOKSIZE[bookNr]];
if (bookNr == DISTDEEPBOOK)
vals = new byte[BOOKSIZE[bookNr]];
int shiftNum, temp;
for (int i = 0; i < BOOKSIZE[bookNr]; i++) {
shiftNum = (bookNr == NORMALBOOK ? 16 : 24);
temp = 0;
for (; shiftNum >= 0; shiftNum -= 8) {
int b = file.read();
temp |= (b << shiftNum);
}
book[i] = temp;
if (bookNr == DISTDEEPBOOK) {
byte b = (byte) file.read();
vals[i] = b;
}
}
}
/**
* Search in the opening book for the coded board and return the value for
* this board. A fast binary-search is used.
*
* @param codedPos
* Position coded in an Integer (see class ConnectFour for
* details)
* @param codedPosMirrored
* Mirrored Position coded in an Integer (see class ConnectFour
* for details)
* @return Game-Theoretic Value for this board
*/
public int getValue(int codedPos, int codedPosMirrored) {
int code = 0, code2 = 0, pos, pos2, step;
pos = pos2 = step = BOOKSIZE[bookNr] - 1;
// Binary Search
while (step > 0) {
step = (step != 1 ? (step + (step & 1)) >> 1 : 0);
if (pos < BOOKSIZE[bookNr] && pos >= 0)
code = book[pos] & MASKPOSITION;
if (pos2 < BOOKSIZE[bookNr] && pos2 >= 0)
code2 = book[pos2] & MASKPOSITION;
if (codedPos < code)
pos -= step;
else if (codedPos > code)
pos += step;
else if (codedPos == code)
if (bookNr != DISTDEEPBOOK)
return (book[pos] & MASKVALUE);
else
return vals[pos];
if (codedPosMirrored < code2)
pos2 -= step;
else if (codedPosMirrored > code2)
pos2 += step;
else if (codedPosMirrored == code2)
if (bookNr != DISTDEEPBOOK)
return (book[pos2] & MASKVALUE);
else
return vals[pos2];
}
return 2; //Value was not found in database, must be a win for X
}
/**
* Get a Board and its value at an specified index of this opening-book
*
* @param index
* Position in the opening-book
* @param board
* Return-Value: Contains the board
* @return Value for the board
*/
public int getBoard(int index, int board[][]) {
int hCode = book[index];
int col = 0, row = 0;
long b1 = 0, b2 = 0;
if (board == null)
board = new int[7][6];
if (bookNr == NORMALBOOK)
hCode <<= 8; // Move to Front of Integer
for (int i = 0; i < STONENUM[bookNr] + 6; i++) {
b1 = hCode & MSBINT;
hCode <<= 1;
// Column is Full
if (b1 == 0L) {
col++;
row = 0;
continue;
}
b2 = hCode & MSBINT;
hCode <<= 1;
if (b2 != 0L)
board[col][row++] = 2;
else
board[col][row++] = 1;
}
if (bookNr != DISTDEEPBOOK)
return book[index] & MASKVALUE;
return vals[index];
}
/**
* @return Size of the opening-book in bytes
*/
public int getBookSize() {
return BOOKSIZE[bookNr];
}
}