SabakiHQ / Sabaki

An elegant Go board and SGF editor for a more civilized age.
https://sabaki.yichuanshen.de/
MIT License
2.39k stars 375 forks source link

Jump to a specific node from command line? #872

Open jcguu95 opened 2 years ago

jcguu95 commented 2 years ago

Question

Is it possible to jump to a specific node of an sgf file from command line. Of course, a domain specific language for specifying a node is required, or we may use regex matching to find the nodes with comments. For example,

$> sabaki --load "game.sgf" --node "E5[1]"

Usage

This will be useful because people can then take notes for GO easily. For example, in org-mode (a la emacs) one can custimize link protocols as follows.

* Lesson 1: Vital points

A Vital Point is an important shape point for both players, e.g.

+ [[go:~/game.sgf:E5[1]]]

The [[..]] would be turned into a link, which is then bound to the command (non-existent?) above.

Related

HackYardo commented 2 years ago

As far as I know, it is a basic feature of GoTextProtocol to load a position from a sgf file by a movenumber:

6.3.5 Regression Commands

So, you can wrap it to implement the custom:

def loadsgf(file,node):
    ...
    loadsgf(file,movenumber)
jcguu95 commented 2 years ago

This is great! I think I can write a wrapper in python, but how do I send the signal to Sabaki?

HackYardo commented 2 years ago

You will need to embed the custom loadsgf() into a tiny gtp wrap, e.g. instead path/to/gnugo --mode gtp, use python path/to/script.py in the Sabaki's menu: image

I find a relevant method in sente.py here.

Or, if you know JavaScript, you can modify the source code of Sabaki and then request a pull.

HackYardo commented 2 years ago

It is very easy to implement a GTP Wrap. Here is an example written in Julia, a new language similar to Python:

katagoCommand=`./katago gtp -config gtp_custom.cfg -model b6/model.txt.gz`
katagoProcess=open(katagoCommand,"r+")

function query()
    sentence=""
    while true
        sentence=readline()
        if sentence=="" || "" in split(sentence," ")
            continue
        else
            println(katagoProcess,sentence)
            break
        end
    end
    return sentence::String
end

function reply()
    paragraph=""
    while true
        sentence=readline(katagoProcess)
        if sentence==""
            break
        else 
            paragraph="$paragraph$sentence\n"
        end
    end
    println(paragraph)
    return paragraph::String
end

function play()
    while true
        sentence=query()
        paragraph=reply()
        if sentence=="quit"
            break
        else
            continue
        end
    end
end

function main()
    play()
end

main()
jcguu95 commented 2 years ago

@HackYardo Thank you so much for your help!!

I read through each part of the wonderful doc of sente. It's very close to what I want. In particular, it can create an internal gtp engine, which can be called by Sabaki or other go GUIs. To write a simple AI using sente, as shown in the doc, we need to implement our own genmove(). I also learn how to hook such AI with Sabaki. Awesome!

My goal is simpler: to send an external signal to Sabaki for it to jump to a specific node of a specific sgf file. This should be done by sending an external signal to sente, and let sente to ask Sabaki to display a certain node. Do you know how to do the last bolded step?

atw1020 commented 2 years ago

As far as I know, it is a basic feature of GoTextProtocol to load a position from a sgf file by a movenumber:

loadSGF is an instruction that Sabaki is giving to the engine. GTP does not provide any method for an engine to tell Sabaki to change moves. Sabaki has no way for a program to tell it what move to advance to as fare as I can tell.

HackYardo commented 2 years ago

@atw1020 @jcguu95 Well, in my view, you complicate this issue. Yeah, GTP is only a standard, it is not GTP but GTP engines/controllers do the implementing. So that either controllers or engines can implement their GTP extensions. So does a script which wraps gtp engines. That's the point. See the diagram:

user <==> gui <==> controller <==> engine
user <==> Sabaki <==> engine
user <==> Sabaki <==> wrap <==> engine

There is a gtp controler in Sabaki, so one can modify Sabaki to implement some gtp extensions.

HackYardo commented 2 years ago

In details:

user -> loadsgf node -> gui -> controller -> loadsgf(node) -> loadsgf move_number -> engine -> target position -> controller -> gui -> user

Just fill some codes in loadsgf().

atw1020 commented 2 years ago

I'm still not sure what you are trying to describe.

If you run `loadsgf in the sabaki console window, an engine using GTP will load the game, but the SGF will not show up in sabaki. As you can see in the screenshot below, the engine is successfully able to load the SGF file, however the sabaki go board does not populate with the game loaded by the command.

Screen Shot 2022-05-31 at 9 32 07 PM

On the other hand, you can also try to have the engine send the loadsgf command to sabaki directly. If you try to send such a command to sabaki, sabaki will ignore it because sabaki is a controller and ignores commands if an engine tries to send them. You can verify this by adding a print statement into the sente GTP engine example (see below for code modification) and then running the engine in sabaki. The command will not show up in the console.

    while session.active():

        # respond to a command from the controller
        response = session.interpret(input(""))
        print(response)

        # try to send
        print("loadsgf ORissei-YamashiroHiroshi38563.sgf")

Is there something I'm missing here? please let me know

HackYardo commented 2 years ago

Sorry so much for the trouble! I remember Sabaki has a engine sync feature, so you can sync board after loadsgf, but it is "gui leads, engine follows" not vice versa... Meanwhile, this issue is not a GTP thing but a GUI thing... image

(In fact, I'm writing a web app, it knows none about Go rules and uses showboard to handle Go logic. It is "engine leads, gui follows". So the trouble occurs...)