/*
CuckooChess - A java chess program.
Copyright (C) 2011 Peter Ă–sterlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package tui;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import uci.UCIProtocol;
import chess.ChessParseError;
import chess.ComputerPlayer;
import chess.Evaluate;
import chess.Game;
import chess.Move;
import chess.Player;
import chess.Position;
import chess.TextIO;
import chess.TwoReturnValues;
public class TUIGame extends Game {
public TUIGame(Player whitePlayer, Player blackPlayer) {
super(whitePlayer, blackPlayer);
}
protected boolean handleCommand(String moveStr) {
if (super.handleCommand(moveStr))
return true;
if (moveStr.startsWith("testsuite ")) {
String testSuiteCmd = moveStr.substring(moveStr.indexOf(" ") + 1);
return handleTestSuite(testSuiteCmd);
} else if (moveStr.equals("uci")) {
whitePlayer = null;
blackPlayer = null;
UCIProtocol.main(true);
System.exit(0);
return false;
} else if (moveStr.equals("help")) {
showHelp();
return true;
}
return false;
}
private void showHelp() {
System.out.println("Enter a move, or one of the following special commands:");
System.out.println(" new - Start a new game");
System.out.println(" undo - Undo last half-move");
System.out.println(" redo - Redo next half-move");
System.out.println(" swap - Swap sides");
System.out.println(" go - Same as swap");
System.out.println(" list - List all moves in current game");
System.out.println(" setpos FEN - Set a position using a FEN string");
System.out.println(" getpos - Print current position in FEN notation");
System.out.println(" draw rep [move] - Claim draw by repetition");
System.out.println(" draw 50 [move] - Claim draw by 50-move rule");
System.out.println(" draw offer move - Play move and offer draw");
System.out.println(" draw accept - Accept a draw offer");
System.out.println(" resign - Resign the current game");
System.out.println(" testsuite filename maxtime");
System.out.println(" book on|off - Turn opening book on/off");
System.out.println(" time t - Set computer thinking time, ms");
System.out.println(" perft d - Run perft test to depth d");
System.out.println(" uci - Switch to uci protocol.");
System.out.println(" help - Show this help");
System.out.println(" quit - Terminate program");
}
private boolean handleTestSuite(String cmd) {
LineNumberReader fr = null;
try {
int idx = cmd.indexOf(" ");
String filename = cmd.substring(0, idx);
String timeStr = cmd.substring(idx + 1, cmd.length());
int timeLimit = Integer.parseInt(timeStr);
// System.out.printf("file:%s time:%s (%d)\n", filename, timeStr, timeLimit);
fr = new LineNumberReader(new FileReader(filename));
String line;
Player pl = whitePlayer.isHumanPlayer() ? blackPlayer : whitePlayer;
if (pl.isHumanPlayer()) {
System.out.printf("No computer player available");
return false;
}
ComputerPlayer cp = (ComputerPlayer)pl;
int numRight = 0;
int numTotal = 0;
while ((line = fr.readLine()) != null) {
if (line.startsWith("#") || (line.length() == 0)) {
continue;
}
int idx1 = line.indexOf(" bm ");
String fen = line.substring(0, idx1);
int idx2 = line.indexOf(";", idx1);
String bm = line.substring(idx1 + 4, idx2);
// System.out.printf("Line %3d: fen:%s bm:%s\n", fr.getLineNumber(), fen, bm);
Position testPos = TextIO.readFEN(fen);
cp.clearTT();
TwoReturnValues<Move, String> ret = cp.searchPosition(testPos, timeLimit);
Move sm = ret.first;
String PV = ret.second;
Move m = new Move(sm);
String[] answers = bm.split(" ");
boolean correct = false;
for (String a : answers) {
Move am = TextIO.stringToMove(testPos, a);
if (am == null) {
throw new ChessParseError("Invalid move " + a);
}
if (am.equals(m)) {
correct = true;
break;
}
}
if (correct) {
numRight++;
}
numTotal++;
System.out.printf("%3d : %6s %6d %d %03d/%03d %s : %s\n", fr.getLineNumber(),
TextIO.moveToString(testPos, sm, false), sm.score, correct ? 1 : 0,
numRight, numTotal, bm, PV);
}
fr.close();
} catch (NumberFormatException nfe) {
System.out.printf("Number format exception: %s\n", nfe.getMessage());
return false;
} catch (FileNotFoundException fnfe) {
System.out.printf("File not found: %s\n", fnfe.getMessage());
return false;
} catch (IOException ex) {
System.out.printf("IO error: %s\n", ex.getMessage());
} catch (ChessParseError cpe) {
int lineNo = (fr == null) ? -1 : fr.getLineNumber();
System.out.printf("Parse error, line %d: %s\n", lineNo, cpe.getMessage());
} catch (StringIndexOutOfBoundsException e) {
int lineNo = (fr == null) ? -1 : fr.getLineNumber();
System.out.printf("Parse error, line %d: %s\n", lineNo, e.getMessage());
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException ex) {
// Stupid FileReader class forces me to catch this meaningless exception
}
}
}
return true;
}
/**
* Administrate a game between two players, human or computer.
*/
public void play() throws IOException {
handleCommand("new");
while (true) {
// Print last move
if (currentMove > 0) {
Position prevPos = new Position(pos);
prevPos.unMakeMove(moveList.get(currentMove - 1), uiInfoList.get(currentMove - 1));
String moveStr= TextIO.moveToString(prevPos, moveList.get(currentMove - 1), false);
if (haveDrawOffer()) {
moveStr += " (offer draw)";
}
String msg = String.format("Last move: %d%s %s",
prevPos.fullMoveCounter, prevPos.whiteMove ? "." : "...",
moveStr);
System.out.println(msg);
}
// System.out.printf("Hash: %016x\n", pos.zobristHash());
{
Evaluate eval = new Evaluate();
int evScore = eval.evalPos(pos) * (pos.whiteMove ? 1 : -1);
System.out.printf("Eval: %.2f%n", evScore / 100.0);
}
// Check game state
System.out.print(TextIO.asciiBoard(pos));
String stateStr = getGameStateString();
if (stateStr.length() > 0) {
System.out.printf("%s%n", stateStr);
}
if (getGameState() != GameState.ALIVE) {
activateHumanPlayer();
}
// Get command from current player and act on it
Player pl = pos.whiteMove ? whitePlayer : blackPlayer;
String moveStr = pl.getCommand(new Position(pos), haveDrawOffer(), getHistory());
if (moveStr.equals("quit")) {
return;
} else {
boolean ok = processString(moveStr);
if (!ok) {
System.out.printf("Invalid move: %s\n", moveStr);
}
}
}
}
}