Skip to content

Commit

Permalink
Support Switch Multiple Engine Heights
Browse files Browse the repository at this point in the history
  • Loading branch information
zsalch authored and zsalch committed Oct 4, 2018
1 parent f274469 commit d475ad7
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 16 deletions.
43 changes: 42 additions & 1 deletion src/main/java/featurecat/lizzie/Lizzie.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package featurecat.lizzie;

import org.json.JSONArray;
import org.json.JSONException;
import featurecat.lizzie.analysis.Leelaz;
import featurecat.lizzie.plugin.PluginManager;
Expand Down Expand Up @@ -56,7 +57,7 @@ public static void main(String[] args) throws IOException, JSONException, ClassN
try {
leelaz = new Leelaz();
if(config.handicapInsteadOfWinrate) {
leelaz.estimatePassWinrate();
leelaz.estimatePassWinrate();
}
if (args.length == 1) {
frame.loadFile(new File(args[0]));
Expand Down Expand Up @@ -95,4 +96,44 @@ public static void shutdown() {
System.exit(0);
}

/**
* Switch the Engine by index number
* @param index engine index
*/
public static void switchEngine(int index) {

String commandLine = null;
if (index == 0) {
commandLine = Lizzie.config.leelazConfig.getString("engine-command");
commandLine = commandLine.replaceAll("%network-file", Lizzie.config.leelazConfig.getString("network-file"));
} else {
JSONArray commandList = Lizzie.config.leelazConfig.getJSONArray("engine-command-list");
if (commandList != null && commandList.length() >= index) {
commandLine = commandList.getString(index - 1);
} else {
index = -1;
}
}
if (index < 0 || commandLine == null || commandLine.trim().isEmpty() || index == Lizzie.leelaz.currentEngineN()) {
return;
}

// Workaround for leelaz cannot exit when restarting
if (leelaz.isThinking) {
if (Lizzie.frame.isPlayingAgainstLeelaz) {
Lizzie.frame.isPlayingAgainstLeelaz = false;
Lizzie.leelaz.togglePonder(); // we must toggle twice for it to restart pondering
Lizzie.leelaz.isThinking = false;
}
Lizzie.leelaz.togglePonder();
}

board.saveMoveNumber();
try {
leelaz.restartEngine(commandLine, index);
board.restoreMoveNumber();
} catch (IOException e) {
e.printStackTrace();
}
}
}
33 changes: 33 additions & 0 deletions src/main/java/featurecat/lizzie/Util.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package featurecat.lizzie;

import java.awt.FontMetrics;
import java.io.*;
import java.net.URL;
import java.nio.channels.Channels;
Expand Down Expand Up @@ -80,4 +81,36 @@ public static void saveAsFile(URL url, File file) {
e.printStackTrace();
}
}

/**
* Truncate text that is too long for the given width
*
* @param line
* @param fm
* @param fitWidth
* @return fitted
*/
public static String truncateStringByWidth(String line, FontMetrics fm, int fitWidth) {
if (line == null || line.length() == 0) {
return "";
}
int width = fm.stringWidth(line);
if (width > fitWidth) {
int guess = line.length() * fitWidth / width;
String before = line.substring(0, guess).trim();
width = fm.stringWidth(before);
if (width > fitWidth) {
int diff = width - fitWidth;
int i = 0;
for (; (diff > 0 && i < 5); i++) {
diff = diff - fm.stringWidth(line.substring(guess - i - 1, guess - i));
}
return line.substring(0, guess - i).trim();
} else {
return before;
}
} else {
return line;
}
}
}
116 changes: 106 additions & 10 deletions src/main/java/featurecat/lizzie/analysis/Leelaz.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import java.net.URL;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -60,6 +63,15 @@ public class Leelaz {
private boolean isLoaded = false;
private boolean isCheckingVersion;

// for Multiple Engine
private String engineCommand = null;
private List<String> commands = null;
private JSONObject config = null;
private String currentWeight = null;
private boolean switching = false;
private int currentEngineN = -1;
private ScheduledExecutorService executor = null;

// dynamic komi and opponent komi as reported by dynamic-komi version of leelaz
private float dynamicKomi = Float.NaN, dynamicOppKomi = Float.NaN;
/**
Expand All @@ -78,7 +90,8 @@ public Leelaz() throws IOException, JSONException {
currentCmdNum = 0;
cmdQueue = new ArrayDeque<>();

JSONObject config = Lizzie.config.config.getJSONObject("leelaz");
// Move config to member for other method call
config = Lizzie.config.config.getJSONObject("leelaz");

printCommunication = config.getBoolean("print-comms");
maxAnalyzeTimeMillis = MINUTE * config.getInt("max-analyze-time-minutes");
Expand All @@ -87,6 +100,24 @@ public Leelaz() throws IOException, JSONException {
updateToLatestNetwork();
}


// command string for starting the engine
engineCommand = config.getString("engine-command");
// substitute in the weights file
engineCommand = engineCommand.replaceAll("%network-file", config.getString("network-file"));

// Initialize current engine number and start engine
currentEngineN = 0;
startEngine(engineCommand);
Lizzie.frame.refreshBackground();
}

public void startEngine(String engineCommand) throws IOException {
// Check engine command
if (engineCommand == null || engineCommand.trim().isEmpty()) {
return;
}

String startfolder = new File(Config.getBestDefaultLeelazPath()).getParent(); // todo make this a little more obvious/less bug-prone

// Check if network file is present
Expand All @@ -95,13 +126,23 @@ public Leelaz() throws IOException, JSONException {
JOptionPane.showMessageDialog(null, resourceBundle.getString("LizzieFrame.display.network-missing"));
}


// command string for starting the engine
String engineCommand = config.getString("engine-command");
// substitute in the weights file
engineCommand = engineCommand.replaceAll("%network-file", config.getString("network-file"));
// create this as a list which gets passed into the processbuilder
List<String> commands = Arrays.asList(engineCommand.split(" "));
commands = Arrays.asList(engineCommand.split(" "));

// get weight name
if (engineCommand != null) {
Pattern wPattern = Pattern.compile("(?s).*?(--weights |-w )([^ ]+)(?s).*");
Matcher wMatcher = wPattern.matcher(engineCommand);
if (wMatcher.matches()) {
currentWeight = wMatcher.group(2);
if (currentWeight != null) {
String[] names = currentWeight.split("[\\\\|/]");
if (names != null && names.length > 1) {
currentWeight = names[names.length - 1];
}
}
}
}

// run leelaz
ProcessBuilder processBuilder = new ProcessBuilder(commands);
Expand All @@ -117,8 +158,42 @@ public Leelaz() throws IOException, JSONException {
sendCommand("version");

// start a thread to continuously read Leelaz output
new Thread(this::read).start();
Lizzie.frame.refreshBackground();
//new Thread(this::read).start();
//can stop engine for switching weights
executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(this::read);
}

public void restartEngine(String engineCommand, int index) throws IOException {
if (engineCommand == null || engineCommand.trim().isEmpty()) {
return;
}
switching = true;
this.engineCommand = engineCommand;
// stop the ponder
if (Lizzie.leelaz.isPondering()) {
Lizzie.leelaz.togglePonder();
}
normalQuit();
startEngine(engineCommand);
currentEngineN = index;
togglePonder();
}

public void normalQuit() {
sendCommand("quit");
executor.shutdown();
try {
while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
if (executor.awaitTermination(1, TimeUnit.SECONDS)) {
shutdown();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}

private void updateToLatestNetwork() {
Expand Down Expand Up @@ -204,6 +279,10 @@ else if (line.equals("\n")) {
// End of response
} else if (line.startsWith("info")) {
isLoaded = true;
// Clear switching prompt
switching = false;
// Display engine command in the title
if (Lizzie.frame != null) Lizzie.frame.updateTitle();
if (isResponseUpToDate()) {
// This should not be stale data when the command number match
parseInfo(line.substring(5));
Expand Down Expand Up @@ -294,7 +373,8 @@ private void read() {
System.out.println("Leelaz process ended.");

shutdown();
System.exit(-1);
// Do no exit for switching weights
//System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
Expand Down Expand Up @@ -561,4 +641,20 @@ private synchronized void notifyBestMoveListeners() {
public boolean isLoaded() {
return isLoaded;
}

public String currentWeight() {
return currentWeight;
}

public boolean switching() {
return switching;
}

public int currentEngineN() {
return currentEngineN;
}

public String engineCommand() {
return this.engineCommand;
}
}
15 changes: 15 additions & 0 deletions src/main/java/featurecat/lizzie/gui/Input.java
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,21 @@ public void keyPressed(KeyEvent e) {
toggleShowDynamicKomi();
break;

// Use Ctrl+Num to switching multiple engine
case VK_0:
case VK_1:
case VK_2:
case VK_3:
case VK_4:
case VK_5:
case VK_6:
case VK_7:
case VK_8:
case VK_9:
if (controlIsPressed(e)) {
Lizzie.switchEngine(e.getKeyCode() - VK_0);
}
break;
default:
shouldDisableAnalysis = false;
}
Expand Down
29 changes: 25 additions & 4 deletions src/main/java/featurecat/lizzie/gui/LizzieFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ public class LizzieFrame extends JFrame {

private long lastAutosaveTime = System.currentTimeMillis();

// Save the player title
private String playerTitle = null;

static {
// load fonts
try {
Expand Down Expand Up @@ -395,8 +398,10 @@ public void paint(Graphics g0) {

if (Lizzie.leelaz != null && Lizzie.leelaz.isLoaded()) {
if (Lizzie.config.showStatus) {
// Display switching prompt
drawPonderingState(g, resourceBundle.getString("LizzieFrame.display.pondering") +
(Lizzie.leelaz.isPondering()?resourceBundle.getString("LizzieFrame.display.on"):resourceBundle.getString("LizzieFrame.display.off")),
(Lizzie.leelaz.isPondering()?resourceBundle.getString("LizzieFrame.display.on"):resourceBundle.getString("LizzieFrame.display.off")) +
" " + Lizzie.leelaz.currentWeight() + (Lizzie.leelaz.switching() ? resourceBundle.getString("LizzieFrame.prompt.switching") : ""),
ponderingX, ponderingY, ponderingSize);
}

Expand Down Expand Up @@ -491,6 +496,14 @@ private void drawPonderingState(Graphics2D g, String text, int x, int y, double
Font font = new Font(systemDefaultFontName, Font.PLAIN, (int)(Math.max(getWidth(), getHeight()) * size));
FontMetrics fm = g.getFontMetrics(font);
int stringWidth = fm.stringWidth(text);
// Truncate too long text when display switching prompt
if (Lizzie.leelaz.isLoaded()) {
int mainBoardX = (boardRenderer != null && boardRenderer.getLocation() != null) ? boardRenderer.getLocation().x : 0;
if ((mainBoardX > x) && stringWidth > (mainBoardX - x) ) {
text = Util.truncateStringByWidth(text, fm, mainBoardX - x);
stringWidth = fm.stringWidth(text);
}
}
int stringHeight = fm.getAscent() - fm.getDescent();
int width = stringWidth;
int height = (int)(stringHeight * 1.2);
Expand Down Expand Up @@ -881,8 +894,15 @@ public void toggleCoordinates() {
}

public void setPlayers(String whitePlayer, String blackPlayer) {
setTitle(String.format("%s (%s [W] vs %s [B])", DEFAULT_TITLE,
whitePlayer, blackPlayer));
this.playerTitle = String.format("(%s [W] vs %s [B])", whitePlayer, blackPlayer);
this.updateTitle();
}

public void updateTitle() {
StringBuilder sb = new StringBuilder(DEFAULT_TITLE);
sb.append(this.playerTitle != null ? " " + this.playerTitle.trim() : "");
sb.append(Lizzie.leelaz.engineCommand() != null ? " [" + Lizzie.leelaz.engineCommand() + "]" : "");
setTitle(sb.toString());
}

private void setDisplayedBranchLength(int n) {
Expand All @@ -904,7 +924,8 @@ public boolean incrementDisplayedBranchLength(int n) {
}

public void resetTitle() {
setTitle(DEFAULT_TITLE);
this.playerTitle = null;
this.updateTitle();
}

public void copySgf() {
Expand Down
Loading

0 comments on commit d475ad7

Please sign in to comment.