diff --git a/src/main/java/featurecat/lizzie/gui/BasicInfoPane.java b/src/main/java/featurecat/lizzie/gui/BasicInfoPane.java index 795d8c3fc..4bd1f7353 100644 --- a/src/main/java/featurecat/lizzie/gui/BasicInfoPane.java +++ b/src/main/java/featurecat/lizzie/gui/BasicInfoPane.java @@ -120,8 +120,8 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh g.setColor(Color.white); // Draw black and white "stone" - int diam = height / 3; - int smallDiam = diam / 2; + int diam = height / 4; + int smallDiam = diam * 2 / 3; int bdiam = diam, wdiam = diam; if (Lizzie.board != null) { if (Lizzie.board.inScoreMode() || Lizzie.frame.isEstimating) { @@ -136,11 +136,11 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh } g.setColor(Color.black); g.fillOval( - posX + width / 4 - bdiam / 2, posY + height * 3 / 8 + (diam - bdiam) / 2, bdiam, bdiam); + posX + width / 4 - bdiam / 2, posY + height * 1 / 8 + (diam - bdiam) / 2, bdiam, bdiam); g.setColor(Color.WHITE); g.fillOval( - posX + width * 3 / 4 - wdiam / 2, posY + height * 3 / 8 + (diam - wdiam) / 2, wdiam, wdiam); + posX + width * 3 / 4 - wdiam / 2, posY + height * 1 / 8 + (diam - wdiam) / 2, wdiam, wdiam); // Draw captures String bval = "", wval = ""; @@ -167,8 +167,8 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh int bx = (largeSubBoard ? diam : -bw / 2); int wx = (largeSubBoard ? bx : -ww / 2); - g.drawString(bval, posX + width / 4 + bx, posY + height * 7 / 8); - g.drawString(wval, posX + width * 3 / 4 + wx, posY + height * 7 / 8); + g.drawString(bval, posX + width / 4 + bx + diam, posY + height * 5 / 16); + g.drawString(wval, posX + width * 3 / 4 + wx + diam, posY + height * 5 / 16); g.drawString(bTime, posX + width / 10, posY + height / 6); g.drawString(wTime, posX + width * 3 / 5, posY + height / 6); @@ -177,16 +177,27 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh String komi = GameInfoDialog.FORMAT_KOMI.format(Lizzie.board.getHistory().getGameInfo().getKomi()); int kw = g.getFontMetrics().stringWidth(komi); - g.drawString(komi, posX - strokeRadius + width / 2 - kw / 2, posY + height * 7 / 8); + g.drawString(komi, posX - strokeRadius + width / 2 - kw / 2, posY + height * 7 / 16); // Status Indicator int statusDiam = height / 8; g.setColor((Lizzie.leelaz != null && Lizzie.leelaz.isPondering()) ? Color.GREEN : Color.RED); g.fillOval( posX - strokeRadius + width / 2 - statusDiam / 2, - posY + height * 3 / 8 + (diam - statusDiam) / 2, + posY + height * 1 / 16 + (diam - statusDiam) / 2, statusDiam, statusDiam); + + // Draw intuition misses + String[] msgs = Lizzie.frame.intuitionMissMessages(); + if (msgs != null) { + g.setColor(Color.WHITE); + setPanelFont(g, (float) (height * 0.14)); + int w0 = g.getFontMetrics().stringWidth(msgs[0]); + int w1 = g.getFontMetrics().stringWidth(msgs[1]); + g.drawString(msgs[0], posX + (width - w0) / 2, posY + height * 5 / 8); + g.drawString(msgs[1], posX + (width - w1) / 2, posY + height * 7 / 8); + } } private void setPanelFont(Graphics2D g, float size) { diff --git a/src/main/java/featurecat/lizzie/gui/LizzieFrame.java b/src/main/java/featurecat/lizzie/gui/LizzieFrame.java index 434828245..ba397e355 100644 --- a/src/main/java/featurecat/lizzie/gui/LizzieFrame.java +++ b/src/main/java/featurecat/lizzie/gui/LizzieFrame.java @@ -1092,8 +1092,8 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh g.setColor(Color.white); // Draw black and white "stone" - int diam = height / 3; - int smallDiam = diam / 2; + int diam = height / 4; + int smallDiam = diam * 2 / 3; int bdiam = diam, wdiam = diam; if (Lizzie.board != null) { if (Lizzie.board.inScoreMode() || isEstimating) { @@ -1108,11 +1108,11 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh } g.setColor(Color.black); g.fillOval( - posX + width / 4 - bdiam / 2, posY + height * 3 / 8 + (diam - bdiam) / 2, bdiam, bdiam); + posX + width / 4 - bdiam / 2, posY + height * 1 / 8 + (diam - bdiam) / 2, bdiam, bdiam); g.setColor(Color.WHITE); g.fillOval( - posX + width * 3 / 4 - wdiam / 2, posY + height * 3 / 8 + (diam - wdiam) / 2, wdiam, wdiam); + posX + width * 3 / 4 - wdiam / 2, posY + height * 1 / 8 + (diam - wdiam) / 2, wdiam, wdiam); // Draw captures String bval = "", wval = ""; @@ -1139,8 +1139,18 @@ private void drawCaptured(Graphics2D g, int posX, int posY, int width, int heigh int bx = (largeSubBoard ? diam : -bw / 2); int wx = (largeSubBoard ? bx : -ww / 2); - g.drawString(bval, posX + width / 4 + bx, posY + height * 7 / 8); - g.drawString(wval, posX + width * 3 / 4 + wx, posY + height * 7 / 8); + g.drawString(bval, posX + width / 4 + bx + diam, posY + height * 5 / 16); + g.drawString(wval, posX + width * 3 / 4 + wx + diam, posY + height * 5 / 16); + + // Draw intuition misses + String[] msgs = intuitionMissMessages(); + if (msgs != null) { + setPanelFont(g, (float) (height * 0.14)); + int w0 = g.getFontMetrics().stringWidth(msgs[0]); + int w1 = g.getFontMetrics().stringWidth(msgs[1]); + g.drawString(msgs[0], posX + (width - w0) / 2, posY + height * 5 / 8); + g.drawString(msgs[1], posX + (width - w1) / 2, posY + height * 7 / 8); + } } private void setPanelFont(Graphics2D g, float size) { diff --git a/src/main/java/featurecat/lizzie/gui/MainFrame.java b/src/main/java/featurecat/lizzie/gui/MainFrame.java index d3074ef09..91504a073 100644 --- a/src/main/java/featurecat/lizzie/gui/MainFrame.java +++ b/src/main/java/featurecat/lizzie/gui/MainFrame.java @@ -3,9 +3,14 @@ import featurecat.lizzie.Lizzie; import featurecat.lizzie.analysis.GameInfo; import featurecat.lizzie.analysis.Leelaz; +import featurecat.lizzie.analysis.MoveData; import featurecat.lizzie.analysis.YaZenGtp; +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 featurecat.lizzie.rules.Stone; import java.awt.BorderLayout; import java.awt.FileDialog; import java.awt.Font; @@ -364,6 +369,69 @@ protected String loadingText() { : resourceBundle.getString("LizzieFrame.display.loading"); } + public String[] intuitionMissMessages() { + JSONObject conf = Lizzie.config.uiConfig.optJSONObject("experimental-intuition-miss"); + if (conf == null || !conf.optBoolean("show-intuition-miss")) return null; + int[] numMoves = {0, 0}; + int[] numMajorIntuitions = {0, 0}; + int[] numMajorMisses = {0, 0}; + int[] numMinorMisses = {0, 0}; + BoardHistoryNode node = Lizzie.board.getHistory().getCurrentHistoryNode(); + while (node.previous().isPresent()) { + BoardData data = node.getData(); + node = node.previous().get(); + // Get the move. + if (!data.lastMove.isPresent()) continue; + int[] lastMove = data.lastMove.get(); + String lastMoveName = Board.convertCoordinatesToName(lastMove[0], lastMove[1]); + int player = (data.lastMoveColor == Stone.BLACK) ? 0 : 1; + // Get the policies. + List bestMoves = node.getData().bestMoves; + if (bestMoves == null || bestMoves.isEmpty()) continue; + // (Lizzie assumes that bestMoves are sorted by 'order'.) + double bestmovePolicy = bestMoves.get(0).policy; + double policy = 0.0; + for (MoveData move : bestMoves) { + if (move.coordinate.equals(lastMoveName)) { + policy = move.policy; + break; + } + } + // Detect the misses and count them. + numMoves[player] += 1; + if (policy < conf.optDouble("minor-policy-threshold", 10)) { + numMinorMisses[player] += 1; + } + if (bestmovePolicy > conf.optDouble("bestmove-policy-threshold", 70)) { + numMajorIntuitions[player] += 1; + if (policy < conf.optDouble("played-policy-threshold", 10)) numMajorMisses[player] += 1; + } + } + String[] ret = { + String.format( + "%d/%d %s (Intuition Miss) %s %d/%d", + numMajorMisses[0], + numMajorIntuitions[0], + percentString(numMajorMisses[0], numMajorIntuitions[0]), + percentString(numMajorMisses[1], numMajorIntuitions[1]), + numMajorMisses[1], + numMajorIntuitions[1]), + String.format( + "%d/%d %s (minor) %s %d/%d", + numMinorMisses[0], + numMoves[0], + percentString(numMinorMisses[0], numMoves[0]), + percentString(numMinorMisses[1], numMoves[1]), + numMinorMisses[1], + numMoves[1]), + }; + return ret; + } + + private String percentString(int numerator, int denominator) { + return denominator > 0 ? String.format("%.0f%%", (float) 100.0 * numerator / denominator) : ""; + } + public void toggleEstimateByZen() { if (isEstimating) { noEstimateByZen(true);