与控制台应用程序通信

huangapple go评论81阅读模式
英文:

Communicating with console apps

问题

我是一个初学者。我尝试使用Go语言的exec包与一个国际象棋引擎进行通信,但它要求我关闭标准输入(stdin)。我希望能够与引擎建立对话。

请问我该如何在Go语言中实现这个功能?

以下是一个Python实现的通信示例,非常直观,可以在https://stackoverflow.com/questions/12341882/how-to-communicate-with-a-chess-engine-in-python找到:

import subprocess, time

engine = subprocess.Popen(
'stockfish-x64.exe',
universal_newlines=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)

def put(command):
    print('\nyou:\n\t'+command)
    engine.stdin.write(command+'\n')

def get():
    # using the 'isready' command (engine has to answer 'readyok')
    # to indicate current last line of stdout
    engine.stdin.write('isready\n')
    print('\nengine:')
    while True:
        text = engine.stdout.readline().strip()
        if text == 'readyok':
            break
        if text !='':
            print('\t'+text)

get()
put('uci')
get()

put('setoption name Hash value 128')
get()
put('ucinewgame')
get()
put('position startpos moves e2e4 e7e5 f2f4')
get()
put('go infinite')
time.sleep(3)
get()
put('stop')
get()
put('quit')

为了简化问题,考虑以下Go语言代码:

package main

import ( 
    "bytes"
    "fmt"
    "io"
    "os/exec"
)

func main() {
    cmd := exec.Command("stockfish")
    stdin, _ := cmd.StdinPipe()
    io.Copy(stdin, bytes.NewBufferString("isready\n"))
    var out bytes.Buffer
    cmd.Stdout = &out
    cmd.Run()
    fmt.Printf(out.String())
}

这个程序在没有打印任何内容的情况下等待。但是当我关闭标准输入(stdin)时,程序会打印结果,但关闭标准输入(stdin)会阻碍引擎和Go程序之间的通信。

解决方案如下:

package main

import ( 
    "bytes"
    "fmt"
    "io"
    "os/exec"
    "time"
)

func main() {
    cmd := exec.Command("stockfish")
    stdin, _ := cmd.StdinPipe()
    io.Copy(stdin, bytes.NewBufferString("isready\n"))
    var out bytes.Buffer
    cmd.Stdout = &out
    cmd.Start()
    time.Sleep(1000 * time.Millisecond)
    fmt.Printf(out.String())
}
英文:

I am a beginner. I have tried to communicate to a chess engine with go's exec package, but it requires me to close the stdin. What I wish to do is to establish a dialogue with the engine.

How do I do that with go?

This is the python implementation of the communication which is pretty much straight forward, can be found at https://stackoverflow.com/questions/12341882/how-to-communicate-with-a-chess-engine-in-python

    import subprocess, time

    engine = subprocess.Popen(
    'stockfish-x64.exe',
    universal_newlines=True,
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    )

    def put(command):
    print('\nyou:\n\t'+command)
    engine.stdin.write(command+'\n')

    def get():
    # using the 'isready' command (engine has to answer 'readyok')
    # to indicate current last line of stdout
    engine.stdin.write('isready\n')
    print('\nengine:')
    while True:
        text = engine.stdout.readline().strip()
        if text == 'readyok':
            break
        if text !='':
            print('\t'+text)

    get()
    put('uci')
    get()

put('setoption name Hash value 128')
get()
put('ucinewgame')
get()
put('position startpos moves e2e4 e7e5 f2f4')
get()
put('go infinite')
time.sleep(3)
get()
put('stop')
get()
put('quit')

For simplicity consider this in go:

package main

import ( 
    "bytes"
    "fmt"
    "io"
    "os/exec"
)

func main() {
    cmd := exec.Command("stockfish")
    stdin, _ := cmd.StdinPipe()
    io.Copy(stdin, bytes.NewBufferString("isready\n"))
    var out bytes.Buffer
    cmd.Stdout = &out
    cmd.Run()
    fmt.Printf(out.String())
}

The program waits without printing anything. But when I close the stdin the program prints the result, but closing the stdin hinders communication between the engine and go program.

The solution:

package main

    import ( 
        "bytes"
        "fmt"
        "io"
        "os/exec"
        "time"
    )
    
    func main() {
        cmd := exec.Command("stockfish")
        stdin, _ := cmd.StdinPipe()
        io.Copy(stdin, bytes.NewBufferString("isready\n"))
        var out bytes.Buffer
        cmd.Stdout = &out
        cmd.Start()
        time.Sleep(1000 * time.Millisecond)
        fmt.Printf(out.String())
    }

答案1

得分: 2

你仍然可以使用exec.Command来实现这个功能,然后使用Cmd方法cmd.StdinPipe()cmd.StdoutPipe()cmd.Start()

文档中的exec.Cmd.StdoutPipe示例应该能帮助你入门:http://golang.org/pkg/os/exec/#Cmd.StdoutPipe

但在你的情况下,你需要在一个循环中读取和写入管道。我想你的架构会像这样,在一个goroutine中的循环中,通过通道将命令传递给你的其他代码。

英文:

You should still be able to do this with exec.Command and then with the Cmd methods cmd.StdinPipe(), cmd.StdoutPipe(), and cmd.Start()

The example in the docs for exec.Cmd.StdoutPipe should be able to get you started: http://golang.org/pkg/os/exec/#Cmd.StdoutPipe

But in your case, you'd be doing reads and writes from the pipes in a loop. I'd imagine your architecture will look like this loop in a goroutine, passing commands to-and-fro the rest of your code via channels.

huangapple
  • 本文由 发表于 2014年2月17日 23:18:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/21832754.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定