From 0461be164fea57d72a63a9d7cd9b09164991ea32 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Sat, 12 Nov 2011 19:43:59 +0000 Subject: [PATCH] Moved CuckooChess project to trunk/ --- CuckooChess/.classpath | 9 + .../.externalToolBuilders/jar_builder.launch | 23 + CuckooChess/.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 12 + .../org.eclipse.ltk.core.refactoring.prefs | 3 + CuckooChess/build_jar.xml | 33 ++ CuckooChess/src/gui/AppletGUI.form | 309 ++++++++++++ CuckooChess/src/gui/AppletGUI.java | 440 ++++++++++++++++++ CuckooChess/src/gui/ChessBoardPainter.java | 292 ++++++++++++ CuckooChess/src/gui/casefont.ttf | Bin 0 -> 35476 bytes CuckooChess/src/tui/Main.java | 52 +++ CuckooChess/src/tui/TUIGame.java | 216 +++++++++ CuckooChess/src/uci/EngineControl.java | 435 +++++++++++++++++ CuckooChess/src/uci/SearchParams.java | 45 ++ CuckooChess/src/uci/UCIProtocol.java | 222 +++++++++ CuckooChess/test/uci/UCIProtocolTest.java | 68 +++ 16 files changed, 2187 insertions(+) create mode 100644 CuckooChess/.classpath create mode 100644 CuckooChess/.externalToolBuilders/jar_builder.launch create mode 100644 CuckooChess/.project create mode 100644 CuckooChess/.settings/org.eclipse.jdt.core.prefs create mode 100644 CuckooChess/.settings/org.eclipse.ltk.core.refactoring.prefs create mode 100644 CuckooChess/build_jar.xml create mode 100644 CuckooChess/src/gui/AppletGUI.form create mode 100644 CuckooChess/src/gui/AppletGUI.java create mode 100644 CuckooChess/src/gui/ChessBoardPainter.java create mode 100644 CuckooChess/src/gui/casefont.ttf create mode 100644 CuckooChess/src/tui/Main.java create mode 100644 CuckooChess/src/tui/TUIGame.java create mode 100644 CuckooChess/src/uci/EngineControl.java create mode 100644 CuckooChess/src/uci/SearchParams.java create mode 100644 CuckooChess/src/uci/UCIProtocol.java create mode 100644 CuckooChess/test/uci/UCIProtocolTest.java diff --git a/CuckooChess/.classpath b/CuckooChess/.classpath new file mode 100644 index 0000000..48158d7 --- /dev/null +++ b/CuckooChess/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/CuckooChess/.externalToolBuilders/jar_builder.launch b/CuckooChess/.externalToolBuilders/jar_builder.launch new file mode 100644 index 0000000..a646598 --- /dev/null +++ b/CuckooChess/.externalToolBuilders/jar_builder.launch @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CuckooChess/.project b/CuckooChess/.project new file mode 100644 index 0000000..e39bad1 --- /dev/null +++ b/CuckooChess/.project @@ -0,0 +1,28 @@ + + + CuckooChess + + + CuckooChessEngine + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + auto,full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/jar_builder.launch + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/CuckooChess/.settings/org.eclipse.jdt.core.prefs b/CuckooChess/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..44f8e5d --- /dev/null +++ b/CuckooChess/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Sat May 08 15:39:56 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/CuckooChess/.settings/org.eclipse.ltk.core.refactoring.prefs b/CuckooChess/.settings/org.eclipse.ltk.core.refactoring.prefs new file mode 100644 index 0000000..3c96de9 --- /dev/null +++ b/CuckooChess/.settings/org.eclipse.ltk.core.refactoring.prefs @@ -0,0 +1,3 @@ +#Sun May 09 18:44:06 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/CuckooChess/build_jar.xml b/CuckooChess/build_jar.xml new file mode 100644 index 0000000..4cf251c --- /dev/null +++ b/CuckooChess/build_jar.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CuckooChess/src/gui/AppletGUI.form b/CuckooChess/src/gui/AppletGUI.form new file mode 100644 index 0000000..22a7dc0 --- /dev/null +++ b/CuckooChess/src/gui/AppletGUI.form @@ -0,0 +1,309 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/CuckooChess/src/gui/AppletGUI.java b/CuckooChess/src/gui/AppletGUI.java new file mode 100644 index 0000000..afec545 --- /dev/null +++ b/CuckooChess/src/gui/AppletGUI.java @@ -0,0 +1,440 @@ +/* + 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 . +*/ + +package gui; + +import guibase.ChessController; +import guibase.GUIInterface; + +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import chess.ComputerPlayer; +import chess.Move; +import chess.Position; + +/** + * The main class for the chess GUI. + * @author petero + */ +public class AppletGUI extends javax.swing.JApplet implements GUIInterface { + private static final long serialVersionUID = 7357610346389734323L; + ChessBoardPainter cbp; + ChessController ctrl; + final static int ttLogSize = 19; // Use 2^19 hash entries. + String moveListStr = ""; + String thinkingStr = ""; + + /** Initializes the applet AppletGUI */ + @Override + public void init() { + ctrl = new ChessController(this); + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + initComponents(); + cbp = (ChessBoardPainter)ChessBoard; + ctrl.newGame(PlayerWhite.isSelected(), ttLogSize, true); + ctrl.startGame(); + } + }); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * Entry point for the GUI version of the chess program. + */ + public static void main(String[] args) { + javax.swing.JApplet theApplet = new AppletGUI(); + theApplet.init(); + javax.swing.JFrame window = new javax.swing.JFrame(ComputerPlayer.engineName); + window.setContentPane(theApplet); + window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); + window.pack(); + window.setVisible(true); + } + + /** This method is called from within the init() method to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + private void initComponents() { + + PlayerColor = new javax.swing.ButtonGroup(); + MainPanel = new javax.swing.JPanel(); + ChessBoardPanel = new javax.swing.JPanel(); + ChessBoard = new ChessBoardPainter(); + jPanel1 = new javax.swing.JPanel(); + NewGame = new javax.swing.JButton(); + SettingsPanel = new javax.swing.JPanel(); + PlayerWhite = new javax.swing.JRadioButton(); + PlayerBlack = new javax.swing.JRadioButton(); + TimeLabel = new javax.swing.JLabel(); + TimeSlider = new javax.swing.JSlider(); + ShowThinking = new javax.swing.JCheckBox(); + FlipBoard = new javax.swing.JCheckBox(); + jScrollPane1 = new javax.swing.JScrollPane(); + LogTextArea = new javax.swing.JTextPane(); + StatusLine = new javax.swing.JTextField(); + Forward = new javax.swing.JButton(); + Backward = new javax.swing.JButton(); + + ChessBoardPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); + ChessBoardPanel.setPreferredSize(new java.awt.Dimension(500, 500)); + + ChessBoard.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + ChessBoardMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + ChessBoardMouseReleased(evt); + } + }); + ChessBoard.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { + public void mouseDragged(java.awt.event.MouseEvent evt) { + ChessBoardMouseDragged(evt); + } + }); + + javax.swing.GroupLayout ChessBoardPanelLayout = new javax.swing.GroupLayout(ChessBoardPanel); + ChessBoardPanel.setLayout(ChessBoardPanelLayout); + ChessBoardPanelLayout.setHorizontalGroup( + ChessBoardPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(ChessBoard, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE) + ); + ChessBoardPanelLayout.setVerticalGroup( + ChessBoardPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(ChessBoard, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE) + ); + + jPanel1.setFocusable(false); + + NewGame.setText("New Game"); + NewGame.setFocusable(false); + NewGame.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + NewGameActionPerformed(evt); + } + }); + + SettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Settings")); + SettingsPanel.setFocusable(false); + + PlayerColor.add(PlayerWhite); + PlayerWhite.setSelected(true); + PlayerWhite.setText("Play White"); + PlayerWhite.setFocusable(false); + + PlayerColor.add(PlayerBlack); + PlayerBlack.setText("Play Black"); + PlayerBlack.setFocusable(false); + + TimeLabel.setText("Thinking Time"); + + TimeSlider.setMajorTickSpacing(15); + TimeSlider.setMaximum(60); + TimeSlider.setMinorTickSpacing(5); + TimeSlider.setPaintLabels(true); + TimeSlider.setPaintTicks(true); + TimeSlider.setValue(5); + TimeSlider.setFocusable(false); + TimeSlider.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + TimeSliderStateChanged(evt); + } + }); + + ShowThinking.setText("Show Thinking"); + ShowThinking.setFocusable(false); + ShowThinking.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + ShowThinkingStateChanged(evt); + } + }); + + FlipBoard.setText("Flip Board"); + FlipBoard.setFocusable(false); + FlipBoard.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + FlipBoardStateChanged(evt); + } + }); + + javax.swing.GroupLayout SettingsPanelLayout = new javax.swing.GroupLayout(SettingsPanel); + SettingsPanel.setLayout(SettingsPanelLayout); + SettingsPanelLayout.setHorizontalGroup( + SettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(ShowThinking, javax.swing.GroupLayout.PREFERRED_SIZE, 157, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(SettingsPanelLayout.createSequentialGroup() + .addComponent(PlayerWhite) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE) + .addComponent(FlipBoard) + .addContainerGap()) + .addGroup(SettingsPanelLayout.createSequentialGroup() + .addComponent(TimeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(TimeSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(PlayerBlack) + ); + SettingsPanelLayout.setVerticalGroup( + SettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(SettingsPanelLayout.createSequentialGroup() + .addGroup(SettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(PlayerWhite) + .addComponent(FlipBoard)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(PlayerBlack) + .addGap(18, 18, 18) + .addGroup(SettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(TimeLabel) + .addComponent(TimeSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ShowThinking) + .addContainerGap()) + ); + + LogTextArea.setEditable(false); + LogTextArea.setVerifyInputWhenFocusTarget(false); + jScrollPane1.setViewportView(LogTextArea); + + StatusLine.setEditable(false); + StatusLine.setFocusable(false); + + Forward.setText("->"); + Forward.setDefaultCapable(false); + Forward.setFocusPainted(false); + Forward.setFocusable(false); + Forward.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + ForwardActionPerformed(evt); + } + }); + + Backward.setText("<-"); + Backward.setDefaultCapable(false); + Backward.setFocusPainted(false); + Backward.setFocusable(false); + Backward.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + BackwardActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 319, Short.MAX_VALUE) + .addComponent(StatusLine, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 319, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(NewGame) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(Backward) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(Forward)) + .addComponent(SettingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(SettingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(NewGame) + .addComponent(Forward) + .addComponent(Backward)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(StatusLine, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + + javax.swing.GroupLayout MainPanelLayout = new javax.swing.GroupLayout(MainPanel); + MainPanel.setLayout(MainPanelLayout); + MainPanelLayout.setHorizontalGroup( + MainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(MainPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(ChessBoardPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 502, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + MainPanelLayout.setVerticalGroup( + MainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, MainPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(MainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(ChessBoardPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 502, Short.MAX_VALUE)) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(MainPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(MainPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + private void ChessBoardMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ChessBoardMousePressed + if (ctrl.humansTurn()) { + int sq = cbp.eventToSquare(evt); + Move m = cbp.mousePressed(sq); + if (m != null) { + ctrl.humanMove(m); + } + } + }//GEN-LAST:event_ChessBoardMousePressed + + private void FlipBoardStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_FlipBoardStateChanged + cbp.setFlipped(FlipBoard.isSelected()); + }//GEN-LAST:event_FlipBoardStateChanged + + private void NewGameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_NewGameActionPerformed + ctrl.newGame(PlayerWhite.isSelected(), ttLogSize, true); + ctrl.startGame(); + }//GEN-LAST:event_NewGameActionPerformed + + private void ShowThinkingStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_ShowThinkingStateChanged + ctrl.setMoveList(); + }//GEN-LAST:event_ShowThinkingStateChanged + + private void BackwardActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_BackwardActionPerformed + ctrl.takeBackMove(); + }//GEN-LAST:event_BackwardActionPerformed + + private void ForwardActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ForwardActionPerformed + ctrl.redoMove(); + }//GEN-LAST:event_ForwardActionPerformed + + private void TimeSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_TimeSliderStateChanged + ctrl.setTimeLimit(); + }//GEN-LAST:event_TimeSliderStateChanged + + private void ChessBoardMouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ChessBoardMouseDragged + if (ctrl.humansTurn()) { + cbp.mouseDragged(evt); + } + }//GEN-LAST:event_ChessBoardMouseDragged + + private void ChessBoardMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ChessBoardMouseReleased + if (ctrl.humansTurn()) { + int sq = cbp.eventToSquare(evt); + Move m = cbp.mouseReleased(sq); + if (m != null) { + ctrl.humanMove(m); + } + } + }//GEN-LAST:event_ChessBoardMouseReleased + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton Backward; + private javax.swing.JLabel ChessBoard; + private javax.swing.JPanel ChessBoardPanel; + private javax.swing.JCheckBox FlipBoard; + private javax.swing.JButton Forward; + private javax.swing.JTextPane LogTextArea; + private javax.swing.JPanel MainPanel; + private javax.swing.JButton NewGame; + private javax.swing.JRadioButton PlayerBlack; + private javax.swing.ButtonGroup PlayerColor; + private javax.swing.JRadioButton PlayerWhite; + private javax.swing.JPanel SettingsPanel; + private javax.swing.JCheckBox ShowThinking; + private javax.swing.JTextField StatusLine; + private javax.swing.JLabel TimeLabel; + private javax.swing.JSlider TimeSlider; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + // End of variables declaration//GEN-END:variables + + public void setPosition(Position pos) { + cbp.setPosition(pos); + } + + public void setSelection(int sq) { + cbp.setSelection(sq); + } + + public void setStatusString(String str) { + StatusLine.setText(str); + } + + public void setMoveListString(String str) { + moveListStr = str; + str = moveListStr + "\n" + thinkingStr; + if (!str.equals(LogTextArea.getText())) { + LogTextArea.setText(str); + } + } + + public void setThinkingString(String str) { + thinkingStr = str; + str = moveListStr + "\n" + thinkingStr; + if (!str.equals(LogTextArea.getText())) { + LogTextArea.setText(str); + } + } + + + public final int timeLimit() { + return Math.max(25, TimeSlider.getValue() * 1000); + } + + public final boolean showThinking() { + return ShowThinking.isSelected(); + } + + public void requestPromotePiece() { + runOnUIThread(new Runnable() { + public void run() { + Object[] options = { "Queen", "Rook", "Bishop", "Knight" }; + int choice = JOptionPane.showOptionDialog( + cbp, "Promote pawn to?", "Pawn Promotion", + 0, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + ctrl.reportPromotePiece(choice); + } + }); + } + + public void runOnUIThread(Runnable runnable) { + SwingUtilities.invokeLater(runnable); + } + + @Override + public boolean randomMode() { + return false; + } + + @Override + public void reportInvalidMove(Move m) { + } +} diff --git a/CuckooChess/src/gui/ChessBoardPainter.java b/CuckooChess/src/gui/ChessBoardPainter.java new file mode 100644 index 0000000..4cc784d --- /dev/null +++ b/CuckooChess/src/gui/ChessBoardPainter.java @@ -0,0 +1,292 @@ +/* + 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 . +*/ + +package gui; + +import chess.Move; +import chess.Piece; +import chess.Position; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.MouseEvent; +import java.awt.font.FontRenderContext; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.InputStream; +import javax.swing.JLabel; + +/** + * Draws a graphical chess board. Also handles user interaction. + * @author petero + */ +public class ChessBoardPainter extends JLabel { + private static final long serialVersionUID = -1319250011487017825L; + private Position pos; + private int selectedSquare; + private int x0, y0, sqSize; + private boolean flipped; + private Font chessFont; + + // For piece animation during dragging + private int activeSquare; + private boolean dragging; + private int dragX; + private int dragY; + private boolean cancelSelection; + + ChessBoardPainter() { + pos = new Position(); + selectedSquare = -1; + x0 = y0 = sqSize = 0; + flipped = false; + activeSquare = -1; + } + + /** + * Set the board to a given state. + * @param pos + */ + final public void setPosition(Position pos) { + this.pos = pos; + repaint(); + } + + /** + * Set/clear the board flipped status. + * @param flipped + */ + final public void setFlipped(boolean flipped) { + this.flipped = flipped; + repaint(); + } + + /** + * Set/clear the selected square. + * @param square The square to select, or -1 to clear selection. + */ + final public void setSelection(int square) { + if (square != this.selectedSquare) { + this.selectedSquare = square; + repaint(); + } + } + + @Override + public void paint(Graphics g0) { + Graphics2D g = (Graphics2D)g0; + Dimension size = getSize(); + sqSize = (Math.min(size.width, size.height) - 4) / 8; + x0 = (size.width - sqSize * 8) / 2; + y0 = (size.height - sqSize * 8) / 2; + + boolean doDrag = (activeSquare >= 0) && dragging; + + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + final int xCrd = getXCrd(x); + final int yCrd = getYCrd(y); + g.setColor(Position.darkSquare(x, y) ? Color.GRAY : new Color(190, 190, 90)); + g.fillRect(xCrd, yCrd, sqSize, sqSize); + + int sq = Position.getSquare(x, y); + int p = pos.getPiece(sq); + if (doDrag && (sq == activeSquare)) { + // Skip this piece. It will be drawn later at (dragX,dragY) + } else { + drawPiece(g, xCrd + sqSize / 2, yCrd + sqSize / 2, p); + } + } + } + if (selectedSquare >= 0) { + int selX = Position.getX(selectedSquare); + int selY = Position.getY(selectedSquare); + g.setColor(Color.RED); + g.setStroke(new BasicStroke(3)); + g.drawRect(getXCrd(selX), getYCrd(selY), sqSize, sqSize); + } + if (doDrag) { + int p = pos.getPiece(activeSquare); + drawPiece(g, dragX, dragY, p); + } + } + + private final void drawPiece(Graphics2D g, int xCrd, int yCrd, int p) { + g.setColor(Piece.isWhite(p) ? Color.WHITE : Color.BLACK); + String ps; + switch (p) { + case Piece.EMPTY: + ps = ""; + break; + case Piece.WKING: + ps = "k"; + break; + case Piece.WQUEEN: + ps = "q"; + break; + case Piece.WROOK: + ps = "r"; + break; + case Piece.WBISHOP: + ps = "b"; + break; + case Piece.WKNIGHT: + ps = "n"; + break; + case Piece.WPAWN: + ps = "p"; + break; + case Piece.BKING: + ps = "l"; + break; + case Piece.BQUEEN: + ps = "w"; + break; + case Piece.BROOK: + ps = "t"; + break; + case Piece.BBISHOP: + ps = "v"; + break; + case Piece.BKNIGHT: + ps = "m"; + break; + case Piece.BPAWN: + ps = "o"; + break; + default: + ps = "?"; + break; + } + if (ps.length() > 0) { + FontRenderContext frc = g.getFontRenderContext(); + if ((chessFont == null) || (chessFont.getSize() != sqSize)) { + InputStream inStream = getClass().getResourceAsStream("/gui/casefont.ttf"); + try { + Font font = Font.createFont(Font.TRUETYPE_FONT, inStream); + chessFont = font.deriveFont((float)sqSize); + } catch (FontFormatException ex) { + throw new RuntimeException(); + } catch (IOException ex) { + throw new RuntimeException(); + } + } + g.setFont(chessFont); + Rectangle2D textRect = g.getFont().getStringBounds(ps, frc); + int xCent = (int)textRect.getCenterX(); + int yCent = (int)textRect.getCenterY(); + g.drawString(ps, xCrd - xCent, yCrd - yCent); + } + } + + private final int getXCrd(int x) { + return x0 + sqSize * (flipped ? 7 - x : x); + } + private final int getYCrd(int y) { + return y0 + sqSize * (flipped ? y : (7 - y)); + } + + /** + * Compute the square corresponding to the coordinates of a mouse event. + * @param evt Details about the mouse event. + * @return The square corresponding to the mouse event, or -1 if outside board. + */ + final int eventToSquare(MouseEvent evt) { + int xCrd = evt.getX(); + int yCrd = evt.getY(); + + int sq = -1; + if ((xCrd >= x0) && (yCrd >= y0) && (sqSize > 0)) { + int x = (xCrd - x0) / sqSize; + int y = 7 - (yCrd - y0) / sqSize; + if ((x >= 0) && (x < 8) && (y >= 0) && (y < 8)) { + if (flipped) { + x = 7 - x; + y = 7 - y; + } + sq = Position.getSquare(x, y); + } + } + return sq; + } + + final Move mousePressed(int sq) { + Move m = null; + cancelSelection = false; + int p = pos.getPiece(sq); + if ((selectedSquare >= 0) && (sq == selectedSquare)) { + int fromPiece = pos.getPiece(selectedSquare); + if ((fromPiece == Piece.EMPTY) || (Piece.isWhite(fromPiece) != pos.whiteMove)) { + return m; // Can't move the piece the oppenent just moved. + } + } + if ((selectedSquare < 0) && + ((p == Piece.EMPTY) || (Piece.isWhite(p) != pos.whiteMove))) { + return m; // You must click on one of your own pieces. + } + activeSquare = sq; + dragging = false; + dragX = dragY = -1; + + if (selectedSquare >= 0) { + if (sq == selectedSquare) { + cancelSelection = true; + } else { + if ((p == Piece.EMPTY) || (Piece.isWhite(p) != pos.whiteMove)) { + m = new Move(selectedSquare, sq, Piece.EMPTY); + activeSquare = -1; + setSelection(sq); + } + } + } + if (m == null) { + setSelection(-1); + } + return m; + } + + final void mouseDragged(MouseEvent evt) { + final int xCrd = evt.getX(); + final int yCrd = evt.getY(); + if (!dragging || (dragX != xCrd) || (dragY != yCrd)) { + dragging = true; + dragX = xCrd; + dragY = yCrd; + repaint(); + } + } + + final Move mouseReleased(int sq) { + Move m = null; + if (activeSquare >= 0) { + if (sq != activeSquare) { + m = new Move(activeSquare, sq, Piece.EMPTY); + setSelection(sq); + } else if (!cancelSelection) { + setSelection(sq); + } + activeSquare = -1; + repaint(); + } + return m; + } +} diff --git a/CuckooChess/src/gui/casefont.ttf b/CuckooChess/src/gui/casefont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..61c12d6e7256f956e1e00f8f84ab612fe59b3a2c GIT binary patch literal 35476 zcmd6Q2b?5jnfLov?woVZlV`emdU|$Z@6PUQoZZ7B{8rFA&223g35~et6%3%L|XK!trxBcJDj;{L{ZRcFwJY2p=WnxOe~F1IO=+ z?_5F1iZm#$#H$3Cpq$EeP6&e*X#QtNz;_R zFA*cXQQxoLpC?o>;NGnK)%|MutNYdRSNE&sukKgNU)`^kzq(&7e|2BG|Kf>*6GwL) zo7fxQeSUoO(7|Je_8r}Ic>l!Fcy~vhEG84=Al9Q~7deK{y(EsNJ0IIoatPlX!*-wc z?P0QCyDm<;Ne9V~?4OvNjF0S^oR}md+EShJp{m;1 z)!R959(kuvREbJDF+h8WxOql(e0@D1I-WS(Mtf-=EsQb74Ei<3j#6 z{sbwIA<{-g(nQ`*9w8I-QM#VqO6buYZufe&wS53*Yho{h}~RTJM)7Z0{2U+~+~c9#5Pcwl(IKE?iN=fKne zTS>l)F5M3#d8EakX2j~(f23GPVy^Ngc(|XdT=Hi%c-4NKe^X9qkfFFs^Ei z+(|niII4qruBI)i9(O8P?B)d!Cy#|`HdyMdYQnJ-ayv+(BuO%)nY5EUDUyCdG9EeQ zqA6PR(3An64v%)I9TjMiVs**I1U?KnN>vX_34C9q{E12Ru1ZCv-Ic=y`uNm~D!10> zJNX@zKRPw8a=)lNm7j|8W%c9@em|EeOns3)Q5m2gyiu(@bJtzR_+uyY0sgtW3zL+q zRA~2&`N}~qG4&$1Zt4j?KmX(-{N&?PQ(G!-du_ny2#<;yuX8$dSHQ0=nL#%44Sb0a%4Gj>E(ug5K= zlG$Q+5B zF;KxC_`J>^DF39!8xt53!(|s0gt7=(AV6~=;0tw*fFYtuf*RpK`D?7PP-DRSlL;(L zkZ2S`*nNk}&gy*`x1D`k#$Mm-wv4y3v4-1LsXL+F^?zDgv_(oUYqbqDo>4Bl8`?l? zf$3I1S> zug$*gTlJbl?=}8Jl^W2-Xp>n~Hv7gib&c6n=Fs|$-PSb+SMrbm^!Eg~Ql9jX0WzN~ zfy%g+Y$7`d0qZIC(<<*_pE#yf1{I-Ieifl|iY6tG+gnh3irv`~c$n8mi)@?CQ4j4Y zVWaUhZ;ml7Y_Tb6tW5$NV%$jQOW;s`C<9rB60`#h@2Sd9Ra)?lS3V!0>n)v?AJCk@ResFfm#_SIKYs$ON@H0X^U~ND zcx4wDBV&0tf%#S0;0=YzX`U0p?SCpPr0au~FPIKFJ+z=s{aa#!cBoV1G*|g4Rh8Dt z7w|aS(#qeeH0M5E`H{-qSNT!Arbj@R;lUBd$`Oqta-s;)V$c*>h!W^iOotSwg_?be zGR?(4RU6>q9Go)IUGTKh?w*1tD}fRx)}A%i(w|6-ow<(o5famT`Bkz2X3(YNgXGiX zE97zVBzcDXko=hZ1Nmq268RN5LH?Eemi&SIiA+&SMQWfH>Of}&Xqd)m3bIL(*tkEDwhJmKsJ`0Ivbm&eh2AJ9*_}M>7Wf*!#!q4t zhdy?y8xNTNgHi@b4d$Ej$m~+~4Z9zHfYLWdand2L1k5A$hD@6}`ijS30 za^*?|COLDmXPC;K62-9(E1$zK=5r+vU-H-}YF#LKWFJ-$IzkDXQchoOG*yyIkkSof zA)$=}T%DqS=-S)4EyyRrR&&dsIdASQZwf45y*L>P`m&jPFg-fHJg~XkYw5BKwz!<0 zh|p&2{#a27IFj~ENr`uvn?#T3ix>x1j0bGZU5gVAn+jCP;TZu9$X!<{yhB6}8k0(;Vm z(${WTrB>!ueoe)$pSSFrRq-`QQ7gsq&ZY_gtl}A36Ex zSYR#pNV{5ES5_A--K?H|@u)iZ`R$CLn${@u5l|KH2-wzE$H40YAY0dlW zs|3HX)w0OGX6c%R1AHQz_PCl;*@Q4KvS!Iz`yxxL(J!ouL}C_?!im;Tx-5RqB61vO z2m}Pl>F$iUeTqOOArLUY&J%ePZxo&0N^e(BPgn0?&@npHSCXVs-%!RHF?%Kz(PihU z(1md*k*TFWr3Ql4x3$}Po&4EzEJs(C2j=R5TEv9T z!v2=Av%t#}Eq!ax9Mg5^Z)kF2n#+iDa2cL*vz|Q7Ww<#W?Q*Az{S+EmQSC`2Cf1z| zCc~aQcIH}enP{EM*dRORk#VvM*8C^QUF37*OXNQCH{_e-+vG9wJ@Pd9Tk<3F_vD|* z&&e;yE95ui-^uU5cmA7s%Q6_^Y$&Iy1KUg88fWk^E>XnLXXjyyV6{P_uwmU(sxpg= z{wo>3@Ok^WAqr;Elj$k3onm(?2|j@@9E>Swf8brE9(MQc5@TRRD0kom1&{3U`l6hN z{TkPUeK2l=zl;y8AOkMII6#dXP+8|2GI$3#f`=al^8iD^H9m?HKCC&c>>Peu0IR5r z&??(t>b@p6|2Q;Q=olFo9O*nOR{8s&MKM||-tJW^jLQal9qv}QiLMOHPcF<@gpC)! zXCrS(rxvD-K{}9)Hl?w$)Bcm&agJygWDcQ~v7#?n8rW-_DZSb6T%j9yv`t z!U+ZH3w$Vg-#Yu=(b31~qm^r1FR4>csYgteA8pt$@vVEZmz~W?fsN{e`6jipW)AL9 znNn$SQoTlzjCR>zknL85qZb5P+(xU_t;n_m<&tb_^F3jbIFZlyhQotx%)vs1dwXNS zQu%lU!v-nc&rpo4ZTf0-;X=gauIc7Ie+DVf>gEf$dM%z0( z+oREF*zU*}ahj^l;dpU4Yz6sjS$9>}*8-`5KE70|Hci*S}GPzg% ziMmLwe5LTHN;gJduADg9RC#{Ay5T<_RPQNWrXHYw=iS`gJevhnHHQ!6C##-Z=$Ws= z;+s#_!)13Bxt81r8T=7)E4ia#e0-gJgFH+gCEq1aksmaSk5{2}L9#MG!WVqBvb6_+boy7$bT%AaWQOofHEEg9OsG;DMHi3$+zuI91Zd z*7ww8v9pJxt;t{@k!|5Rxv9U1UP~^&b$EV1Pi024wiZWwq01kzID&)4I6$1V*htg{c`%~ z=qSbkM#B^v6;mM$koRMtJct4FeGHt+0XBrJ$!u58PPzVgaM!x|-3y$)_Q9CjrAPvAusa3COjl)#oi-u1v()Kyea!1U zbGX!_rpl_{?sVFt`TmsJ(>qkTE3X^vm0$Y!SAD(;lSVazyt(<1cQdM>9yk|tdpqd& zt4Evi(U(u209`Kwfe(Pt1rYo}M*1hO+j6MXJFJvS;y~Z$F*-=N&e`XYWpIC=OD-T6 zLyx?ITurVcA0Quo14^Fe^rW3uxp7HnrE;>!Xt{&t80l&hmg}c#iP52_r=XKBn6;bY zG?>3G6F`}?Ctqds$y~CP>P(%fn-S{HN1>4SWHbV1KM_H&aO<5yth|jD8CPcPdbMQ-dx5ZH+fQ7 z8wdX^N4ee+IqiyBO*Vsh->xH54^ZZ{4)hCVi@%HW(EXd2i853c$~lyg@zW`_8Wr=@ z#~cB{9^k_u&smh2Fppkw#lDN44m`5!xcapP-D>w^MYZ@?kJ@vCT2x=yyxBalBlX^M z3!l4n@k`Hcr;b47cNcE7Mm-TXIu)g7O> zR6Xa02h|0VV5-P9ha{GXEJ#oKOsXleSE%F^4_hpVwG=0|%K{V!4~z@FJp!Htu03r%HF6!upeRuTnevVYB_ zVI=EAL3q$K(^pbh8+4aqiAM=*=6qt>gt>mW0~9L4txdBcHM)kgJT-VtCWj%8=ZhKSA=;Zqb0~Xn6R7I1uFQeoP?r@WdKCO`{-_$^lQ!DRyB;<^N z+6D1|q0?_M3j=;e`d5fqH!pgO(2A)fJNU5M-LaS|wt&gN8_X_ld0wI)6ZZtu803@> z@CF%o5CoAkNW21OIo4vcEHY)Bv>Wt22s+;ig1=uQ{mz%3?Z&XkVR&rEFxigb62!1s zjNucULrIxbd4G&r!yeq&X*3IB)FIkAg;R`zi(*9g+dQrg?$VD`D&56WTcW$k5laUL zTf7E?7?qZFu5&l{uFVUTujSTHogx&u}Dt3&u&e z9jf6aqI$J=M?D$HDAQSa)gN+I&w%EF@XM$aRI&{-Cd zrSSjE9BBs;usn}k$l}peyC1_wr|%lsMk(l7_XL0hHHS}CZvX?eaWmc5BGd$M+Nu#w znU@HwW{iXVGWB2<<+`AJz^g=m!zEIC6K>}QZ!*@}TK0A{W#fBOaqhJlLj8h!)Z?c| zE1#Pw-G7$2OkHbxMEzcf4hJf~6lkLIYKV6K%=Ozx#qU+_8&OBLFHje3pRdl}I-)M5 zp9nm>v+_&Y6skN-J14y9t@9VF#$+tBE|p2PhJ&S+WX4&}q!$VmM z+;hCJy7GCIi_Z|wH`(6%%k(3aFZk$Cpt7!u#?;CNKP{@24@Z9sH&@&D)XG;!uyFI| zb0Z^L?+iRl$11;oYw4cKBP#7A@Yb=udkq#}Qtzc5WDf$>XCb6KsrS;fr2Z&uvQNPO zb2s@sBK)&@Pv<#Ry|Kz4bC9;IbD13l!>j`vZ4W#M{0dis_kcyQ{$@s!hxH6|>G8UB z)zmx9@?nBi7pEfnS6>U*fmFo`4piqxP!fv}wv30?9gK47H#DB!lW;lLd*-vw-r)4a z_om}qYg?#4Z?cBG{dS8*5mH`HGGMj!<&D<-K(MtP{nh1SJ$DFQnCVmdAMI279_!Ed zvCpTZC(+?r$5%<}5#$G-+Wt7^|o z_)=RJFlvZq)-!78VZ@MHpNc0z4CQU{pnB$DHW~55e6h!)rIgWR@Y&5KizgcOxDq~t zMM;(N5y>k1Bk9cG88puNwrfS@v<_oJUpHt}t_Z&a&_n++a=|LTgc7{u-j&>H!Ww9tXI6#=h2^;;p zK{=Dq@2-N^FHKdtke)>k(_{2Fy@*~)ub@}c>*xpQhv`S@?etFiX;|#=h1INK{j+NE zGOITSMGJ-ivjbeP*d^xu%QC&M>X^eR>@Z`)#{{D$Q6*X9B~_7Dy*2|ik9qjAC4DEM zd-;mpzWQFKX6|U#izY2KajP3aI6Lc{je=&i%NZR^YW9)x>97ro5? zpbdp-$*g}f_jx?trx%#l+!?x;GFxH-9NZB@hE*G*D+fbM#jfT6#UY+r^>suj(+Zf5 zph8Pv?WpObnkI?^@J5&)a#4iN$_y>WG@F?HTRG0C_>^dflY!_NDVvQ3s+jiQ^Vxka zFNgTn0>R0LV&;&MlPsdmE>v!e#iGuSVnYv`olbN73bu_^&Wkh|O;nUc+la_Dha)ZC zkijjK%+H+s_T5@2 zf(0P7QBIGlMPXi{P!LM}&av%_J{@>s{X^>AeV41}o!4?Y9I8J4fMHAJZ~UG#hO$%U z&4!S*XWZ)bE;f04bDM{oQhY$@@0Si6-QLYP*Z!`6cf7|FG4m$3A+yM{FB*@Vo#U~1 zJmxZ6T=CerlYK;QYmOLvVac5g6q|=`SmN-Q#7J{6CB|zS5wt(`xSRou3aD*l$Il`-*|K+-{DXq&1qJ&siU&!i^X7{@Z4Dzh2zZ`uVl4K-poR1 zbUZ`B(2&hwu!f=1Nx;a^k2ifT@Q8nz+UMAId2&~Of8|qw6)HDxy;}LtkuxFOa!;$= zh8p8Ss3-6`q1_))k2ZP~UBpL1q=fkRFmPFm$#Swvi%4xHI|20C51aHbA{)oSwJsx9 z0#kH7xe5N2kCNNTozV87edLNM+2c#V$A=&Sj(9nd6FrHdn8P5)TJU)a4O?96ktx1+ z>ADBgKWZz5FM}y79%cz*_-QMSZFrF8{m4Ku$#}HOQW$|%9UKa|hsQ4)1}6j?(~Rg7 z&eg6_`+B-^y?xZR+WEv9`s|v@b}l^iod42;>BHW%=NeDSdnA4EQh#L?jeNXc?b`;) zwH2S+=c)bM@yXqB`^P=E1uFl1k$Tai`ud#<^A~*dzV8J8iCQd`S7@a2%UdrEa4%9r z<&W0Cygcf^|C(z~K3r9QVXSGcd)^XvI+KpkMTv(7 z#N!^erjG3V^JUOde*N>GPyMbcme`g%t8lAo3EdXheWA8+=byi?aIc#8|C4%gy7FuF z`h4Y=s!_c(0KAu?R{pr^&+1D{1NWolf*q;_8tcozDx@8l@7f~u>F`d3E>EE zBhU-|gT?K(#FW<7j@H)4%z|Navo97h4bx1}C>;m@#ciNUa8&Ai^+i3P<8*L=**Uw`zbIz!}`uyw~1r z_wjy1t997AeH7tHF`mujn$nqslxXSBwJwdz78?ioXmhW0J9&@$g*km#C;PedC_;am zCbGjL-u99QF~M^X8{CE%;h+{Q{7-}p??(LaLKaDU-2MHG9IgBvB8)o_Y22X29O;v3 zz{=xwE!+>i`)<(UgXBAijs2RuM*dBU!y_IBw2x5tUilFvN0809lkPv~dl`fzjMd{2RCyZ8lz7_cYjP;A8fpvNLqW`G1` z@HZBIXXa!MG|yJCYH4U;2*wqez^#gDM)EL0@IC&u@I<5MmwAAPIXT7sWKsXFT?32a zj%d=d+H7duY>yj+=*t$T(-L)3{?d8zgjKm^P1bGcPg2<~3o^9RNVtXPp`9vrUvo6v zqAXM_l1pihgqsW|5TGcJ$j#A6vo9p_@;J{!n{Dai6@!>E&ZHRYbmzz#guuWFo>G0m|#V)TY&cd9fRjNZ7|m@-70TEZ!tv(+7G z8(P~VdF=wbNDXD%)K!Yr>l_W3LUF~(4M63zI9IvM&^(#;xyor_n(@?sx)A>n5CU?$ zO)}?I7OO`oVR|EXKWuUxhj{W|pjx`2V|GK?%t7g-8~UMv9&~K`N2sICP)nB?www(3 zI4jimVW{yJL7o2s)cOyMZO@hZl|q3N<`HO~RcrYK{9@e=9!0o{XT^>{&Lo6D!orfH-QO*CHXIHsOP*A-%4QE%e#C958vvMhA<1}wA zJS!S{rKEo{9}2VaaLhiTY^JIfAR=l&S+TFQ$nqZ^0)F1*I?>`-QT9D+PMi^G^wZae2c){%2%FKU!!L>Vz=m*stmjX7&RQX=g>pJM z=QF{lMNyf0_^H5CvMlkznrf&)wO)Jex!X^uKcs8W)mNcJtUxN={#8HqSH>#Osnq{K zkanr8M6~PPAU$8LL@J*GuKtsLx;pTiLgmXpJn_$s@Gf*!1BSD|?9lLw2;2w&ZQ;v0 zqQ8@NPD9A&!f!Gh76WA@;8)p6hWV@cPXS{W!=#A?&>1fU=IX`r0s6!fAFuKS-vSPV-YecxaMYwOt;)VQ( zuySk}zcej;*eBds6uvkp+`4?(Vt!O6d5M^%uK3CkdFc|j^yzt0@Y`2?nxoh1dU5AK zClF-%JOsAOu<29!AJAn0!{VqqRY1q;*FQ*oufC&0pRXlPG$L4^&@j6!K&|;TG&*Nw zFV&jz|>d`NY#k0GR*>CovDGc0)Hix%lJ<4V)QGsFiqdB;hm=bwGjt3c`8b3u!^3l zyiKsxfp?1L(neJs3tJmin6ClHz)XZKLj>2*jdP7EsIti!_*zoM!Pf4H-(VULn*~ur zG!0;+PTvy%%SJlYkk$;##Gt?!szCZ*M7Hrq`43^{+H&|m&qY-GW8`b)_4JNA${){P z@}7fd?%BF!VSjTx77jUYJ-j~=x33EY?U&yq&Pyf5fd4$fI4U^HLh}Nld4-T)CtQBL zM6Mc_+H99e6Z@o1n;iyp`kprF85r-|Nr7)1EHXJcX*&my(GCdqm9fA7r zGm<+Rt96G4AZNp`rquma;3oc5oK!+rDrdr}<^*2BiUD}@6o?iZ*i3n2svA=m=^y_} z5Yk^70Zeq|+#shp@KBXc%!!<8z*cR0XHX$}*G$OKEJ)JrvtdiKpiPxC8?jHAmvEs* zdp7}boky(gJm?M|E05BvuP(p;@Ov*jYxl10+tw`{?CEIoIJirW_qQbX?6&XSw$;7` zGl5ibbYib~+Ln-T*d(l)FD-FNy-`Ivux8259UNUXO=>zlRf$YHXdo}l9jJ45eMhIT zRpjbM3cFfk@NbC{%4l(*X98N2}z@HFtpTM|xw8SkV|lxvAKKD@6~b(zi^*R8Y; zKbKrt?xp9QS3Z8up))4-?%uh2)!3rmd{;-CNOo@DuxO~iJDZ3F%nA^)=lEd2+NC4S z(%|4(ly0ag0gSn5f`4Xr&+7dSz56$i^BTMVJl6d#&1s=wYu*xvGaI^-d8a6#r!*`K zxBCsCGXFILP_y!#fO6=2bnMClb3rL5#r^sAwx&cp9Q6C_raNxB;-YoqE9dnz zXX0V^GSLzhZs!EUM&YYBN)TO`?6iKJbm2u8ewNakY8}lceRdA8Ndt8)@2$Fg#`k*v z-$cIF*#BSC`k&!h)ZCnCmJ-veGyn_Yd;Gf(ZFxf!4m8NBj{;ztLJ3@ACVb~PXN-j+ z4j8+p(I$3GUX=YNlgsY@$f>}SOd*StPYTy);BvsbVz=f1jUdLa93#t5eZh*=Xcd^xJk%wqfq5W2G4bH-h zofBjN*8f8Iq?VTbG@UMI5{XFAXEsWlRrI8Y6VRPHp@F_?lvC5-07Yq}nlz&trh`}2 ze0*yARVBO;B=SZ`j<-fyusN%*q0}6|2vgJ7kVEATx^``O-T3&5(SaVdvpMFFh_J>i zEb$5p(?VZZ7z#-9JBie_rfWXn!1dZ_22g#-Ojiw6tkq5>Ya45~meq~{&o%eh+eApn zr?f`RBEjgXA!fLryeXuiZEhUIEq@itKz%FF0;WMiBiX@!mcNQ*G3|d8Hta9qoBSg% zbqXB;vAn&YwNKLl8>8LwjA%HodjWHrVFs2~^DfTvInHt~{_h9yH7`BPNT{-PC*`!; zQimmo?;P4d|LaX7)jypP)qbcR?as2;_y2BqoxV?t;yCSfs5`af& z&H!=mj41Ms>F_dl19SPM|9=U8-&PIBk5_~9tZ3uai2XYa_(LoBCbWVMem-Ud#x(3r zKW!=BK?erPgOQ$MM|*!?si(V;%~&nzTsos3O}ae2diI1Sh3vjR}6A(_t1dr=nqAqLxpAO`@*mw$L<=hFll5 z^QV4Z)uBA0oK&88qfgANuPvHhs;eR*8E9m?1B~smDC?U=STp!OgE&8rIO?hKe>#Ei z=J>4e`qXn=xU!wa-%p9jb4!2z^Gay$F!=7Su8YRU=`%A!=a8gqN#Kts4W0_k`!OA{ zp6RJT&oow3^Hi{4H9U&&Q}CEQwU00IW$2KMUcO!4uF2;>Fu+kSCM_9#ewWMbbh-py z5RIaQ1Stl)O*ET~22m274iVw*c!UolEkP<7Th@R7G%IjjSyPQ^ z@0&ZgOpRLX8Dnb)>F3|ie-bjx4|MoZ_;{Wy??%+P{GQfDIj52ASifr7{MLBDiz!G^ z`?eMKjYp3hHXxmcFz@PFL|&i4hgO-~!}H(&%uVN?4%l46=dmf=Pk!+9cOUxv-JiPoL)Tw**~RJ==`y8nMEh+FwxHA*~p2>GQ`qLmz} zhA~$$B|?jBvOPpuzwrMi%6gw3<*fu}hJTqg_#$}`Nn4l?>Wk&&w5_e&p3Y^%A+N(O zi6oazC!*ny!)`Sxl9)&&aao+2Ac~-y_>4xM$!Nk&TFs_JJmJM$eGh=yu4c@~sSkt! zs>zKflqakwAwTeU>T!ccFwGscL7@}BLfRUMzfEJ2e?{z-zEyDaEd!Q>qiq_ZnqkJ0 zWU`#6sZ=>lBW6>`WDGh5!6*15f}dx>55G?iS|!CT#X?e0PmfZM3JgOqus>bQ;)prz z22fol74!-lNvg5JDXqdtZNeZPh$R<+6V`n1sU(~1lktce$k@w5D3!n4xp;4TNzV0+ zjqW`Ev@z#n`ui+xs?W;j7mP7z6|8<)RyS)xio8+Xv;;7$lBd?HrLk5mGi$~C2k`%5 zPMsc47=rOBV^TLPW>(v3ItsX0*glrdtB|Qf8<7>r(^ z-`q}{=&&Q-qX4uVv6zwJQZN~jj6ft-iMJ4#VqT9E$#>mI{$i`^79emoezjnymO)8l zNe#47vsY?edst6EvvEZnWW%})((KF6>{pnAx^Yz+);e~&- z88&WkHB)P-@-GIiP_OqrdcBRvj>7W&om=jPYE$lPO$7XYpV*ugn{w?fLR+gzAThzg zNofE!Lz1Vxt(k8k8u9bgq1%_$%1x8~+&%3e9gQ{V&}ss@)@3H9JcIAfDOu|sUfQ+h ze6J=wUE@r+Zn~;2T)mf{c0{lB<5dwlFiW=52le`kKv-A%-2_BkD`abd9544^YHGQd zZ;2PW1U28;CU&&@1=1v#B_Zk*lAPqWN?An;7t~Ikx!~LRHl9Y`s0~Vx@&Dv6RR^sY^^~WMDTP=Fu^*xV!@7nh}zzj5Vb3}F4%MBnPE);@6=o3;es<% zf?z$N3))MW0A8JTH4kMp0Zjj~#s>sQ-Z5SB%0Q~e$z_P}CKBZ&=XBU@)>^_%B#&@- z1tk;&jSE%_ymcI9NjM{t$t}VEFe3}6E`(V#=x!P&yEK_q6I(Sc627U%hDor7sU_xo zQ-O^6P}iL{Ru{=b3#%fzn#Hry%)~NJx7^!y*21>;GqH?VcCDsN!-&J?{y=#F&1A~i zm<35|)2U=49*aiofL{aD84whg(`o^dTX2wgM2bbz2`R~QvMD4&j7AYT3~p^OKwA5XfcneDY)$u~db(2XnCKqdv2w>) zGVB%uf$U&gXLHvYPUhHTS7H+@*oY|6B(>AsF(?5i{$ zFDJNI6ue!}q8oELc||k_1#`WR!$^}Of%U&}AESHct|cMy##+W_bnhI)9_m)1T9e9E z%hzt1*Rv!Ymcyx@e9w}xC9xp8fyNREFfrgr%YFE4oE0bhqJ{1_(&_!KIvoQ49 z-g5cnTb9h1mo7c4sIJ~3@V=GDv$Z-$g3g7>O#1Xy?Jb+BP~6JuOnzGD*;yn+zq!1K z77FEVE*Wq-3<}bw=ylGd8NK^Egh*2^l?;e}Av;a)Fp%?72s)h9GK=U3G^4-XifRexb3W3o|-8$AZe!PJuy|I;z^+GX?>yExkQHVjk#PUJA&;uA$bx(rKG^jivoA zb1aY^Y|A%A*3_D2z3|=9M97}Cxq`)(p}i|MDT+nB?yww7_eEl-j0+#R5SEzVUk-2} z{8|ISuJnP^+jy(su-8e#Bbn_s12bqEbFeZ)Y-WoI?ekVo5DY%DN>qB?@3jy zOg;H@EWSQGNwxn6F+SL1=b$8xJul;IA49L&~zy;56ze4nT3E75OrdMKK>7(Tx z^yZt(w{)H{v3*`sE*c32?6$M^*zMj})E*D`?cO7TG9p|!EHveo3Z3r}R)0|Bt`SQJ zzWKcK<i^4>A2#d4vvbGNkN{Nr0TZ(1*Hkc55G4dD5+!^o~mIsJC4VS<` z)e^4(^;kPIoTU?xIT1Nmj#3?8ZhM3F-RrBd$ToZYwl>WuzAJZ{kf%fbE`|SC@!A+g()QSoq1k~%CtQd&J;=uCE5}m zh}r<2aVCA0AG-&mLkTlKc64%uU}{D-mqVB>-BxhJqDh!8=w7t1&Varf= z_i)R?&gHA~vCjUE))AYLwgv;T)f)|lnp<08rH1`BdqQcYv?Co1cg+i!-JbmF<@5s1 zhTU5f4{u^_+dy#7atPHceFkI1$MV2U) zHDxVFfQocPTABccxM0Z^w4@x2wL_tOYs|$gbOk#3lymH+U?|nz2VJ-$91i8`v@(d1 zVit)D*l&;~WE$V8QBdt>S_To6seZCPyG(;x)R7i!Cp!nyf=y#XAvBb;c8^*L306{`a6ctAxY-dvhAK$h)5aM~g|H*vCK z*diBK9HTVK$;(V`nd@fPaQqU-+gy&9c>^7oXL87_OAq4luY;~8@FiK+3S;Q(Jm3I>0ddpzaXll6F(cDh0a!RSyj z{Vrg@7_Sz%n~}X}m8M~jkC#`EjV)c+SIl=bMePz<ogQh9|T~SAY+)^Y{*m@X~Uk51k-Zr zV2J9Y0@u}WVDyD1e|Njl+}4fPo)}|pcf@Fx+&OEzr>)1A%W=`zmS}RNyRRwR=N?N& zw#37rzO_*=8kDZq?RJ*6`u*iTJ&&zHkrY{!6d()$N&zAWYz$}= zMOF+7+c5!vfMoxO2k7o`J?TGtElM>206A83IM!5I1`5#?Jx!A74L#?(0a(04=5sEw zn5lZhgZDT;jWh?#m>$F3%2z%p(}_@X9Cit#i~r`$$Z``0#(oqC!AszU`c?Tb{oeP= zPhuw4O*dS6^vvCBSC21UlB>M1KAj5@(>>& z$a?U^xm8Cg+GQ=Dr`md0MIZhGdb$D~Cs7%4K6RafxmrZE6iP2Sc8W z-_Wtik!~|J0WD=RXG^9wliIh+JF;Xb;crVO+Wqn2B@2Dy^9uN)l(jqHpUp|CGrfr} z2eDhNb~q?`li7~kH3GfGWwpB4T1hGbOg?J&uxu>*T&AEY)!UtyqVR-UAx;cw_V^Ar>VnbTOxRsCd+_r z$;i^7ZZVQfq|=FHMCchBiLoEjWah^4XI7OmWjIn@Fr zRqo_oA+L2a)`YqHT4)6Q;Hj6By$$9=<%QJc!pk$94z#H(!3pSaDo#7&roeBB$Za57 zEhsI_B~(U~wNl$8!HQ74GMmd*nM;+|&T<Ri^t zUvT};v>IL4;P5uS@UJWfIjfnLw`GpEMX?AXdt=o9&fB8i___aUZ>bVB3G*m-E3|j! z13RDPa=`44d+#mZ_vO!j_ER6f_5D{}e)!D&r(@dAj%}xnlselmnIjeoV0s7UZ`^vz z^_O3`W6jDHMYTDbjK?A&w}BfKE$f9Z6Y1KuYorT4bKwPe!&zN?fEx8^S4}9)_?$yR z%=jJ$dY4~M?rrSyds&ye=APh@LblQpQgwDmA&=P>jHN?cVY)p;fc~fJ_L^W} z)+?GxGVmq4sD4kF6nGr|p+z<1X7#v_+QXRKA?#LK z0XpG}UStoo3S81^w>#b^BwdsWLA-HDvdJb_sJTpG(is(GKS$zPx}Z&>lfq_yye$NN z8CY^I^0!OtD7H1ketI%Kr-<9V;OLok}VlTuo7#tdE~v+JM) zN86iYZokc7H5j*SI-MH5VJe#A@0ZPL#x|t&Rke#&}Fj zBc`7gf`aJxX$%E11)x*H%;OID4?jI&wFXV8X>Yop4%DO*oK93m($q*)O?5sp!x2>r zuhu@b7`YBn*{z3IH;l{-u`brQ&0GQ2mVlLU9eR`Qn+s|96c+oZn5S!FVe*g-0$GGK z1gn&YUy|T_1Pf~PGU+waqNi1-dZQLf=7{ra;04g>sWCKYIhr$_J2ZzY9oPk~(TxtX zo})|Z{p2J2%PpF>jCyTW5fdIofq6~cf>G-rpM>z3Q}3M`ARE$(d4j5a!yH1|h;J;u zNM^gn*qfH<98iTSkFR{`;L3}S?W)2Qv^NqmkU~?}G)O`7^VQni3odw3xkQu6GLT3t zsIPlM!5<*BBF(D(*@Fw^f@=V>~T5t3{qvLquitux-z(a)V{ zaF>=dH-9MTHbmg&Z)I+Nbjt0*a~*K;w`Ln%{LI5&t09ZgT~eN>`M9Zry{iXwNp*+Vm($>_UEFwIo#R|E>o{0)01cTajS0J zdY~#1L7*xG*DV57tcrJV&kfdNREHE6qna^p0^|nZGJ?T!h&t>>Q3z;Nbh;Fm8!z8< z05oF*irk=~NrY;=9o3X2pGh*?tTTI3BS=ut-!NFg z?UOyxhET%3A9CLCzQgd$7&G;3(^=;lEm9F(y3U~ z14AGYM}M{mm@Xj^-$L3uepJ5l^S`Lqa+mtJPVn7J6|8M|=y{ zJa@5qpmW6=I_3dxV-)<|(PYq;v$+C2jZXP^sxJb3TO)^bku%F})a@>Ns0~47Gy;=S zzzspC*IGp)4oN|W!-|=~Bz4PFr(5X8jMK1wtoNe3vAXVhb?0!ubEml@%=x}@aWjfP z_4KskeFkUoA!>X+KzJH1E$s7}jA6V16SylsvZM$SgL3(Suw*?3Fqc~b+Ga+P>m9}V zOjqRV(WFyI@C^WJZx%%2F1hluElbO%gpkl3yY%qU$__nzgjos97qNl+FzQ#E@#8Ds zbn1*BKt7tXnHh6_-guf1$k_09XZdK8d+JktX3X-@=lH~6_tk|8=(whr4=OIce7kZEFiBGuWu8Ul8*Xi*+lb(t~U#VQZ zjDCFCz4oP!VcQDYvBEa&SZb$V|Ni$Y%RMWPy}WTE?utZQY>iKBeEHZ)&!*Pa!%LRX zJEAsw%sxCcG>i|M_O2sl<&gKxTq(mkT%-*(!X3xwZz0#u#EMV6Uzmsx_Tp`rw;jid z@1?)Rt47mUaUc2b@nYZ(tnb4LjF=HRf$=dytUXwftJ~H@h;xV#55}?Y210_rf=coU zq)Gh|A*l-x8(=G*le?FYmQ4iA4y*^)bm8}fKCJjn;TL$l`F28j&&6xH7ZNh??}Q9~ zhLE9?ge=%X$U>BF;WdOT`Wr$PDlJ~c!Ju46fBYUgYFwa@x_{eF%2t$p`)Kec=AYBeGz4D!{;CI315Qt{eNTsSJ?jttS?~wF4lXn zK7qBNJ!bE7|AZ_$-6X+9SvDQIntNUQl~*wf6iw2Le06Vg8C$t=^{!QKbn)6Po7VO9j}L4e+2i$1S&Kjq<6IMoqpub8BE$R@(PInHW20K`yxr)P)6xFN$vtS-|Ap?~LVS1w0S?$WM23;pyd@*VP0Jgi+g>ydMuptzfg=skPx61=^L{jr>V zyR|>|?DwL-zm5Af(xd^NoElx)fVpP0iQcJGXSH(}eMTY2n+G6xK5+yapZd0iY$YhLAN`BIM|MPjKi3pRz~^fBlq;7>MKDTg+C2!=l~JT)(Nw=`;{6ujae6vDl1Gt9C2QGSnB7%Vi|4cW<%UjV_yZ zI|Qus#q4$)iTmAKY<82|rroZ(WxI&(n~3M#TWpA*;kB<=Z1tO3yj~OWzI%(^Y4$p_ z+u7?kwfcN!;(PZNhs*49YPWOLZ))}X&BXuiEl#(^@6>MRsNdA4X)zywcE)iJao0ei z+*tjj-zCV_&cuwsHq}Ktt{sd)A%L8UBg25EBUQK4st_TU;!^0p1_IFrJ@cHA{S%Xu z@sVAV6O(baypE;x`s-P)Pm^fQp&Y~i4%lp*;E`6O+@cl7@PnX-1e literal 0 HcmV?d00001 diff --git a/CuckooChess/src/tui/Main.java b/CuckooChess/src/tui/Main.java new file mode 100644 index 0000000..4d01b9a --- /dev/null +++ b/CuckooChess/src/tui/Main.java @@ -0,0 +1,52 @@ +/* + 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 . +*/ + +package tui; + +import java.io.IOException; + +import chess.ComputerPlayer; +import chess.HumanPlayer; +import chess.Player; +import chess.TreeLogger; + +/** + * + * @author petero + */ +public class Main { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws IOException { + if ((args.length == 1) && args[0].equals("gui")) { + gui.AppletGUI.main(args); + } else if ((args.length == 1) && args[0].equals("txt")) { + Player whitePlayer = new HumanPlayer(); + ComputerPlayer blackPlayer = new ComputerPlayer(); + blackPlayer.setTTLogSize(21); + TUIGame game = new TUIGame(whitePlayer, blackPlayer); + game.play(); + } else if ((args.length == 2) && args[0].equals("tree")) { + TreeLogger.main(new String[]{args[1]}); + } else { + uci.UCIProtocol.main(false); + } + } +} diff --git a/CuckooChess/src/tui/TUIGame.java b/CuckooChess/src/tui/TUIGame.java new file mode 100644 index 0000000..ae304b1 --- /dev/null +++ b/CuckooChess/src/tui/TUIGame.java @@ -0,0 +1,216 @@ +/* + 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 . +*/ + +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 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); + } + } + } + } +} diff --git a/CuckooChess/src/uci/EngineControl.java b/CuckooChess/src/uci/EngineControl.java new file mode 100644 index 0000000..b38461e --- /dev/null +++ b/CuckooChess/src/uci/EngineControl.java @@ -0,0 +1,435 @@ +/* + 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 . +*/ + +package uci; + +import chess.Book; +import chess.ComputerPlayer; +import chess.Move; +import chess.MoveGen; +import chess.Parameters; +import chess.Piece; +import chess.Position; +import chess.Search; +import chess.TextIO; +import chess.TranspositionTable; +import chess.Parameters.CheckParam; +import chess.Parameters.ComboParam; +import chess.Parameters.ParamBase; +import chess.Parameters.SpinParam; +import chess.Parameters.StringParam; +import chess.TranspositionTable.TTEntry; +import chess.UndoInfo; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * Control the search thread. + * @author petero + */ +public class EngineControl { + PrintStream os; + + Thread engineThread; + private final Object threadMutex; + Search sc; + TranspositionTable tt; + MoveGen moveGen; + + Position pos; + long[] posHashList; + int posHashListSize; + boolean ponder; // True if currently doing pondering + boolean onePossibleMove; + boolean infinite; + + int minTimeLimit; + int maxTimeLimit; + int maxDepth; + int maxNodes; + List searchMoves; + + // Options + int hashSizeMB = 16; + boolean ownBook = false; + boolean analyseMode = false; + boolean ponderMode = true; + + // Reduced strength variables + int strength = 1000; + long randomSeed = 0; + + /** + * This class is responsible for sending "info" strings during search. + */ + private static class SearchListener implements Search.Listener { + PrintStream os; + + SearchListener(PrintStream os) { + this.os = os; + } + + public void notifyDepth(int depth) { + os.printf("info depth %d%n", depth); + } + + public void notifyCurrMove(Move m, int moveNr) { + os.printf("info currmove %s currmovenumber %d%n", moveToString(m), moveNr); + } + + public void notifyPV(int depth, int score, int time, int nodes, int nps, boolean isMate, + boolean upperBound, boolean lowerBound, ArrayList pv) { + StringBuilder pvBuf = new StringBuilder(); + for (Move m : pv) { + pvBuf.append(" "); + pvBuf.append(moveToString(m)); + } + String bound = ""; + if (upperBound) { + bound = " upperbound"; + } else if (lowerBound) { + bound = " lowerbound"; + } + os.printf("info depth %d score %s %d%s time %d nodes %d nps %d pv%s%n", + depth, isMate ? "mate" : "cp", score, bound, time, nodes, nps, pvBuf.toString()); + } + + public void notifyStats(int nodes, int nps, int time) { + os.printf("info nodes %d nps %d time %d%n", nodes, nps, time); + } + } + + public EngineControl(PrintStream os) { + this.os = os; + threadMutex = new Object(); + setupTT(); + moveGen = new MoveGen(); + } + + final public void startSearch(Position pos, ArrayList moves, SearchParams sPar) { + setupPosition(new Position(pos), moves); + computeTimeLimit(sPar); + ponder = false; + infinite = (maxTimeLimit < 0) && (maxDepth < 0) && (maxNodes < 0); + startThread(minTimeLimit, maxTimeLimit, maxDepth, maxNodes); + searchMoves = sPar.searchMoves; + } + + final public void startPonder(Position pos, List moves, SearchParams sPar) { + setupPosition(new Position(pos), moves); + computeTimeLimit(sPar); + ponder = true; + infinite = false; + startThread(-1, -1, -1, -1); + } + + final public void ponderHit() { + Search mySearch; + synchronized (threadMutex) { + mySearch = sc; + } + if (mySearch != null) { + if (onePossibleMove) { + if (minTimeLimit > 1) minTimeLimit = 1; + if (maxTimeLimit > 1) maxTimeLimit = 1; + } + mySearch.timeLimit(minTimeLimit, maxTimeLimit); + } + infinite = (maxTimeLimit < 0) && (maxDepth < 0) && (maxNodes < 0); + ponder = false; + } + + final public void stopSearch() { + stopThread(); + } + + final public void newGame() { + randomSeed = new Random().nextLong(); + tt.clear(); + } + + /** + * Compute thinking time for current search. + */ + final public void computeTimeLimit(SearchParams sPar) { + minTimeLimit = -1; + maxTimeLimit = -1; + maxDepth = -1; + maxNodes = -1; + if (sPar.infinite) { + minTimeLimit = -1; + maxTimeLimit = -1; + maxDepth = -1; + } else if (sPar.depth > 0) { + maxDepth = sPar.depth; + } else if (sPar.mate > 0) { + maxDepth = sPar.mate * 2 - 1; + } else if (sPar.moveTime > 0) { + minTimeLimit = maxTimeLimit = sPar.moveTime; + } else if (sPar.nodes > 0) { + maxNodes = sPar.nodes; + } else { + int moves = sPar.movesToGo; + if (moves == 0) { + moves = 999; + } + moves = Math.min(moves, 45); // Assume 45 more moves until end of game + if (ponderMode) { + final double ponderHitRate = 0.35; + moves = (int)Math.ceil(moves * (1 - ponderHitRate)); + } + boolean white = pos.whiteMove; + int time = white ? sPar.wTime : sPar.bTime; + int inc = white ? sPar.wInc : sPar.bInc; + final int margin = Math.min(1000, time * 9 / 10); + int timeLimit = (time + inc * (moves - 1) - margin) / moves; + minTimeLimit = (int)(timeLimit * 0.85); + maxTimeLimit = (int)(minTimeLimit * (Math.max(2.5, Math.min(4.0, moves / 2)))); + + // Leave at least 1s on the clock, but can't use negative time + minTimeLimit = clamp(minTimeLimit, 1, time - margin); + maxTimeLimit = clamp(maxTimeLimit, 1, time - margin); + } + } + + private static final int clamp(int val, int min, int max) { + if (val < min) { + return min; + } else if (val > max) { + return max; + } else { + return val; + } + } + + final private void startThread(final int minTimeLimit, final int maxTimeLimit, + int maxDepth, final int maxNodes) { + synchronized (threadMutex) {} // Must not start new search until old search is finished + sc = new Search(pos, posHashList, posHashListSize, tt); + sc.timeLimit(minTimeLimit, maxTimeLimit); + sc.setListener(new SearchListener(os)); + sc.setStrength(strength, randomSeed); + MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos); + MoveGen.removeIllegal(pos, moves); + if ((searchMoves != null) && (searchMoves.size() > 0)) { + Arrays.asList(moves.m).retainAll(searchMoves); + } + final MoveGen.MoveList srchMoves = moves; + onePossibleMove = false; + if ((srchMoves.size < 2) && !infinite) { + onePossibleMove = true; + if (!ponder) { + if ((maxDepth < 0) || (maxDepth > 2)) maxDepth = 2; + } + } + tt.nextGeneration(); + final int srchmaxDepth = maxDepth; + engineThread = new Thread(new Runnable() { + public void run() { + Move m = null; + if (ownBook && !analyseMode) { + Book book = new Book(false); + m = book.getBookMove(pos); + } + if (m == null) { + m = sc.iterativeDeepening(srchMoves, srchmaxDepth, maxNodes, false); + } + while (ponder || infinite) { + // We should not respond until told to do so. Just wait until + // we are allowed to respond. + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + break; + } + } + Move ponderMove = getPonderMove(pos, m); + synchronized (threadMutex) { + if (ponderMove != null) { + os.printf("bestmove %s ponder %s%n", moveToString(m), moveToString(ponderMove)); + } else { + os.printf("bestmove %s%n", moveToString(m)); + } + engineThread = null; + sc = null; + } + } + }); + engineThread.start(); + } + + private final void stopThread() { + Thread myThread; + Search mySearch; + synchronized (threadMutex) { + myThread = engineThread; + mySearch = sc; + } + if (myThread != null) { + mySearch.timeLimit(0, 0); + infinite = false; + ponder = false; + try { + myThread.join(); + } catch (InterruptedException ex) { + throw new RuntimeException(); + } + } + } + + + private final void setupTT() { + int nEntries = hashSizeMB > 0 ? hashSizeMB * (1 << 20) / 24 : 1024; + int logSize = (int) Math.floor(Math.log(nEntries) / Math.log(2)); + tt = new TranspositionTable(logSize); + } + + private final void setupPosition(Position pos, List moves) { + UndoInfo ui = new UndoInfo(); + posHashList = new long[200 + moves.size()]; + posHashListSize = 0; + for (Move m : moves) { + posHashList[posHashListSize++] = pos.zobristHash(); + pos.makeMove(m, ui); + } + this.pos = pos; + } + + /** + * Try to find a move to ponder from the transposition table. + */ + private final Move getPonderMove(Position pos, Move m) { + if (m == null) return null; + Move ret = null; + UndoInfo ui = new UndoInfo(); + pos.makeMove(m, ui); + TTEntry ent = tt.probe(pos.historyHash()); + if (ent.type != TTEntry.T_EMPTY) { + ret = new Move(0, 0, 0); + ent.getMove(ret); + MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos); + MoveGen.removeIllegal(pos, moves); + boolean contains = false; + for (int mi = 0; mi < moves.size; mi++) + if (moves.m[mi].equals(ret)) { + contains = true; + break; + } + if (!contains) + ret = null; + } + pos.unMakeMove(m, ui); + return ret; + } + + private static final String moveToString(Move m) { + if (m == null) + return "0000"; + String ret = TextIO.squareToString(m.from); + ret += TextIO.squareToString(m.to); + switch (m.promoteTo) { + case Piece.WQUEEN: + case Piece.BQUEEN: + ret += "q"; + break; + case Piece.WROOK: + case Piece.BROOK: + ret += "r"; + break; + case Piece.WBISHOP: + case Piece.BBISHOP: + ret += "b"; + break; + case Piece.WKNIGHT: + case Piece.BKNIGHT: + ret += "n"; + break; + default: + break; + } + return ret; + } + + static void printOptions(PrintStream os) { + os.printf("option name Hash type spin default 16 min 1 max 2048%n"); + os.printf("option name OwnBook type check default false%n"); + os.printf("option name Ponder type check default true%n"); + os.printf("option name UCI_AnalyseMode type check default false%n"); + os.printf("option name UCI_EngineAbout type string default %s by Peter Osterlund, see http://web.comhem.se/petero2home/javachess/index.html%n", + ComputerPlayer.engineName); + os.printf("option name Strength type spin default 1000 min 0 max 1000\n"); + + for (String pName : Parameters.instance().getParamNames()) { + ParamBase p = Parameters.instance().getParam(pName); + switch (p.type) { + case CHECK: { + CheckParam cp = (CheckParam)p; + os.printf("optionn name %s type check default %s\n", + p.name, cp.defaultValue?"true":"false"); + break; + } + case SPIN: { + SpinParam sp = (SpinParam)p; + os.printf("option name %s type spin default %d min %d max %d\n", + p.name, sp.defaultValue, sp.minValue, sp.maxValue); + break; + } + case COMBO: { + ComboParam cp = (ComboParam)p; + os.printf("option name %s type combo default %s ", cp.name, cp.defaultValue); + for (String s : cp.allowedValues) + os.printf(" var %s", s); + os.printf("\n"); + break; + } + case BUTTON: + os.printf("option name %s type button\n", p.name); + break; + case STRING: { + StringParam sp = (StringParam)p; + os.printf("option name %s type string default %s\n", + p.name, sp.defaultValue); + break; + } + } + } + } + + final void setOption(String optionName, String optionValue) { + try { + if (optionName.equals("hash")) { + hashSizeMB = Integer.parseInt(optionValue); + setupTT(); + } else if (optionName.equals("ownbook")) { + ownBook = Boolean.parseBoolean(optionValue); + } else if (optionName.equals("ponder")) { + ponderMode = Boolean.parseBoolean(optionValue); + } else if (optionName.equals("uci_analysemode")) { + analyseMode = Boolean.parseBoolean(optionValue); + } else if (optionName.equals("strength")) { + strength = Integer.parseInt(optionValue); + } else { + Parameters.instance().set(optionName, optionValue); + } + } catch (NumberFormatException nfe) { + } + } +} diff --git a/CuckooChess/src/uci/SearchParams.java b/CuckooChess/src/uci/SearchParams.java new file mode 100644 index 0000000..6e5866f --- /dev/null +++ b/CuckooChess/src/uci/SearchParams.java @@ -0,0 +1,45 @@ +/* + 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 . +*/ + +package uci; + +import chess.Move; +import java.util.ArrayList; +import java.util.List; + +/** + * Store search parameters (times, increments, max depth, etc). + * @author petero + */ +public class SearchParams { + List searchMoves; // If non-empty, search only these moves + int wTime; // White remaining time, ms + int bTime; // Black remaining time, ms + int wInc; // White increment per move, ms + int bInc; // Black increment per move, ms + int movesToGo; // Moves to next time control + int depth; // If >0, don't search deeper than this + int nodes; // If >0, don't search more nodes than this + int mate; // If >0, search for mate-in-x + int moveTime; // If >0, search for exactly this amount of time, ms + boolean infinite; + + public SearchParams() { + searchMoves = new ArrayList(); + } +} diff --git a/CuckooChess/src/uci/UCIProtocol.java b/CuckooChess/src/uci/UCIProtocol.java new file mode 100644 index 0000000..4c8a5f7 --- /dev/null +++ b/CuckooChess/src/uci/UCIProtocol.java @@ -0,0 +1,222 @@ +/* + 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 . +*/ + +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. + * @author petero + */ +public class UCIProtocol { + // Data set by the "position" command. + Position pos; + ArrayList 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(); + 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+"); + } +} diff --git a/CuckooChess/test/uci/UCIProtocolTest.java b/CuckooChess/test/uci/UCIProtocolTest.java new file mode 100644 index 0000000..b29a4b4 --- /dev/null +++ b/CuckooChess/test/uci/UCIProtocolTest.java @@ -0,0 +1,68 @@ +/* + 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 . +*/ + +package uci; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author petero + */ +public class UCIProtocolTest { + + public UCIProtocolTest() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of tokenize method, of class UCIProtocol. + */ + @Test + public void testTokenize() { + System.out.println("tokenize"); + UCIProtocol uci = new UCIProtocol(); + String[] result = uci.tokenize(" a b c de \t \t fgh"); + assertEquals(5, result.length); + assertEquals("a", result[0]); + assertEquals("b", result[1]); + assertEquals("c", result[2]); + assertEquals("de", result[3]); + assertEquals("fgh", result[4]); + } +}