Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next: Support Switch Multiple Engine Heights #368

Merged
merged 2 commits into from
Oct 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,6 @@
<useFile>false</useFile>
</configuration>
</plugin>
<plugin>
<groupId>com.coveo</groupId>
<artifactId>fmt-maven-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Expand Down
49 changes: 49 additions & 0 deletions src/main/java/featurecat/lizzie/Lizzie.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import java.io.File;
import java.io.IOException;
import javax.swing.*;
import org.json.JSONArray;
import org.json.JSONException;

/** Main class. */
public class Lizzie {
Expand Down Expand Up @@ -80,4 +82,51 @@ public static void shutdown() {
if (leelaz != null) leelaz.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 @@ -74,4 +75,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;
}
}
}
113 changes: 107 additions & 6 deletions src/main/java/featurecat/lizzie/analysis/Leelaz.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
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;
import javax.swing.*;
import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -55,6 +60,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 @@ -73,7 +87,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 @@ -82,13 +97,44 @@ 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;
}

File startfolder = new File(config.optString("engine-start-location", "."));
String engineCommand = config.getString("engine-command");
String networkFile = config.getString("network-file");
// substitute in the weights file
engineCommand = engineCommand.replaceAll("%network-file", networkFile);
// 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];
}
}
}
}

// Check if engine is present
File lef = startfolder.toPath().resolve(new File(commands.get(0)).toPath()).toFile();
Expand Down Expand Up @@ -123,8 +169,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 @@ -201,6 +281,10 @@ private void parseLine(String line) {
// 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 @@ -301,7 +385,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 @@ -568,4 +653,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 @@ -342,6 +342,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
35 changes: 31 additions & 4 deletions src/main/java/featurecat/lizzie/gui/LizzieFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ public class LizzieFrame extends JFrame {

private long lastAutosaveTime = System.currentTimeMillis();

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

// Display Comment
private JScrollPane scrollPane = null;
private JTextPane commentPane = null;
Expand Down Expand Up @@ -436,8 +439,11 @@ public void paint(Graphics g0) {

if (Lizzie.leelaz != null && Lizzie.leelaz.isLoaded()) {
if (Lizzie.config.showStatus) {
String key = "LizzieFrame.display." + (Lizzie.leelaz.isPondering() ? "on" : "off");
String text = resourceBundle.getString(key);
String pondKey = "LizzieFrame.display." + (Lizzie.leelaz.isPondering() ? "on" : "off");
String pondText = resourceBundle.getString(pondKey);
String switchText = resourceBundle.getString("LizzieFrame.prompt.switching");
String weightText = Lizzie.leelaz.currentWeight().toString();
String text = pondText + " " + weightText + (Lizzie.leelaz.switching() ? switchText : "");
drawPonderingState(g, text, ponderingX, ponderingY, ponderingSize);
}

Expand Down Expand Up @@ -545,6 +551,17 @@ private void drawPonderingState(Graphics2D g, String text, int x, int y, double
Font font = new Font(systemDefaultFontName, Font.PLAIN, fontSize);
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 @@ -1017,7 +1034,16 @@ 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 @@ -1039,7 +1065,8 @@ public boolean incrementDisplayedBranchLength(int n) {
}

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

public void copySgf() {
Expand Down
Loading