1+ """
2+ Generate configuration files for tournaments between pairs of models in specified arenas.
3+
4+ Each configuration file specifies a tournament between two models in a given arena,
5+ including the number of rounds and simulations per round. The configurations are saved
6+ as YAML files in the specified output directory (default: configs/main/).
7+
8+ Also generates a tracking JSON file at configs/tracker.json to keep track of
9+ the number of tournaments and rounds played for each pair of models in each arena.
10+
11+ Usage:
12+
13+ python codeclash/utils/generate_confs.py -m configs/models.yaml -r 15 -s 1000
14+ """
15+
116import argparse
217import json
318from pathlib import Path
419
520import yaml
621
722from codeclash .games import (
8- BattleCodeGame ,
9- BattleSnakeGame ,
23+ ARENAS ,
1024 CodeGame ,
11- CoreWarGame ,
12- HuskyBenchGame ,
25+ DummyGame ,
1326 RoboCodeGame ,
14- RobotRumbleGame ,
1527)
1628
1729
@@ -37,19 +49,12 @@ def literal_representer(dumper, data):
3749yaml .SafeDumper .add_representer (IncludeTag , include_representer )
3850yaml .SafeDumper .add_representer (LiteralString , literal_representer )
3951
40- ARENAS : list [CodeGame ] = [
41- BattleCodeGame ,
42- BattleSnakeGame ,
43- CoreWarGame ,
44- HuskyBenchGame ,
45- RoboCodeGame ,
46- RobotRumbleGame ,
47- ]
4852
4953NUM_TOURNAMENTS = 10
54+ TRACKING_PATH = "configs/tracker.json"
5055
5156
52- def prompt_game_desc (arena , rounds ):
57+ def prompt_game_desc (arena , rounds , players ):
5358 # Return as a LiteralString to get proper YAML literal block scalar formatting
5459 content = f"""You are a software developer ({{{{player_id}}}}) competing in a coding game called { arena .name } .
5560{ arena .description }
@@ -63,6 +68,41 @@ def prompt_game_desc(arena, rounds):
6368 return LiteralString (content )
6469
6570
71+ def get_config (rounds : int , simulations : int , arena : CodeGame , players : list [dict ], prompt_func = prompt_game_desc ):
72+ return {
73+ "tournament" : {
74+ "rounds" : rounds ,
75+ },
76+ "game" : {
77+ "name" : arena .name ,
78+ "sims_per_round" : simulations ,
79+ "args" : arena .default_args ,
80+ },
81+ "players" : [
82+ {
83+ "agent" : "mini" ,
84+ "name" : get_name (p ),
85+ "config" : {"agent" : IncludeTag ("mini/default.yaml" ), "model" : p },
86+ }
87+ for p in players
88+ ],
89+ "prompts" : {"game_description" : prompt_func (arena , rounds , players )},
90+ }
91+
92+
93+ def clean_config (config_path : str ):
94+ # Post-process to remove quotes around include paths
95+ with open (config_path ) as f :
96+ content = f .read ()
97+
98+ # Remove quotes around include paths
99+ content = content .replace ("!include 'mini/" , "!include mini/" )
100+ content = content .replace (".yaml'" , ".yaml" )
101+
102+ with open (config_path , "w" ) as f :
103+ f .write (content )
104+
105+
66106def get_name (p ):
67107 return p ["model_name" ].split ("/" )[- 1 ]
68108
@@ -84,32 +124,16 @@ def main(models, arenas, rounds: int, simulations: int, record_ratio: float, out
84124
85125 tracking_dict = {}
86126 arenas_list = ARENAS if arenas == "all" else [a for a in ARENAS if a .name in arenas .split ("," )]
127+ if DummyGame in arenas_list :
128+ arenas_list .remove (DummyGame ) # Skip DummyGame for config generation
87129 if not arenas_list :
88130 print (f"No valid arenas found from { arenas } . Choose from { [a .name for a in ARENAS ]} ." )
89131 return # Stop execution if no valid arenas are found
90132 for arena in arenas_list :
91133 print (f"Generating { len (pairs )} configs for arena: { arena .name } " )
92134 tracking_dict [arena .name ] = {}
93135 for pair in pairs :
94- config = {
95- "tournament" : {
96- "rounds" : rounds ,
97- },
98- "game" : {
99- "name" : arena .name ,
100- "sims_per_round" : simulations ,
101- "args" : arena .default_args ,
102- },
103- "players" : [
104- {
105- "agent" : "mini" ,
106- "name" : get_name (p ),
107- "config" : {"agent" : IncludeTag ("mini/default.yaml" ), "model" : p },
108- }
109- for p in pair
110- ],
111- "prompts" : {"game_description" : prompt_game_desc (arena , rounds )},
112- }
136+ config = get_config (rounds , simulations , arena , pair )
113137
114138 if arena == RoboCodeGame :
115139 robocode_adjustments (config , record_ratio )
@@ -127,34 +151,24 @@ def main(models, arenas, rounds: int, simulations: int, record_ratio: float, out
127151 Dumper = yaml .SafeDumper ,
128152 )
129153
130- # Post-process to remove quotes around include paths
131- with open (output / config_name ) as f :
132- content = f .read ()
133-
134- # Remove quotes around include paths
135- content = content .replace ("!include 'mini/" , "!include mini/" )
136- content = content .replace (".yaml'" , ".yaml" )
137-
138- with open (output / config_name , "w" ) as f :
139- f .write (content )
154+ clean_config (output / config_name )
140155
141156 pvp = "." .join (sorted ([get_name (pair [0 ]), get_name (pair [1 ])]))
142157 tracking_key = f"r{ rounds } .s{ simulations } .p2"
143158 if tracking_key not in tracking_dict [arena .name ]:
144159 tracking_dict [arena .name ][tracking_key ] = {}
145160 tracking_dict [arena .name ][tracking_key ][pvp ] = 0
146161
147- tracking_path = "configs/scripts/main_tracker.json"
148- if Path (tracking_path ).exists ():
149- with open (tracking_path ) as f :
162+ if Path (TRACKING_PATH ).exists ():
163+ with open (TRACKING_PATH ) as f :
150164 tracking_dict_current = json .load (f )
151165 tracking_dict .update (tracking_dict_current )
152166
153- with open (tracking_path , "w" ) as f :
167+ with open (TRACKING_PATH , "w" ) as f :
154168 json .dump (tracking_dict , f , indent = 2 )
155- print (f"Wrote tracking file to '{ tracking_path } '." )
169+ print (f"Wrote tracking file to '{ TRACKING_PATH } '." )
156170
157- print (f"Generated { len (pairs ) * len (arenas )} configuration files in '{ output } '." )
171+ print (f"Generated { len (pairs ) * len (arenas_list )} configuration files in '{ output } '." )
158172 print (f"- # Models: { len (models )} " )
159173 print (f"- # Arenas: { len (ARENAS )} " )
160174 print (f"- r (rounds) { rounds } " )
@@ -173,7 +187,7 @@ def main(models, arenas, rounds: int, simulations: int, record_ratio: float, out
173187 "-m" ,
174188 "--models" ,
175189 type = str ,
176- default = "configs/scripts/ models.yaml" ,
190+ default = "configs/models.yaml" ,
177191 help = "Path to model configurations." ,
178192 )
179193 parser .add_argument (
0 commit comments