/* 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 uci; import chess.ChessParseError; import chess.ComputerPlayer; import chess.Move; import chess.Position; import chess.TextIO; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.ArrayList; /** Handle the UCI protocol mode. */ public class UCIProtocol { // Data set by the "position" command. Position pos; ArrayList<Move> moves; // Engine data EngineControl engine; // Set to true to break out of main loop boolean quit; public static void main(boolean autoStart) { UCIProtocol uciProt = new UCIProtocol(); uciProt.mainLoop(System.in, System.out, autoStart); } public UCIProtocol() { pos = null; moves = new ArrayList<Move>(); quit = false; } final public void mainLoop(InputStream is, PrintStream os, boolean autoStart) { try { if (autoStart) { handleCommand("uci", os); } InputStreamReader inStrRead = new InputStreamReader(is); BufferedReader inBuf = new BufferedReader(inStrRead); String line; while ((line = inBuf.readLine()) != null) { handleCommand(line, os); if (quit) { break; } } } catch (IOException ex) { // If stream closed or other I/O error, terminate program } } final void handleCommand(String cmdLine, PrintStream os) { String[] tokens = tokenize(cmdLine); try { String cmd = tokens[0]; if (cmd.equals("uci")) { os.printf("id name %s%n", ComputerPlayer.engineName); os.printf("id author Peter Osterlund%n"); EngineControl.printOptions(os); os.printf("uciok%n"); } else if (cmd.equals("isready")) { initEngine(os); os.printf("readyok%n"); } else if (cmd.equals("setoption")) { initEngine(os); StringBuilder optionName = new StringBuilder(); StringBuilder optionValue = new StringBuilder(); if (tokens[1].endsWith("name")) { int idx = 2; while ((idx < tokens.length) && !tokens[idx].equals("value")) { optionName.append(tokens[idx++].toLowerCase()); optionName.append(' '); } if ((idx < tokens.length) && tokens[idx++].equals("value")) { while ((idx < tokens.length)) { optionValue.append(tokens[idx++].toLowerCase()); optionValue.append(' '); } } engine.setOption(optionName.toString().trim(), optionValue.toString().trim()); } } else if (cmd.equals("ucinewgame")) { if (engine != null) { engine.newGame(); } } else if (cmd.equals("position")) { String fen = null; int idx = 1; if (tokens[idx].equals("startpos")) { idx++; fen = TextIO.startPosFEN; } else if (tokens[idx].equals("fen")) { idx++; StringBuilder sb = new StringBuilder(); while ((idx < tokens.length) && !tokens[idx].equals("moves")) { sb.append(tokens[idx++]); sb.append(' '); } fen = sb.toString().trim(); } if (fen != null) { pos = TextIO.readFEN(fen); moves.clear(); if ((idx < tokens.length) && tokens[idx++].equals("moves")) { for (int i = idx; i < tokens.length; i++) { Move m = TextIO.uciStringToMove(tokens[i]); if (m != null) { moves.add(m); } else { break; } } } } } else if (cmd.equals("go")) { if (pos == null) { try { pos = TextIO.readFEN(TextIO.startPosFEN); } catch (ChessParseError ex) { throw new RuntimeException(); } } initEngine(os); int idx = 1; SearchParams sPar = new SearchParams(); boolean ponder = false; while (idx < tokens.length) { String subCmd = tokens[idx++]; if (subCmd.equals("searchmoves")) { while (idx < tokens.length) { Move m = TextIO.uciStringToMove(tokens[idx]); if (m != null) { sPar.searchMoves.add(m); idx++; } else { break; } } } else if (subCmd.equals("ponder")) { ponder = true; } else if (subCmd.equals("wtime")) { sPar.wTime = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("btime")) { sPar.bTime = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("winc")) { sPar.wInc = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("binc")) { sPar.bInc = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("movestogo")) { sPar.movesToGo = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("depth")) { sPar.depth = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("nodes")) { sPar.nodes = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("mate")) { sPar.mate = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("movetime")) { sPar.moveTime = Integer.parseInt(tokens[idx++]); } else if (subCmd.equals("infinite")) { sPar.infinite = true; } } if (ponder) { engine.startPonder(pos, moves, sPar); } else { engine.startSearch(pos, moves, sPar); } } else if (cmd.equals("stop")) { engine.stopSearch(); } else if (cmd.equals("ponderhit")) { engine.ponderHit(); } else if (cmd.equals("quit")) { if (engine != null) { engine.stopSearch(); } quit = true; } } catch (ChessParseError ex) { } catch (ArrayIndexOutOfBoundsException e) { } catch (NumberFormatException nfe) { } } final private void initEngine(PrintStream os) { if (engine == null) { engine = new EngineControl(os); } } /** Convert a string to tokens by splitting at whitespace characters. */ final String[] tokenize(String cmdLine) { cmdLine = cmdLine.trim(); return cmdLine.split("\\s+"); } }