2 # -*- coding: utf-8 -*-
5 Usage: clop-cutechess-cli.py CPU_ID SEED [PARAM_NAME PARAM_VALUE]...
6 Run cutechess-cli with CLOP_PARAM(s).
8 CPU_ID Symbolic name of the CPU or machine that should run the game
9 SEED Running number for the game to be played
10 PARAM_NAME Name of a parameter that's being optimized
11 PARAM_VALUE Integer value for parameter PARAM_NAME
13 CLOP is a black-box parameter tuning tool designed and written by RĂ©mi Coulom.
14 More information about CLOP can be found at the CLOP website:
15 http://remi.coulom.free.fr/CLOP/
17 This script works between CLOP and cutechess-cli. The path to this script,
18 without any parameters, should be on the "Script" line of the .clop file.
19 'Replications' in the .clop file should be set to 2 so that this script can
20 alternate the engine's playing side correctly.
22 In this script the variables 'cutechess_cli_path', 'engine', 'engine_param_cmd',
23 'opponents' and 'options' must be modified to fit the test environment and
24 conditions. The default values are just examples.
26 When the game is completed the script writes the game outcome to its
33 from subprocess
import Popen
, PIPE
38 # Path to the cutechess-cli executable.
39 # On Windows this should point to cutechess-cli.exe
40 cutechess_cli_path
= 'path_to_cutechess-cli/cutechess-cli.sh'
42 # The engine whose parameters will be optimized
43 engine
= 'conf=MyEngine'
45 # Format for the commands that are sent to the engine to
46 # set the parameter values. When the command is sent,
47 # {name} will be replaced with the parameter name and {value}
48 # with the parameter value.
49 engine_param_cmd
= 'setvalue {name} {value}'
51 # A pool of opponents for the engine. The opponent will be
52 # chosen based on the seed sent by CLOP.
54 'conf=OpponentEngine1',
55 'conf=OpponentEngine2',
56 'conf=OpponentEngine3'
59 # Additional cutechess-cli options, eg. time control and opening book
60 options
= '-each tc=40/1+0.05 -draw 80 1 -resign 5 500'
63 def main(argv
= None):
67 if len(argv
) == 0 or argv
[0] == '--help':
72 if len(argv
) < 3 or len(argv
) % 2 == 0:
73 print 'Too few arguments'
78 clop_seed
= int(argv
[0])
79 except exceptions
.ValueError:
80 print 'Invalid seed value: %s' % argv
[0]
84 scp
= opponents
[(clop_seed
>> 1) % len(opponents
)]
86 # Parse the parameters that should be optimized
87 for i
in range(1, len(argv
), 2):
88 # Make sure the parameter value is numeric
91 except exceptions
.ValueError:
92 print 'Invalid value for parameter %s: %s' % (argv
[i
], argv
[i
+ 1])
94 # Pass CLOP's parameters to the engine by using
95 # cutechess-cli's initialization string feature
96 initstr
= engine_param_cmd
.format(name
= argv
[i
], value
= argv
[i
+ 1])
97 fcp
+= ' initstr="%s"' % initstr
99 # Choose the engine's playing side (color) based on CLOP's seed
100 if clop_seed
% 2 != 0:
103 cutechess_args
= '-engine %s -engine %s %s' % (fcp
, scp
, options
)
104 command
= '%s %s' % (cutechess_cli_path
, cutechess_args
)
106 # Run cutechess-cli and wait for it to finish
107 process
= Popen(command
, shell
= True, stdout
= PIPE
)
108 output
= process
.communicate()[0]
109 if process
.returncode
!= 0:
110 print 'Could not execute command: %s' % command
113 # Convert Cutechess-cli's result into W/L/D
114 # Note that only one game should be played
116 for line
in output
.splitlines():
117 if line
.startswith('Finished game'):
118 if line
.find(": 1-0") != -1:
119 result
= clop_seed
% 2
120 elif line
.find(": 0-1") != -1:
121 result
= (clop_seed
% 2) ^
1
122 elif line
.find(": 1/2-1/2") != -1:
125 print 'The game did not terminate properly'
136 if __name__
== "__main__":