public INIParser(INIParser other) { using (var s = new StringReader(other.ToString())) Parse(s, INIMode.CompactEquals); } // TODO: Improve perf
static void Main(string[] args) { try { if (args.Length != 1) { throw new ArgumentException($"Received {args.Length} arguments, expected 1. Usage: 'RLBotAutoRunner.exe <path to configuration file>'"); } // TODO: Detect and report invalid config var config = new INIParser(args[0], INIMode.SpacedEquals); var botFilter = config["Autorunner Configuration", "header_filter"]; var teamSize = int.Parse(config["Autorunner Configuration", "team_size"]); var breakLengthParsed = double.TryParse(config["Autorunner Configuration", "break_length"], out var breakLengthSeconds); Enum.TryParse(config["Autorunner Configuration", "size_override"], out SizeOverride sizeOverride); var tourneyTypeString = config["Tournament Configuration", "type"]; var matchRunner = new MatchRunner(config, breakLengthParsed ? new TimeSpan((long)(breakLengthSeconds * TimeSpan.TicksPerSecond)) : TimeSpan.Zero); var tourneyType = Enum.TryParse(tourneyTypeString, out Tournament.Type type) ? type : throw new InvalidDataException($"Configuration specified tournament type '{tourneyTypeString}', which doesn't exist."); Console.WriteLine($"Searching for metadata files containing section '[{botFilter}]'...\n"); var teams = new List <Team>(); foreach (var file in Directory.EnumerateFiles(@".\", "*.metadata", SearchOption.AllDirectories)) { var dir = Path.GetDirectoryName(file); string FullPath(string path) => Path.GetFullPath(Path.Combine(dir, path)); var ini = new INIParser(file, INIMode.SpacedEquals); Console.WriteLine($"Found metadata file '{file}'. Showing stripped contents:"); Console.WriteLine(ini.ToString(INIMode.SpacedEquals)); var name = ini[botFilter, "team"]; var cfgs = ini[botFilter, "cfgs"]; var sel = ini[botFilter, "cfg_selection"]; var res = ini[botFilter, "resources"]; var size = ini[botFilter, "size"]; if (name?.Length > 0 && cfgs?.Length > 0) { // TODO: Error handling Console.WriteLine($"Metadata file contains appropriate section. Adding '{name}' to list of participants..."); var parsedRes = new List <IUniqueResource>(); foreach (var r in res != null ? res.Split(';') : new string[0]) { if (UniqueResource.TryParse(FullPath(r), out var p)) { parsedRes.Add(p); } } var fullCfgs = cfgs.Split(';'); for (int i = 0; i < fullCfgs.Length; ++i) { fullCfgs[i] = FullPath(fullCfgs[i]); } teams.Add(new Team( name, int.TryParse(size, out var desiredSize) && (sizeOverride == SizeOverride.Any || (sizeOverride == SizeOverride.HandicapOnly && desiredSize < teamSize)) ? desiredSize : teamSize, GetCfgPool(Enum.TryParse(sel, out CfgSelectionMode desiredSel) ? desiredSel : CfgSelectionMode.SequentialRepeat, fullCfgs), parsedRes )); } } Tournament.Run(teams.ToArray(), matchRunner, tourneyType, config); } catch (Exception e) { Console.Error.WriteLine(e.Message); } }
public MatchRunner(INIParser baseIni, TimeSpan?breakLength = null) { this.baseIni = baseIni; this.breakLength = breakLength ?? TimeSpan.Zero; }
public static IEnumerable <MatchResult> Run(Team[] teams, MatchRunner runner, Type type, INIParser config) { Program.Random.Shuffle(teams); switch (type) { case Type.RoundRobin: for (int i = 0; i < teams.Length; ++i) { for (int j = i + 1; j < teams.Length; ++j) { yield return(runner.Run(teams[i], teams[j])); } } break; case Type.Gauntlet: var challengerName = config["Tournament Config", "challenger"]; var challengerIndex = Array.FindIndex(teams, t => t.Name == challengerName); var challenger = teams[challengerIndex]; for (int i = 0; i < challengerIndex; ++i) { yield return(runner.Run(challenger, teams[i])); } for (int i = challengerIndex + 1; i < teams.Length; ++i) { yield return(runner.Run(challenger, teams[i])); } break; default: break; } }