kaorahi / lizgoban

Leela Zero & KataGo visualizer
GNU General Public License v3.0
169 stars 28 forks source link

Can I show win rate of stones by facial expressions? #92

Closed qcgm1978 closed 11 months ago

qcgm1978 commented 11 months ago

The README says the project can show ownerships of stones by facial expressions. I want to show win rate of stones by facial expressions i.e. the face stone stands for the win rate of black or white after current move. Is it possible?

kaorahi commented 11 months ago

Officially, no.

Can you edit the source code? If you revert 4e5f8b0a2, the face expressions depend on winrate when ownership info isn't present (you can toggle the ownership feature using the shift + E key). I removed this functionality due to a glitch where it would use the current winrate even when a past board was temporarily displayed by clicking on existing stones, etc.

Fix of the glitch needs some hustle and introduces complexity that increases the future maintenance cost. So I'm not planning to support it officially.

qcgm1978 commented 11 months ago

I revert the version and found it seems work when the game isn't end, but all the faces except dead stones change to the same after it ends. Is it designed or a bug? What'more the faces of the same color are different. I want all the same color stones stand for the current instant win rate of that color.

截屏2023-10-08 08 31 18 截屏2023-10-08 08 31 44
kaorahi commented 11 months ago

It may be due to cached ownership data, I suspect. To make sure you always use winrate instead of ownership, you may like something like this:

--- a/src/draw_goban.js
+++ b/src/draw_goban.js
@@ -661,10 +661,8 @@ function face_image_for(h) {
     if (h.movenums) {return null}
     const {endstate, endstate_diff, black} = h
     const conv = z => (black ? 1 : -1) * (z || 0)
-    // using "current" winrate is not a good idea for subboard with past board etc.
-    // const wr = true_or((R.winrate_history[R.move_count] || {}).r, 50) / 50 - 1
-    const wr = 0
-    const es = conv(true_or(endstate, wr)), diff = conv(endstate_diff)
+    const wr = true_or((R.winrate_history[R.move_count] || {}).r, 50) / 50 - 1
+    const es = conv(wr), diff = 0
     const {endstate_rule, endstate_diff_rule} = R.face_image_rule
     const pick = (rule, z) => !rule ? [] :
           rule.find(([threshold, , ]) => z < threshold) || last(rule)

Please note that the code may change someday, and this patch may not work at that time.

qcgm1978 commented 11 months ago

Wonderful. It's what I want exactly. I still need some stone pics to make UI more funny.

qcgm1978 commented 11 months ago

I found that the program needs to be run twice in order to display the correct emoji images representing win rate. Is this a bug, cache or does the katago engine need sufficient time to calculate the accurate win rate? The first time when auto playing, after I click the stop button, it can then display the correct emoji representing the win rate.

kaorahi commented 11 months ago

Could you provide detailed information on (1) what you did, (2) the results you observed, and (3) what you were expecting? Please offer a step-by-step breakdown to reproduce the issue like this report. https://github.com/featurecat/lizzie/issues/788

Screenshots of the window from both successful and failed cases would also be helpful.

qcgm1978 commented 11 months ago

There is issue on displaying the correct emoji images representing win rate in 4e5f8b0 version. I changed the code of src/draw_goban.js as you said in the previous answer.

Common setup:

config.json

"face_image_rule": [
    [-0.9, "svg/black_-9.svg", "svg/white_-9.svg"],
    [-0.8, "svg/black_-8.svg", "svg/white_-8.svg"],
    [-0.7, "svg/black_-7.svg", "svg/white_-7.svg"],
    ...

Start Katago with an empty board. Open sgf file Click auto button to play

Issue:

The faces of stones are same.

截屏2023-10-10 19 18 00

But the faces would be different if I clicked the stop button

截屏2023-10-10 19 19 57

It would work if I played the game for the second time i.e. I played it to game end for the first time and clicked play button again.

kaorahi commented 11 months ago

Until the AI's analysis arrives, the winrate is temporarily regarded as 50% for each move. As a result, you'll see the 50% face briefly displayed before it changes to the face representing the correct winrate. To avoid such annoying switches, you may prefer using the previous face instead of the 50% face as follows.

--- a/src/draw_goban.js
+++ b/src/draw_goban.js
@@ -657,14 +657,15 @@ function face_image_p() {
 }

 function stone_image_for(h) {return stone_image_for_key(h, 'black_stone', 'white_stone')}
+let face_image_prev_winrate = 50
 function face_image_for(h) {
     if (h.movenums) {return null}
     const {endstate, endstate_diff, black} = h
     const conv = z => (black ? 1 : -1) * (z || 0)
-    // using "current" winrate is not a good idea for subboard with past board etc.
-    // const wr = true_or((R.winrate_history[R.move_count] || {}).r, 50) / 50 - 1
-    const wr = 0
-    const es = conv(true_or(endstate, wr)), diff = conv(endstate_diff)
+    const winrate = face_image_prev_winrate =
+          true_or((R.winrate_history[R.move_count] || {}).r, face_image_prev_winrate)
+    const wr = winrate / 50 - 1
+    const es = conv(wr), diff = 0
     const {endstate_rule, endstate_diff_rule} = R.face_image_rule
     const pick = (rule, z) => !rule ? [] :
           rule.find(([threshold, , ]) => z < threshold) || last(rule)
qcgm1978 commented 11 months ago

Excellent. It works as I expected. Thank you for your patient explanation.