Skip to content

Commit

Permalink
Support use different color to indicate move blunder in variation
Browse files Browse the repository at this point in the history
  • Loading branch information
zsalch committed Oct 31, 2018
1 parent 69fd2a1 commit e294275
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 21 deletions.
20 changes: 20 additions & 0 deletions src/main/java/featurecat/lizzie/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.json.*;

public class Config {
Expand Down Expand Up @@ -56,6 +58,11 @@ public class Config {
public Color winrateMissLineColor = null;
public Color blunderBarColor = null;
public boolean solidStoneIndicator = false;
public boolean showCommentNodeColor = true;
public Color commentNodeColor = null;
public Optional<List<Double>> blunderWinrateThresholds;
public Optional<Map<Double, Color>> blunderNodeColors;
public int nodeColorMode = 0;

private JSONObject loadAndMergeConfig(
JSONObject defaultCfg, String fileName, boolean needValidation) throws IOException {
Expand Down Expand Up @@ -170,6 +177,11 @@ public Config() throws IOException {
winrateMissLineColor = theme.winrateMissLineColor();
blunderBarColor = theme.blunderBarColor();
solidStoneIndicator = theme.solidStoneIndicator();
showCommentNodeColor = theme.showCommentNodeColor();
commentNodeColor = theme.commentNodeColor();
blunderWinrateThresholds = theme.blunderWinrateThresholds();
blunderNodeColors = theme.blunderNodeColors();
nodeColorMode = theme.nodeColorMode();
}

// Modifies config by adding in values from default_config that are missing.
Expand Down Expand Up @@ -201,6 +213,10 @@ public void toggleShowMoveNumber() {
this.showMoveNumber = !this.showMoveNumber;
}

public void toggleNodeColorMode() {
this.nodeColorMode = this.nodeColorMode > 1 ? 0 : this.nodeColorMode + 1;
}

public void toggleShowBranch() {
this.showBranch = !this.showBranch;
}
Expand All @@ -221,6 +237,10 @@ public void toggleShowComment() {
this.showComment = !this.showComment;
}

public void toggleShowCommentNodeColor() {
this.showCommentNodeColor = !this.showCommentNodeColor;
}

public void toggleShowBestMoves() {
this.showBestMoves = !this.showBestMoves;
}
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/featurecat/lizzie/gui/Input.java
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,15 @@ public void keyPressed(KeyEvent e) {
break;

case VK_T:
Lizzie.config.toggleShowComment();
if (controlIsPressed(e)) {
Lizzie.config.toggleShowCommentNodeColor();
} else {
Lizzie.config.toggleShowComment();
}
break;

case VK_Y:
Lizzie.config.toggleNodeColorMode();
break;

case VK_C:
Expand Down
57 changes: 56 additions & 1 deletion src/main/java/featurecat/lizzie/gui/LizzieFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import featurecat.lizzie.analysis.Leelaz;
import featurecat.lizzie.rules.Board;
import featurecat.lizzie.rules.BoardData;
import featurecat.lizzie.rules.BoardHistoryNode;
import featurecat.lizzie.rules.GIBParser;
import featurecat.lizzie.rules.SGFParser;
import java.awt.*;
Expand Down Expand Up @@ -71,8 +72,11 @@ public class LizzieFrame extends JFrame {
resourceBundle.getString("LizzieFrame.commands.keyF"),
resourceBundle.getString("LizzieFrame.commands.keyV"),
resourceBundle.getString("LizzieFrame.commands.keyW"),
resourceBundle.getString("LizzieFrame.commands.keyCtrlW"),
resourceBundle.getString("LizzieFrame.commands.keyG"),
resourceBundle.getString("LizzieFrame.commands.keyT"),
resourceBundle.getString("LizzieFrame.commands.keyCtrlT"),
resourceBundle.getString("LizzieFrame.commands.keyY"),
resourceBundle.getString("LizzieFrame.commands.keyHome"),
resourceBundle.getString("LizzieFrame.commands.keyEnd"),
resourceBundle.getString("LizzieFrame.commands.keyControl"),
Expand Down Expand Up @@ -657,7 +661,7 @@ void drawControls() {
Graphics2D g = cachedImage.createGraphics();

int maxSize = min(getWidth(), getHeight());
Font font = new Font(Lizzie.config.fontName, Font.PLAIN, (int) (maxSize * 0.034));
Font font = new Font(Lizzie.config.fontName, Font.PLAIN, (int) (maxSize * 0.03));
g.setFont(font);

FontMetrics metrics = g.getFontMetrics(font);
Expand Down Expand Up @@ -1177,4 +1181,55 @@ private int drawComment(Graphics2D g, int x, int y, int w, int h, boolean full)
cachedComment = comment;
return cHeight;
}

public double lastWinrateDiff(BoardHistoryNode node) {

// Last winrate
BoardData lastData = node.previous().get().getData();
boolean validLastWinrate = (lastData != null && lastData.playouts > 0);
double lastWR = validLastWinrate ? lastData.winrate : 50;

// Current winrate
BoardData data = node.getData();
boolean validWinrate = false;
double curWR = 50;
if (data == Lizzie.board.getHistory().getData()) {
Leelaz.WinrateStats stats = Lizzie.leelaz.getWinrateStats();
curWR = stats.maxWinrate;
validWinrate = (stats.totalPlayouts > 0);
if (isPlayingAgainstLeelaz
&& playerIsBlack == !Lizzie.board.getHistory().getData().blackToPlay) {
validWinrate = false;
}
} else {
validWinrate = (data.playouts > 0);
curWR = validWinrate ? data.winrate : 100 - lastWR;
}

// Last move difference winrate
if (validLastWinrate && validWinrate) {
return 100 - lastWR - curWR;
} else {
return 0;
}
}

public Color getBlunderNodeColor(BoardHistoryNode node) {
if (Lizzie.config.nodeColorMode == 1 && node.getData().blackToPlay
|| Lizzie.config.nodeColorMode == 2 && !node.getData().blackToPlay) {
return Color.WHITE;
}
double diffWinrate = lastWinrateDiff(node);
Optional<Double> st =
diffWinrate >= 0
? Lizzie.config.blunderWinrateThresholds.flatMap(
l -> l.stream().filter(t -> (t > 0 && t <= diffWinrate)).reduce((f, s) -> s))
: Lizzie.config.blunderWinrateThresholds.flatMap(
l -> l.stream().filter(t -> (t < 0 && t >= diffWinrate)).reduce((f, s) -> f));
if (st.isPresent()) {
return Lizzie.config.blunderNodeColors.map(m -> m.get(st.get())).get();
} else {
return Color.WHITE;
}
}
}
87 changes: 68 additions & 19 deletions src/main/java/featurecat/lizzie/gui/VariationTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public class VariationTree {
private int YSPACING;
private int XSPACING;
private int DOT_DIAM = 11; // Should be odd number
private int DOT_DIAM_S = 9; // For small node
private int CENTER_DIAM = 5;
private int RING_DIAM = 15;
private int diam = DOT_DIAM;

private ArrayList<Integer> laneUsageList;
private int laneCount = 0;
Expand Down Expand Up @@ -55,47 +59,68 @@ public void drawTree(
BoardHistoryNode cur = startNode;
int curposx = posx + lane * XSPACING;
int dotoffset = DOT_DIAM / 2;
if (Lizzie.config.nodeColorMode == 1 && cur.getData().blackToPlay
|| Lizzie.config.nodeColorMode == 2 && !cur.getData().blackToPlay) {
diam = DOT_DIAM_S;
} else {
diam = DOT_DIAM;
}
int dotoffsety = diam / 2;
int diff = (DOT_DIAM - diam) / 2;

// Draw line back to main branch
if (lane > 0) {

// Draw line back to main branch
if (lane - startLane > 0 || variationNumber > 1) {
// Need a horizontal and an angled line
drawLine(
g,
curposx + dotoffset,
posy + dotoffset,
posy + dotoffsety,
curposx + dotoffset - XSPACING,
posy + dotoffset - YSPACING,
posy + dotoffsety - YSPACING,
minposx);
drawLine(
g,
posx + (startLane - variationNumber) * XSPACING + 2 * dotoffset,
posy - YSPACING + dotoffset,
posy - YSPACING + dotoffsety,
curposx + dotoffset - XSPACING,
posy + dotoffset - YSPACING,
posy + dotoffsety - YSPACING,
minposx);
} else {
// Just an angled line
drawLine(
g,
curposx + dotoffset,
posy + dotoffset,
posy + dotoffsety,
curposx + 2 * dotoffset - XSPACING,
posy + 2 * dotoffset - YSPACING,
posy + 2 * dotoffsety - YSPACING,
minposx);
}
}

// Draw all the nodes and lines in this lane (not variations)
Color curcolor = g.getColor();
if (curposx > minposx && posy > 0) {
if (startNode == curMove) {
g.setColor(Color.green.brighter().brighter());
}
if (startNode.previous().isPresent()) {
g.fillOval(curposx, posy, DOT_DIAM, DOT_DIAM);
g.setColor(Color.BLACK);
g.drawOval(curposx, posy, DOT_DIAM, DOT_DIAM);
if (Lizzie.config.showCommentNodeColor && !cur.getData().comment.isEmpty()) {
g.setColor(Lizzie.config.commentNodeColor);
g.fillOval(
curposx + (DOT_DIAM + diff - RING_DIAM) / 2,
posy + (DOT_DIAM + diff - RING_DIAM) / 2,
RING_DIAM,
RING_DIAM);
}
g.setColor(Lizzie.frame.getBlunderNodeColor(cur));
g.fillOval(curposx + diff, posy + diff, diam, diam);
if (startNode == curMove) {
g.setColor(Color.BLACK);
g.fillOval(
curposx + (DOT_DIAM + diff - CENTER_DIAM) / 2,
posy + (DOT_DIAM + diff - CENTER_DIAM) / 2,
CENTER_DIAM,
CENTER_DIAM);
}
} else {
g.fillRect(curposx, posy, DOT_DIAM, DOT_DIAM);
g.setColor(Color.BLACK);
Expand All @@ -109,18 +134,42 @@ public void drawTree(
posy += YSPACING;
cur = cur.next().get();
if (curposx > minposx && posy > 0) {
if (Lizzie.config.nodeColorMode == 1 && cur.getData().blackToPlay
|| Lizzie.config.nodeColorMode == 2 && !cur.getData().blackToPlay) {
diam = DOT_DIAM_S;
} else {
diam = DOT_DIAM;
}
dotoffsety = diam / 2;
diff = (DOT_DIAM - diam) / 2;
if (Lizzie.config.showCommentNodeColor && !cur.getData().comment.isEmpty()) {
g.setColor(Lizzie.config.commentNodeColor);
g.fillOval(
curposx + (DOT_DIAM + diff - RING_DIAM) / 2,
posy + (DOT_DIAM + diff - RING_DIAM) / 2,
RING_DIAM,
RING_DIAM);
}
g.setColor(Lizzie.frame.getBlunderNodeColor(cur));
g.fillOval(curposx + diff, posy + diff, diam, diam);
if (cur == curMove) {
g.setColor(Color.green.brighter().brighter());
g.setColor(Color.BLACK);
g.fillOval(
curposx + (DOT_DIAM + diff - CENTER_DIAM) / 2,
posy + (DOT_DIAM + diff - CENTER_DIAM) / 2,
CENTER_DIAM,
CENTER_DIAM);
}
g.fillOval(curposx, posy, DOT_DIAM, DOT_DIAM);
g.setColor(Color.BLACK);
g.drawOval(curposx, posy, DOT_DIAM, DOT_DIAM);
g.setColor(curcolor);
g.drawLine(
curposx + dotoffset,
posy - 1,
posy - 1 + diff,
curposx + dotoffset,
posy - YSPACING + 2 * dotoffset + 2);
posy
- YSPACING
+ dotoffset
+ (diff > 0 ? dotoffset + 1 : dotoffsety)
+ (Lizzie.config.nodeColorMode == 0 ? 1 : 0));
}
}
// Now we have drawn all the nodes in this variation, and has reached the bottom of this
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/featurecat/lizzie/theme/Theme.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.IntStream;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
import org.json.JSONArray;
Expand All @@ -26,6 +32,7 @@ public class Theme {
private String path = null;
private JSONObject config = new JSONObject();
private JSONObject uiConfig = null;
private Optional<List<Double>> blunderWinrateThresholds = Optional.empty();

public Theme(JSONObject uiConfig) {
this.uiConfig = uiConfig;
Expand Down Expand Up @@ -96,6 +103,12 @@ public boolean solidStoneIndicator() {
return config.optBoolean(key, uiConfig.optBoolean(key));
}

/** Show the node with the comment color */
public boolean showCommentNodeColor() {
String key = "show-comment-node-color";
return config.optBoolean(key, uiConfig.optBoolean(key, true));
}

/** The size of the shadow */
public int shadowSize() {
return getIntByKey("shadow-size", 100);
Expand All @@ -116,6 +129,11 @@ public int commentFontSize() {
return getIntByKey("comment-font-size", 3);
}

/** The size of the shadow */
public int nodeColorMode() {
return getIntByKey("node-color-mode", 0);
}

/**
* The background color of the comment panel
*
Expand All @@ -130,6 +148,11 @@ public Color commentFontColor() {
return getColorByKey("comment-font-color", Color.WHITE);
}

/** The color of the node with the comment */
public Color commentNodeColor() {
return getColorByKey("comment-node-color", Color.BLUE.brighter());
}

/** The color of the winrate line */
public Color winrateLineColor() {
return getColorByKey("winrate-line-color", Color.green);
Expand All @@ -145,6 +168,41 @@ public Color blunderBarColor() {
return getColorByKey("blunder-bar-color", new Color(255, 0, 0, 150));
}

/** The threshold list of the blunder winrate */
public Optional<List<Double>> blunderWinrateThresholds() {
String key = "blunder-winrate-thresholds";
Optional<JSONArray> array = Optional.ofNullable(config.optJSONArray(key));
if (!array.isPresent()) {
array = Optional.ofNullable(uiConfig.optJSONArray(key));
}
array.ifPresent(
m -> {
blunderWinrateThresholds = Optional.of(new ArrayList<Double>());
m.forEach(a -> blunderWinrateThresholds.get().add(new Double(a.toString())));
});
return blunderWinrateThresholds;
}

/** The color list of the blunder node */
public Optional<Map<Double, Color>> blunderNodeColors() {
Optional<Map<Double, Color>> map = Optional.of(new HashMap<Double, Color>());
String key = "blunder-node-colors";
Optional<JSONArray> array = Optional.ofNullable(config.optJSONArray(key));
if (!array.isPresent()) {
array = Optional.ofNullable(uiConfig.optJSONArray(key));
}
array.ifPresent(
a -> {
IntStream.range(0, a.length())
.forEach(
i -> {
Color color = array2Color((JSONArray) a.get(i), null);
blunderWinrateThresholds.map(l -> l.get(i)).map(t -> map.get().put(t, color));
});
});
return map;
}

private Color getColorByKey(String key, Color defaultColor) {
Color color = array2Color(config.optJSONArray(key), null);
if (color == null) {
Expand Down

0 comments on commit e294275

Please sign in to comment.