Skip to content

Commit

Permalink
Adds the gameCount system property to help making engines fights
Browse files Browse the repository at this point in the history
  • Loading branch information
fathzer committed Mar 19, 2024
1 parent c7e4550 commit eedd560
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Java 17+ to run the application and mvn to build it.
## How to launch the swing application
```java -jar ./target/jchess.jar```

## Where are the pgn of games saved?
The application saves the pgn of games in ```./data/pgn```. THis folder will contain one file per day.

## How to add external [UCI](https://gist.github.com/DOBRO/2592c6dad754ba67e6dcaec8c90165bf) engines to the engines list
Add a json file named *engines.json* in the *data* folder using the following example:

Expand All @@ -33,11 +36,21 @@ Add a json file named *engines.json* in the *data* folder using the following ex

Please note that engines should have different names, if not, only the first engine will have its original name, next will have a changed names (the original name followed by a suffix). The name *JChess* is reserved for the internal engine; If it is used for an external engine, this engine name will have a suffix like duplicated ones.

# Tips and hints
Warning, the tips in this section may not be maintained... Use it at your own risk.

## How to make multiple games between two engines.
By default, at the end of a game, the user is asked for making a revenge or ends playing.
If you specify a value for the *gameCount* system property while starting the application. The application will make *gameCount* games without asking the user if it want to continue.


# Known bugs
- When a engine used in player settings hangs, it leaves settings in a wrong state with no possibility to fix it; The application should be restarted.
- When a engine that is used in player settings hangs, it leaves settings in a wrong state with no possibility to fix it; The application should be restarted.
- When a human looses against an engine because its allocated time is elapsed, and it decides to continue the game, the bot never moves again (it receives a negative time counter ... which is strange).

# TODO
- Allow engine settings to be defined in engines.json or save engine settings in preferences.
- PGN should contain
- Implement a way to play again on missclick.
- Implement PGN game loading
- Implement move backward/forward in the game.
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/fathzer/jchess/bot/uci/UCIEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ public class UCIEngine implements Engine {
private boolean expectedRunning;

public UCIEngine(EngineData data) throws IOException {
log.info ("Launching process {}", Arrays.asList(data.getCommand()));
log.info ("Launching engine {} with {}", data.getName(), Arrays.asList(data.getCommand()));
this.data = data;
final ProcessBuilder processBuilder = new ProcessBuilder(data.getCommand());
this.process = processBuilder.start();
log.info("Engine {} process id is {}", data.getName(), process.pid());
this.expectedRunning = true;
this.reader = process.inputReader();
this.writer = process.outputWriter();
Expand Down
46 changes: 42 additions & 4 deletions src/main/java/com/fathzer/jchess/swing/GameSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public enum State {
private Color player1Color;
private Observable<State> state;
private Game game;
private long lastMoveTime = 0;

public GameSession(GamePanel panel, GameSettings settings) {
this.panel = panel;
Expand Down Expand Up @@ -106,6 +107,7 @@ private void initGame() {
panel.getBoard().setBoard(game.getBoard());
panel.getBoard().setManualMoveEnabled(false);
setScore();
lastMoveTime = System.currentTimeMillis();
}

private Clock buildClock() {
Expand Down Expand Up @@ -204,13 +206,16 @@ private void setState(State state) {
private void onMove(Move move) {
panel.repaint();
this.game.onMove(move);
//TODO think(5000);
final Status status = panel.getBoard().getStatus();
if (!Status.PLAYING.equals(status)) {
// Game is ended
endOfGame(status);
} else {
setScore();
nextMove();
if (getState()==State.RUNNING) {
nextMove();
}
}
}

Expand All @@ -219,6 +224,32 @@ private void setScore() {
ev.init(game.getBoard());
panel.setScore(ev.evaluateAsWhite(game.getBoard())/100);
}

// This makes, always when two bots are competing, and sometime when human plays against a bot,
// closing the window not exiting the application (and not closing the engine's process)
//TODO Should be investigated
@SuppressWarnings("unused")
private void think(long thinkTime) {
final long remaining = thinkTime - (System.currentTimeMillis() - lastMoveTime);
if (remaining>0) {
game.pause();
SwingUtilities.invokeLater(() -> {
System.out.println("Will wait for "+remaining+"ms");
try {
synchronized (this) {
this.wait(remaining);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
lastMoveTime = System.currentTimeMillis();
game.start();
});
} else {
lastMoveTime = System.currentTimeMillis();
}
}


/** This method is called when clock emits a time up event.
* <br>Please note that this method could be invoked on a thread that is not the Swing event thread.
Expand Down Expand Up @@ -264,9 +295,16 @@ private void endOfGame(final Status status) {
} catch (Exception e) {
log.error("An error occured while writing pgn",e);
}
final String revenge = "Revenge";
int choice = JOptionPane.showOptionDialog(panel, getMessage(status), "End of game", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, new String[] {revenge,"Enough for today"}, revenge);
if (choice==0) {
final Integer toPlay = Integer.getInteger("gameCount");
boolean makeRevenge;
if (toPlay==null) {
final String revenge = "Revenge";
int choice = JOptionPane.showOptionDialog(panel, getMessage(status), "End of game", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, new String[] {revenge,"Enough for today"}, revenge);
makeRevenge = choice==0;
} else {
makeRevenge = gameCount+1<toPlay;
}
if (makeRevenge) {
doRevenge();
} else {
setState(State.ENDED);
Expand Down

0 comments on commit eedd560

Please sign in to comment.