github.com/frankkopp/FrankyGo@v1.0.3/internal/uci/ucioption.go (about)

     1  //
     2  // FrankyGo - UCI chess engine in GO for learning purposes
     3  //
     4  // MIT License
     5  //
     6  // Copyright (c) 2018-2020 Frank Kopp
     7  //
     8  // Permission is hereby granted, free of charge, to any person obtaining a copy
     9  // of this software and associated documentation files (the "Software"), to deal
    10  // in the Software without restriction, including without limitation the rights
    11  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    12  // copies of the Software, and to permit persons to whom the Software is
    13  // furnished to do so, subject to the following conditions:
    14  //
    15  // The above copyright notice and this permission notice shall be included in all
    16  // copies or substantial portions of the Software.
    17  //
    18  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    19  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    20  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    21  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    22  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    23  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    24  // SOFTWARE.
    25  //
    26  
    27  package uci
    28  
    29  import (
    30  	"fmt"
    31  	"reflect"
    32  	"strconv"
    33  	"strings"
    34  
    35  	. "github.com/frankkopp/FrankyGo/internal/config"
    36  )
    37  
    38  // init will define all available uci options and store them into the uciOption map
    39  func init() {
    40  	uciOptions = map[string]*uciOption{
    41  		"Print Config": {NameID: "Print Config", HandlerFunc: printConfig, OptionType: Button},
    42  		"Clear Hash":   {NameID: "Clear Hash", HandlerFunc: clearCache, OptionType: Button},
    43  		"Use_Hash":     {NameID: "Use_Hash", HandlerFunc: useCache, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseTT), CurrentValue: strconv.FormatBool(Settings.Search.UseTT)},
    44  		"Hash":         {NameID: "Hash", HandlerFunc: cacheSize, OptionType: Spin, DefaultValue: strconv.Itoa(Settings.Search.TTSize), CurrentValue: strconv.Itoa(Settings.Search.TTSize), MinValue: "0", MaxValue: "65000"},
    45  
    46  		"Use_Book": {NameID: "Use_Book", HandlerFunc: useBook, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseBook), CurrentValue: strconv.FormatBool(Settings.Search.UseBook)},
    47  
    48  		"Ponder": {NameID: "Ponder", HandlerFunc: usePonder, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UsePonder), CurrentValue: strconv.FormatBool(Settings.Search.UsePonder)},
    49  
    50  		"Quiescence":       {NameID: "Quiescence", HandlerFunc: useQuiescence, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseQuiescence), CurrentValue: strconv.FormatBool(Settings.Search.UseQuiescence)},
    51  		"Use_QHash":        {NameID: "Use_QHash", HandlerFunc: useQSHash, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseQSTT), CurrentValue: strconv.FormatBool(Settings.Search.UseQSTT)},
    52  		"Use_SEE":          {NameID: "Use_SEE", HandlerFunc: useSee, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseSEE), CurrentValue: strconv.FormatBool(Settings.Search.UseSEE)},
    53  		"Use_PromNonQuiet": {NameID: "Use_PromNonQuiet", HandlerFunc: usePromNonQuiet, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UsePromNonQuiet), CurrentValue: strconv.FormatBool(Settings.Search.UsePromNonQuiet)},
    54  
    55  		"Use_PVS":  {NameID: "Use_PVS", HandlerFunc: usePvs, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UsePVS), CurrentValue: strconv.FormatBool(Settings.Search.UsePVS)},
    56  		"Use_ASP":  {NameID: "Use_ASP", HandlerFunc: useAsp, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseAspiration), CurrentValue: strconv.FormatBool(Settings.Search.UseAspiration)},
    57  		"Use_MTDf": {NameID: "Use_MTDf", HandlerFunc: useMtdf, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseMTDf), CurrentValue: strconv.FormatBool(Settings.Search.UseMTDf)},
    58  
    59  		"Use_IID":         {NameID: "Use_IID", HandlerFunc: useIID, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseIID), CurrentValue: strconv.FormatBool(Settings.Search.UseIID)},
    60  		"Use_Killer":      {NameID: "Use_Killer", HandlerFunc: useKiller, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseKiller), CurrentValue: strconv.FormatBool(Settings.Search.UseKiller)},
    61  		"Use_HistCount":   {NameID: "Use_HistCount", HandlerFunc: useHC, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseHistoryCounter), CurrentValue: strconv.FormatBool(Settings.Search.UseHistoryCounter)},
    62  		"Use_CounterMove": {NameID: "Use_CounterMove", HandlerFunc: useCM, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseCounterMoves), CurrentValue: strconv.FormatBool(Settings.Search.UseCounterMoves)},
    63  
    64  		"Use_Rfp":      {NameID: "Use_Rfp", HandlerFunc: useRfp, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseRFP), CurrentValue: strconv.FormatBool(Settings.Search.UseRFP)},
    65  		"Use_NullMove": {NameID: "Use_NullMove", HandlerFunc: useNullMove, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseNullMove), CurrentValue: strconv.FormatBool(Settings.Search.UseNullMove)},
    66  		"Use_Mdp":      {NameID: "Use_Mdp", HandlerFunc: useMdp, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseMDP), CurrentValue: strconv.FormatBool(Settings.Search.UseMDP)},
    67  		"Use_Fp":       {NameID: "Use_Fp", HandlerFunc: useFp, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseFP), CurrentValue: strconv.FormatBool(Settings.Search.UseFP)},
    68  		"Use_Lmr":      {NameID: "Use_Lmr", HandlerFunc: useLmr, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseLmr), CurrentValue: strconv.FormatBool(Settings.Search.UseLmr)},
    69  		"Use_Lmp":      {NameID: "Use_Lmp", HandlerFunc: useLmp, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseLmp), CurrentValue: strconv.FormatBool(Settings.Search.UseLmp)},
    70  
    71  		"Use_Ext":         {NameID: "Use_Ext", HandlerFunc: useExt, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseExt), CurrentValue: strconv.FormatBool(Settings.Search.UseExt)},
    72  		"Use_ExtAddDepth": {NameID: "Use_ExtAddDepth", HandlerFunc: useExtAddDepth, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseExtAddDepth), CurrentValue: strconv.FormatBool(Settings.Search.UseExtAddDepth)},
    73  		"Use_CheckExt":    {NameID: "Use_CheckExt", HandlerFunc: useCheckExt, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseCheckExt), CurrentValue: strconv.FormatBool(Settings.Search.UseCheckExt)},
    74  		"Use_ThreatExt":   {NameID: "Use_ThreatExt", HandlerFunc: useThreatExt, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Search.UseThreatExt), CurrentValue: strconv.FormatBool(Settings.Search.UseThreatExt)},
    75  
    76  		"Eval_Lazy":     {NameID: "Eval_Lazy", HandlerFunc: evalLazy, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Eval.UseLazyEval), CurrentValue: strconv.FormatBool(Settings.Eval.UseLazyEval)},
    77  		"Eval_Mobility": {NameID: "Eval_Mobility", HandlerFunc: evalMob, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Eval.UseMobility), CurrentValue: strconv.FormatBool(Settings.Eval.UseMobility)},
    78  		"Eval_AdvPiece": {NameID: "Eval_AdvPiece", HandlerFunc: evalAdv, OptionType: Check, DefaultValue: strconv.FormatBool(Settings.Eval.UseAdvancedPieceEval), CurrentValue: strconv.FormatBool(Settings.Eval.UseAdvancedPieceEval)},
    79  	}
    80  
    81  	// as Go does not let us sort maps manually (e.g. insertion order) we need a
    82  	// list to control order of the entries
    83  	sortOrderUciOptions = []string{
    84  		"Print Config",
    85  		"Clear Hash",
    86  		"Use_Hash",
    87  		"Hash",
    88  		"Use_Book",
    89  		"Ponder",
    90  
    91  		"Quiescence",
    92  		"Use_QHash",
    93  		"Use_SEE",
    94  		"Use_PromNonQuiet",
    95  
    96  		"Use_PVS",
    97  		"Use_ASP",
    98  
    99  		"Use_IID",
   100  		"Use_Killer",
   101  		"Use_HistCount",
   102  		"Use_CounterMove",
   103  
   104  		"Use_Mdp",
   105  		"Use_Rfp",
   106  		"Use_NullMove",
   107  		"Use_Fp",
   108  		"Use_Lmr",
   109  		"Use_Lmp",
   110  
   111  		"Use_Ext",
   112  		"Use_ExtAddDepth",
   113  		"Use_CheckExt",
   114  		"Use_ThreatExt",
   115  
   116  		"Eval_Mobility",
   117  		"Eval_AdvPiece",
   118  	}
   119  }
   120  
   121  // GetOptions returns all available uci options as a slice of strings
   122  // to be send to the UCI user interface during the initialization
   123  // phase of the UCI protocol
   124  func (o *optionMap) GetOptions() *[]string {
   125  	var options []string
   126  	for _, opt := range sortOrderUciOptions {
   127  		options = append(options, uciOptions[opt].String())
   128  	}
   129  	return &options
   130  }
   131  
   132  // String for uciOption will return a representation of the uci option as required by
   133  // the UCI protocol during the initialization phase of the UCI protocol
   134  func (o *uciOption) String() string {
   135  	var os strings.Builder
   136  	os.WriteString("option name ")
   137  	os.WriteString(o.NameID)
   138  	os.WriteString(" type ")
   139  	switch o.OptionType {
   140  	case Check:
   141  		os.WriteString("check ")
   142  		os.WriteString("default ")
   143  		os.WriteString(o.DefaultValue)
   144  	case Spin:
   145  		os.WriteString("spin ")
   146  		os.WriteString("default ")
   147  		os.WriteString(o.DefaultValue)
   148  		os.WriteString(" min ")
   149  		os.WriteString(o.MinValue)
   150  		os.WriteString(" max ")
   151  		os.WriteString(o.MaxValue)
   152  	case Combo:
   153  		os.WriteString("combo ")
   154  		os.WriteString("default ")
   155  		os.WriteString(o.DefaultValue)
   156  		os.WriteString(" var ")
   157  		os.WriteString(o.VarValue)
   158  	case Button:
   159  		os.WriteString("button")
   160  	case String:
   161  		os.WriteString("string ")
   162  		os.WriteString("default ")
   163  		os.WriteString(o.DefaultValue)
   164  	}
   165  
   166  	return os.String()
   167  }
   168  
   169  // uciOptionType is a enum representing the different UCI Option types
   170  type uciOptionType int
   171  
   172  // uci option types constants
   173  const (
   174  	Check  uciOptionType = 0
   175  	Spin   uciOptionType = 1
   176  	Combo  uciOptionType = 2
   177  	Button uciOptionType = 3
   178  	String uciOptionType = 4
   179  )
   180  
   181  // optionHandler is a function type to by used as function pointer
   182  // in each uci option defined. This is called when the uci option
   183  // is changed by the "setoption" command
   184  type optionHandler func(*UciHandler, *uciOption)
   185  
   186  // uciOption defines UCI Options as described in the UCI protocol.
   187  // Each options has a function pointer to a handler which will be
   188  // called when the "setoption" command changes the option.
   189  type uciOption struct {
   190  	NameID       string
   191  	HandlerFunc  optionHandler
   192  	OptionType   uciOptionType
   193  	DefaultValue string
   194  	MinValue     string
   195  	MaxValue     string
   196  	VarValue     string
   197  	CurrentValue string
   198  }
   199  
   200  // optionMap convenience type for a map of pointers to uci options
   201  type optionMap map[string]*uciOption
   202  
   203  // uciOptions stores all available uci options
   204  var uciOptions optionMap
   205  
   206  // to control the sort order of all options
   207  var sortOrderUciOptions []string
   208  
   209  // ////////////////////////////////////////////////////////////////
   210  // HandlerFunc for uci options changes
   211  // ////////////////////////////////////////////////////////////////
   212  
   213  func printConfig(handler *UciHandler, option *uciOption) {
   214  	s := reflect.ValueOf(&Settings.Eval).Elem()
   215  	typeOfT := s.Type()
   216  	for i := s.NumField() - 1; i >= 0; i-- {
   217  		f := s.Field(i)
   218  		handler.SendInfoString(fmt.Sprintf("%-2d: %-22s %-6s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()))
   219  	}
   220  	handler.SendInfoString("Evaluation Config:\n")
   221  	s = reflect.ValueOf(&Settings.Search).Elem()
   222  	typeOfT = s.Type()
   223  	for i := s.NumField() - 1; i >= 0; i-- {
   224  		f := s.Field(i)
   225  		handler.SendInfoString(fmt.Sprintf("%-2d: %-22s %-6s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()))
   226  	}
   227  	handler.SendInfoString("Search Config:\n")
   228  	log.Debug(Settings.String())
   229  
   230  }
   231  
   232  func clearCache(u *UciHandler, o *uciOption) {
   233  	u.mySearch.ClearHash()
   234  	log.Debug("Cleared Cache")
   235  }
   236  
   237  func useCache(u *UciHandler, o *uciOption) {
   238  	v, _ := strconv.ParseBool(o.CurrentValue)
   239  	Settings.Search.UseTT = v
   240  	log.Debugf("Set Use Hash to %v", Settings.Search.UseTT)
   241  }
   242  
   243  func cacheSize(u *UciHandler, o *uciOption) {
   244  	v, _ := strconv.Atoi(o.CurrentValue)
   245  	Settings.Search.TTSize = v
   246  	u.mySearch.ResizeCache()
   247  }
   248  
   249  func useBook(u *UciHandler, o *uciOption) {
   250  	v, _ := strconv.ParseBool(o.CurrentValue)
   251  	Settings.Search.UseBook = v
   252  	log.Debugf("Set Use Book to %v", Settings.Search.UseBook)
   253  }
   254  
   255  func usePonder(u *UciHandler, o *uciOption) {
   256  	v, _ := strconv.ParseBool(o.CurrentValue)
   257  	Settings.Search.UsePonder = v
   258  	log.Debugf("Set Use Ponder to %v", Settings.Search.UsePonder)
   259  }
   260  
   261  func useQuiescence(u *UciHandler, o *uciOption) {
   262  	v, _ := strconv.ParseBool(o.CurrentValue)
   263  	Settings.Search.UseQuiescence = v
   264  	log.Debugf("Set Use Quiescence to %v", Settings.Search.UseQuiescence)
   265  }
   266  
   267  func useQSHash(u *UciHandler, o *uciOption) {
   268  	v, _ := strconv.ParseBool(o.CurrentValue)
   269  	Settings.Search.UseQSTT = v
   270  	log.Debugf("Set Use Hash in Quiescence to %v", Settings.Search.UseQSTT)
   271  }
   272  
   273  func usePvs(u *UciHandler, o *uciOption) {
   274  	v, _ := strconv.ParseBool(o.CurrentValue)
   275  	Settings.Search.UsePVS = v
   276  	log.Debugf("Set Use Principal Variation Search to %v", Settings.Search.UsePVS)
   277  }
   278  
   279  func useAsp(u *UciHandler, o *uciOption) {
   280  	v, _ := strconv.ParseBool(o.CurrentValue)
   281  	Settings.Search.UseAspiration = v
   282  	log.Debugf("Set Use Aspiration Search to %v", Settings.Search.UseAspiration)
   283  }
   284  
   285  func useMtdf(u *UciHandler, o *uciOption) {
   286  	v, _ := strconv.ParseBool(o.CurrentValue)
   287  	Settings.Search.UseMTDf = v
   288  	log.Debugf("Set Use MDTf Search to %v", Settings.Search.UseMTDf)
   289  }
   290  
   291  func useMdp(u *UciHandler, o *uciOption) {
   292  	v, _ := strconv.ParseBool(o.CurrentValue)
   293  	Settings.Search.UseMDP = v
   294  	log.Debugf("Set Use MDP to %v", Settings.Search.UseMDP)
   295  }
   296  
   297  func useKiller(u *UciHandler, o *uciOption) {
   298  	v, _ := strconv.ParseBool(o.CurrentValue)
   299  	Settings.Search.UseKiller = v
   300  	log.Debugf("Set Use Killer Moves to %v", Settings.Search.UseKiller)
   301  }
   302  
   303  func useHC(u *UciHandler, o *uciOption) {
   304  	v, _ := strconv.ParseBool(o.CurrentValue)
   305  	Settings.Search.UseHistoryCounter = v
   306  	log.Debugf("Set Use History Counter to %v", Settings.Search.UseHistoryCounter)
   307  }
   308  
   309  func useCM(u *UciHandler, o *uciOption) {
   310  	v, _ := strconv.ParseBool(o.CurrentValue)
   311  	Settings.Search.UseCounterMoves = v
   312  	log.Debugf("Set Use Counter Moves to %v", Settings.Search.UseCounterMoves)
   313  }
   314  
   315  func useNullMove(u *UciHandler, o *uciOption) {
   316  	v, _ := strconv.ParseBool(o.CurrentValue)
   317  	Settings.Search.UseNullMove = v
   318  	log.Debugf("Set Use Null Move Pruning to %v", Settings.Search.UseNullMove)
   319  }
   320  
   321  func useIID(u *UciHandler, o *uciOption) {
   322  	v, _ := strconv.ParseBool(o.CurrentValue)
   323  	Settings.Search.UseIID = v
   324  	log.Debugf("Set Use IID to %v", Settings.Search.UseIID)
   325  }
   326  
   327  func useLmr(u *UciHandler, o *uciOption) {
   328  	v, _ := strconv.ParseBool(o.CurrentValue)
   329  	Settings.Search.UseLmr = v
   330  	log.Debugf("Set use Late Move Reduction to %v", Settings.Search.UseLmr)
   331  }
   332  
   333  func useLmp(u *UciHandler, o *uciOption) {
   334  	v, _ := strconv.ParseBool(o.CurrentValue)
   335  	Settings.Search.UseLmp = v
   336  	log.Debugf("Set use Late Move Pruning to %v", Settings.Search.UseLmp)
   337  }
   338  
   339  func useSee(u *UciHandler, o *uciOption) {
   340  	v, _ := strconv.ParseBool(o.CurrentValue)
   341  	Settings.Search.UseSEE = v
   342  	log.Debugf("Set use SEE to %v", Settings.Search.UseSEE)
   343  }
   344  
   345  func usePromNonQuiet(u *UciHandler, o *uciOption) {
   346  	v, _ := strconv.ParseBool(o.CurrentValue)
   347  	Settings.Search.UsePromNonQuiet = v
   348  	log.Debugf("Set use Promotion as Non-quiet to %v", Settings.Search.UsePromNonQuiet)
   349  }
   350  
   351  func useExt(u *UciHandler, o *uciOption) {
   352  	v, _ := strconv.ParseBool(o.CurrentValue)
   353  	Settings.Search.UseExt = v
   354  	log.Debugf("Set use Extensions to %v", Settings.Search.UseExt)
   355  }
   356  
   357  func useExtAddDepth(u *UciHandler, o *uciOption) {
   358  	v, _ := strconv.ParseBool(o.CurrentValue)
   359  	Settings.Search.UseExtAddDepth = v
   360  	log.Debugf("Set use Extensions Add to Depth to %v", Settings.Search.UseExtAddDepth)
   361  }
   362  
   363  func useCheckExt(u *UciHandler, o *uciOption) {
   364  	v, _ := strconv.ParseBool(o.CurrentValue)
   365  	Settings.Search.UseCheckExt = v
   366  	log.Debugf("Set use Check Extension to %v", Settings.Search.UseCheckExt)
   367  }
   368  
   369  func useThreatExt(u *UciHandler, o *uciOption) {
   370  	v, _ := strconv.ParseBool(o.CurrentValue)
   371  	Settings.Search.UseThreatExt = v
   372  	log.Debugf("Set use Threat Extension to %v", Settings.Search.UseThreatExt)
   373  }
   374  
   375  func useRfp(u *UciHandler, o *uciOption) {
   376  	v, _ := strconv.ParseBool(o.CurrentValue)
   377  	Settings.Search.UseRFP = v
   378  	log.Debugf("Set use Reverse Futility Pruning (RFP) to %v", Settings.Search.UseRFP)
   379  }
   380  
   381  func useFp(u *UciHandler, o *uciOption) {
   382  	v, _ := strconv.ParseBool(o.CurrentValue)
   383  	Settings.Search.UseFP = v
   384  	log.Debugf("Set use Futility Pruning (FP) to %v", Settings.Search.UseFP)
   385  }
   386  
   387  func evalLazy(u *UciHandler, o *uciOption) {
   388  	v, _ := strconv.ParseBool(o.CurrentValue)
   389  	Settings.Eval.UseLazyEval = v
   390  	log.Debugf("Set use Lazy Eval to %v", Settings.Eval.UseLazyEval)
   391  }
   392  
   393  func evalMob(u *UciHandler, o *uciOption) {
   394  	v, _ := strconv.ParseBool(o.CurrentValue)
   395  	Settings.Eval.UseMobility = v
   396  	log.Debugf("Set use Eval Mobility to %v", Settings.Eval.UseMobility)
   397  }
   398  
   399  func evalAdv(u *UciHandler, o *uciOption) {
   400  	v, _ := strconv.ParseBool(o.CurrentValue)
   401  	Settings.Eval.UseAdvancedPieceEval = v
   402  	log.Debugf("Set use Adv Piece Eval to %v", Settings.Eval.UseAdvancedPieceEval)
   403  }