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 }