update polygon package parsing & testing
This commit is contained in:
141
src/LiquidCode.Tester.Worker/Services/PolygonProblemXmlParser.cs
Normal file
141
src/LiquidCode.Tester.Worker/Services/PolygonProblemXmlParser.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
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; }
|
||||
}
|
||||
Reference in New Issue
Block a user