142 lines
5.2 KiB
C#
142 lines
5.2 KiB
C#
using System.Xml.Linq;
|
|
using LiquidCode.Tester.Common.Models;
|
|
|
|
namespace LiquidCode.Tester.Worker.Services;
|
|
|
|
/// <summary>
|
|
/// Parser for Polygon problem.xml format
|
|
/// </summary>
|
|
public class PolygonProblemXmlParser
|
|
{
|
|
private readonly ILogger<PolygonProblemXmlParser> _logger;
|
|
|
|
public PolygonProblemXmlParser(ILogger<PolygonProblemXmlParser> logger)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
public PolygonProblemDescriptor? ParseProblemXml(string xmlPath)
|
|
{
|
|
try
|
|
{
|
|
var doc = XDocument.Load(xmlPath);
|
|
var problem = doc.Element("problem");
|
|
|
|
if (problem == null)
|
|
{
|
|
_logger.LogWarning("Invalid problem.xml: root 'problem' element not found");
|
|
return null;
|
|
}
|
|
|
|
var judging = problem.Element("judging");
|
|
if (judging == null)
|
|
{
|
|
_logger.LogWarning("No 'judging' section found in problem.xml");
|
|
return null;
|
|
}
|
|
|
|
var testset = judging.Element("testset");
|
|
if (testset == null)
|
|
{
|
|
_logger.LogWarning("No 'testset' section found in problem.xml");
|
|
return null;
|
|
}
|
|
|
|
var descriptor = new PolygonProblemDescriptor
|
|
{
|
|
ShortName = problem.Attribute("short-name")?.Value ?? "unknown",
|
|
Revision = int.TryParse(problem.Attribute("revision")?.Value, out var rev) ? rev : 0
|
|
};
|
|
|
|
// Parse time limit (in milliseconds)
|
|
var timeLimitText = testset.Element("time-limit")?.Value;
|
|
if (int.TryParse(timeLimitText, out var timeLimit))
|
|
{
|
|
descriptor.TimeLimitMs = timeLimit;
|
|
}
|
|
|
|
// Parse memory limit (in bytes)
|
|
var memoryLimitText = testset.Element("memory-limit")?.Value;
|
|
if (long.TryParse(memoryLimitText, out var memoryLimit))
|
|
{
|
|
descriptor.MemoryLimitMb = (int)(memoryLimit / (1024 * 1024)); // Convert bytes to MB
|
|
}
|
|
|
|
// Parse test count
|
|
var testCountText = testset.Element("test-count")?.Value;
|
|
if (int.TryParse(testCountText, out var testCount))
|
|
{
|
|
descriptor.TestCount = testCount;
|
|
}
|
|
|
|
// Parse path patterns
|
|
descriptor.InputPathPattern = testset.Element("input-path-pattern")?.Value ?? "tests/%02d";
|
|
descriptor.AnswerPathPattern = testset.Element("answer-path-pattern")?.Value ?? "tests/%02d.a";
|
|
|
|
// Parse solutions to find main solution
|
|
var assets = problem.Element("assets");
|
|
if (assets != null)
|
|
{
|
|
var solutions = assets.Element("solutions");
|
|
if (solutions != null)
|
|
{
|
|
// Try to find main solution first
|
|
var mainSolution = solutions.Elements("solution")
|
|
.FirstOrDefault(s => s.Attribute("tag")?.Value == "main");
|
|
|
|
// If no main solution, try to find any accepted solution
|
|
if (mainSolution == null)
|
|
{
|
|
mainSolution = solutions.Elements("solution")
|
|
.FirstOrDefault(s => s.Attribute("tag")?.Value == "accepted");
|
|
}
|
|
|
|
if (mainSolution != null)
|
|
{
|
|
var source = mainSolution.Element("source");
|
|
if (source != null)
|
|
{
|
|
descriptor.MainSolutionPath = source.Attribute("path")?.Value;
|
|
descriptor.MainSolutionType = source.Attribute("type")?.Value;
|
|
|
|
_logger.LogInformation("Found main solution: {Path} (type: {Type})",
|
|
descriptor.MainSolutionPath, descriptor.MainSolutionType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("No main or accepted solution found in problem.xml");
|
|
}
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation(
|
|
"Parsed problem.xml: {ShortName} (rev {Revision}), {TestCount} tests, TL={TimeLimit}ms, ML={MemoryLimit}MB",
|
|
descriptor.ShortName, descriptor.Revision, descriptor.TestCount, descriptor.TimeLimitMs, descriptor.MemoryLimitMb);
|
|
|
|
return descriptor;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to parse problem.xml at {Path}", xmlPath);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Descriptor parsed from problem.xml
|
|
/// </summary>
|
|
public class PolygonProblemDescriptor
|
|
{
|
|
public string ShortName { get; set; } = string.Empty;
|
|
public int Revision { get; set; }
|
|
public int TimeLimitMs { get; set; } = 2000;
|
|
public int MemoryLimitMb { get; set; } = 256;
|
|
public int TestCount { get; set; }
|
|
public string InputPathPattern { get; set; } = "tests/%02d";
|
|
public string AnswerPathPattern { get; set; } = "tests/%02d.a";
|
|
public string? MainSolutionPath { get; set; }
|
|
public string? MainSolutionType { get; set; }
|
|
}
|