You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ntool-biz/nkatago/engine_gtp.go

168 lines
4.8 KiB
Go

1 year ago
package nkatago
import (
"fmt"
"git.noahlan.cn/noahlan/ntool-biz/nkatago/codec"
"git.noahlan.cn/noahlan/ntool-biz/nkatago/req"
"git.noahlan.cn/noahlan/ntool-biz/nkatago/resp"
"git.noahlan.cn/noahlan/ntool/ndef"
"git.noahlan.cn/noahlan/ntool/nsys/cmdn"
"strings"
)
var (
gtpStartupDecidedFunc cmdn.LineFunc = func(sb *strings.Builder, line string) bool {
return strings.Contains(line, "GTP ready")
}
gtpEndLineDecidedFunc cmdn.LineFunc = func(sb *strings.Builder, line string) bool {
return len(line) == 0
}
gtpReadIDFunc cmdn.ReadIDFunc = func(serializer ndef.Serializer, data string) (string, error) {
return "", nil
}
)
type GtpEngine struct {
*KatagoEngine
lastID string
}
// NewGtpEngine 创建GTP引擎
func NewGtpEngine(name string, args ...string) (*GtpEngine, error) {
engine := &GtpEngine{KatagoEngine: &KatagoEngine{
Processor: cmdn.NewProcessor(
true,
cmdn.WithSerializer(codec.NewGtpSerializer()),
cmdn.WithStartupDecidedFunc(gtpStartupDecidedFunc),
cmdn.WithEndLineDecidedFunc(gtpEndLineDecidedFunc),
cmdn.WithReadIDFunc(gtpReadIDFunc),
),
Name: name,
Mode: EngineGTP,
}}
err := engine.Processor.Run(name, args...)
return engine, err
}
func (eng *GtpEngine) ID(id string) {
eng.lastID = id
}
// Exec 同步方式自定义命令
func (eng *GtpEngine) Exec(id, cmd string) (*resp.GtpResponse, error) {
cmds := strings.Fields(cmd)
ret := resp.NewGtpResponse(cmds[0])
err := eng.Processor.ExecAsync(req.NewGtpReq(id, cmd, cmds[1:]...), func(serializer ndef.Serializer, data string) {
ret.Err = serializer.Unmarshal([]byte(data), ret)
})
return ret, err
}
// KnowCommand 判断命令是否支持
func (eng *GtpEngine) KnowCommand(cmd string) bool {
value, err := eng.Exec(eng.lastID, "known_command "+cmd)
if err != nil {
return false
}
if strings.ToLower(strings.TrimSpace(value.Content)) != "true" {
return false
}
return true
}
// Komi 设置贴目
func (eng *GtpEngine) Komi(komi float64) (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, fmt.Sprintf("komi %v", komi))
}
// BoardSize 设置棋盘大小
func (eng *GtpEngine) BoardSize(size int) (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, fmt.Sprintf("boardsize %v", size))
}
// GenMove AI落子
func (eng *GtpEngine) GenMove(color string) (*resp.GtpResponse, error) {
color = strings.ToUpper(color)
command := "genmove " + color
return eng.Exec(eng.lastID, command)
}
// Play 手工落子
func (eng *GtpEngine) Play(color, coor string) (*resp.GtpResponse, error) {
color = strings.ToUpper(color)
return eng.Exec(eng.lastID, fmt.Sprintf("play %s %s", color, coor))
}
// LoadSgf 加载SGF文件
func (eng *GtpEngine) LoadSgf(file string) (*resp.GtpResponse, error) {
command := fmt.Sprintf("loadsgf %s", file)
return eng.Exec(eng.lastID, command)
}
// FinalStatusList 获取当前盘面形势判断
func (eng *GtpEngine) FinalStatusList(cmd string) (*resp.GtpResponse, error) {
command := fmt.Sprintf("final_status_list %s", cmd)
return eng.Exec(eng.lastID, command)
}
// SetLevel 设置AI级别
func (eng *GtpEngine) SetLevel(seed int) (*resp.GtpResponse, error) {
command := fmt.Sprintf("level %d", seed)
return eng.Exec(eng.lastID, command)
}
// SetRandomSeed 设置AI随机数
func (eng *GtpEngine) SetRandomSeed(seed int) (*resp.GtpResponse, error) {
command := fmt.Sprintf("set_random_seed %d", seed)
return eng.Exec(eng.lastID, command)
}
// ShowBoard 显示棋盘
func (eng *GtpEngine) ShowBoard() (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, "showboard")
}
// ClearBoard 清空棋盘
func (eng *GtpEngine) ClearBoard() (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, "clear_board")
}
// PrintSgf 打印SGF
func (eng *GtpEngine) PrintSgf() (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, "printsgf")
}
// TimeSetting 设置时间规则
func (eng *GtpEngine) TimeSetting(baseTime, byoTime, byoStones int) (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, fmt.Sprintf("time_settings %d %d %d", baseTime, byoTime, byoStones))
}
// KGSTimeSetting 设置KGS time
func (eng *GtpEngine) KGSTimeSetting(mainTime, readTime, readLimit int) (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, fmt.Sprintf("kgs-time_settings byoyomi %d %d %d", mainTime, readTime, readLimit))
}
// FinalScore 获取结果
func (eng *GtpEngine) FinalScore() (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, "final_score")
}
// Undo 悔棋
func (eng *GtpEngine) Undo() (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, "undo")
}
// TimeLeft 设置时间
func (eng *GtpEngine) TimeLeft(color string, mainTime, stones int) (*resp.GtpResponse, error) {
return eng.Exec(eng.lastID, fmt.Sprintf("time_left %s %d %d", color, mainTime, stones))
}
// Quit 退出
func (eng *GtpEngine) Quit() (*resp.GtpResponse, error) {
r, err := eng.Exec(eng.lastID, "quit")
err = eng.Processor.Stop()
return r, err
}