waltheri/wgo.js

Can I use wgo as a "debugger" of a tsumego solver?

d180cf opened this issue · 15 comments

Hello,

I'm writing (well, trying to write) a tsumego solver in js and found that it's exceptionally hard to debug it: the solver is a complicated search algorithm that walks thru the dynamically generated tree of go positions (a snapshot of the tree is essentially an SGF file) and evaluates them based on some algorithms. Since it's hard to keep in mind the exact state of the search, I'm in need of a tool that would render the dynamically generated SGF as I step thru it.

Currently I'm using eidogo and it seems to work reasonably well, but unfortunately it seems to be abandoned as the last commit was made there in 2013. So I'm looking at alternatives because eidogo has some missing features that I need. What I need from this "tsumego debugger" is:

  1. Render a basic setup from an SGF string: (;FF[4]SZ[9]MA[bb]DD[aa]AB[ac][bc]...AW[ab]...)
  2. Add custom markup, i.e. a colored dot by CD[#ff8c40]. As you see in the previous example, I have to use MA (a cross) to denote the target which needs to be captures and DD (dark background) to list all possible moves for the solver (it's not advanced enough at the moment to figure out this list itself).
  3. Edit the tree at runtime: make a move, undo, pass. Preferrably, such changes should be batched, i.e. when I tell the UI to add/remove stones, it doesn't do that immediately, but setTimeout(..., 0) first and draws the batch of changes at the next turn of the event loop.
  4. Add a comment for a node: after the solver is done with a node, it can add a comment with the result and if I disagree with that, I can debug and see where the solver failed.
  5. Add a subtree: after a solver has found a solution (aka "a proof tree") it needs to be added to the current node. This is useful in the "step over" (F10) feature: if I find the current move not interesting, I can press F10 and skip it, but the solver must add the solution to the tree so that I could quickly check it.
  6. 9x9 board with coordinates (eidogo cannot render labels for this board bc labels are hardcodd in a png background file for 19x19 only).
  7. Have a sort of an event channel from the UI to the code, i.e. if I make a move in the UI, I'd like to pass this move to the solver and see how it handles it. I could do this in the dev console, but it would be much easier to do this in the UI.

Can wgo handle all this?

Thanks.

Hi,

your project seems very interesting and I think WGo is perfect for it. It is designed for go web applications and for example my pattern search is written in it.

I think all points you wrote, can be easily managed with WGo API. Most of them can be done natively and the missing features can be added. For example there isn't native support for colored dots, but with few lines of code you can add it - you'll just extend this object.

However not all parts are well documented, but if you won't understand some code I will gladly help you.

Cheers.

I've started the transition to wgo. In the change there is a tsumego.Player thing which is a communication channel between the solver and the wgo. It has only 4 events:

  1. When it invokes play it wants to say that it's considering a move with the given coordinates, so this stone needs to be added in the UI. The .addObject adds a stone, but doesn't update the review tree (btw, how to show it?).
  2. When it invokes play without coordinates, it wants to say that it's considering a pass for the specified player, so wgo needs to reflect this somehow in the UI.
  3. done and loss are invoked when the solver thinks that the current position is solved, so wgo needs to display a comment with the solution. This corresponds to adding a C[...] node in the SGF.

Perhaps what I need is the Game class mentioned in your docs, but it's not clear how to reach it from BasicPlayer. Could you help me with this?

I would recommend to use either BasicPlayer or Player. These classes have already implemented logic which synchronizes a Board object with a Game object.

If you use BasicPlayer, you will get standard UI. On the other side Player contains just a board and you would need to implement control buttons and box with comments. Both of these classes contains methods for loading kifus (loadKifu, loadSgf, ...), traversing (next, previous, goTo, ...) and events (kifuLoaded, update). However they don't natively contains editing methods - you must implement them. Play method can look for example like this:

var play = function(player, x, y) {
    // ignore invalid move
    if(player.frozen || !player.kifuReader.game.isValid(x, y)) return;

    var node;

    // create new node
    if(x == null) {
        node = new WGo.KNode({
            move: {
                pass: true, 
                c: player.kifuReader.game.turn
            }, 
            _edited: true
        });
    }
    else {
        node = new WGo.KNode({
            move: {
                x: x, 
                y: y, 
                c: player.kifuReader.game.turn
            }, 
            _edited: true
        });
    }

    // append new node to the current kifu
    player.kifuReader.node.appendChild(node);

    // show next move
    player.next(player.kifuReader.node.children.length-1);
}

New node can contain any properties like comments markers etc.

Check files kifu.js and player.editable.js for inspiration.

My attempt to integrate this change was partially successfull: I can make moves and undo them, but when I try to pass, I get a "this.setMessage is not a function" error from .next(0). Could you take a look at the changelist?

I am afraid, I don't understand - there isn't word setMessage in the entire WGo library. Can you debug it more?

It's in player.js:

    // add current move marker
    if(e.node.move) {
        if(e.node.move.pass) this.setMessage({
            text: WGo.t((e.node.move.c == WGo.B ? "b" : "w")+"pass"),
            type: "notification"
        });
TypeError: this.setMessage is not a function
    at update_board (http://localhost:8080/wgo/player.js:64:29)
    at Player.dispatchEvent (http://localhost:8080/wgo/player.js:421:69)
    at Player.update (http://localhost:8080/wgo/player.js:299:8)
    at Player.next (http://localhost:8080/wgo/player.js:462:9)
    at Object.player.play (http://localhost:8080/app.js:850:23)
    at Solver.play (http://localhost:8080/app.js:742:33)
    at Solver.pick (http://localhost:8080/app.js:723:26)
    at Solver.next (http://localhost:8080/app.js:705:18)
    at next (http://localhost:8080/app.js:874:20)
    at http://localhost:8080/app.js:923:17

The error has gone after I updated my copy of wgo to your github version. Apparently, the version on the site is outdated.

So now wgo correctly displays a message "white passed" and the only left thing is adding comments to the current position:

            done: (color, move, note) => {
                if (!log) return;
                const comment = `${cw2s(color, move) } ${note ? '(' + note + ')' : ''}\n`;
                // TODO: add comment to the current node; how?
            },

How can I attach a comment to the current position and make it display in the same area where wgo displays the "white passed" message?

You can add comment to a new node:

new WGo.KNode({
    _edited: true,
    move: {
        pass: !move,
        x: move && move.x,
        y: move && move.y,
        c: color > 0 ? WGo.B : WGo.W
    },
    comment: "Hello!"
});

or to current node:

player.kifuReader.node.comment = "Hello!";
player.update();

or directly display the message with:

player.notification("Hello!")`

All of these options should work, but I didn't test it.

I need to add a comment to the current node. .notification("...") works, but the comment doesn't stick to the node - if I go forth and back the comment is lost. .kifuReader.node.comment = "..." followed by .update() doesn't seem to produce any effect.

That's strange, I just tested it, and it worked. You can try call player.previous() followed by player.next().

If it still doesn't work - can you see comments from SGF, or from the first option I wrote earlier?

Sure, will try tomorrow. In the meantime, could you take a look at the diff: maybe I just made some obvious mistake?

Your code is fine, I just realized what is wrong. When a kifu is loaded BasicPlayer scans it, if it contains any comments. If the kifu doesn't contain any comment, BasicPlayer will show only game information and permanently hide a comment box.

I would recommend to add some empty comment to some node in your SGF, or you need to hack CommentBox.

This fixed the problem. Now it looks very cool: when the solver adds a comment like "B wins by C2" I can hover the mouse over "C2" and wgo shows a cross at C2 - I feature that I missed so much.

Now I even have the coords and I've just realized that the vertical numeric labels are in the reverse order, so when wgo shows C2, the cross appears in the bottom side of the board, while the stones are at the top. I understand that this is how goban normally looks, but is there a way to reverse the vertical coords, so that W[aa] correspond to the top left corner? That would be helpful because all the internal logic of the solver and my SGF files with sample problems assume that [aa] is the top left of the board.

Looks like the inversion of the Y-coordinate is done by the mark function and it's done unconditionally. But I think I can deal with this by inverting the Y-coordinate before adding a comment. However this won't solve the case when I'm debugging the internals of the solver and see coords like (2, 3) and have to map this in mind to C6.

Actually, I've just realised that the inversion has to be done on my side.