그리드 트리밍/검증 리포트 확장
This commit is contained in:
120
Program.cs
120
Program.cs
@@ -101,6 +101,28 @@ internal static class Program
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// 트리밍 모드: --trim <입력 json> [출력 json] [startId] [endId]
|
||||
if (args.Length > 0 && args[0].Equals("--trim", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.Error.WriteLine("사용법: dotnet run -- --trim <입력 json> [출력 json] [startId] [endId]");
|
||||
return;
|
||||
}
|
||||
|
||||
var input = args[1];
|
||||
var output = args.Length >= 3 && !args[2].StartsWith("--", StringComparison.Ordinal) ? args[2] : "trimmed_output.json";
|
||||
var argOffset = args.Length >= 3 && !args[2].StartsWith("--", StringComparison.Ordinal) ? 3 : 2;
|
||||
|
||||
int? trimStart = null;
|
||||
int? trimEnd = null;
|
||||
if (args.Length > argOffset && int.TryParse(args[argOffset], out var ts)) trimStart = ts;
|
||||
if (args.Length > argOffset + 1 && int.TryParse(args[argOffset + 1], out var te)) trimEnd = te;
|
||||
|
||||
RunTrim(input, output, trimStart, trimEnd);
|
||||
return;
|
||||
}
|
||||
|
||||
// 검증 모드: --verify <json 경로> <id> [endId]
|
||||
if (args.Length > 0 && args[0].Equals("--verify", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -261,6 +283,71 @@ internal static class Program
|
||||
Console.WriteLine($"[verify] 완료: 성공 {ok}/{targets.Count} (범위 {startId}~{endId})");
|
||||
}
|
||||
|
||||
private static void RunTrim(string inputPath, string outputPath, int? startId, int? endId)
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
if (!File.Exists(inputPath))
|
||||
{
|
||||
Console.Error.WriteLine($"파일을 찾을 수 없습니다: {inputPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
List<GeneratedLevel>? levels;
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(inputPath);
|
||||
levels = JsonSerializer.Deserialize<List<GeneratedLevel>>(json, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"[trim] JSON을 읽거나 파싱하는 데 실패했습니다: {ex.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels == null || levels.Count == 0)
|
||||
{
|
||||
Console.Error.WriteLine("[trim] 레벨 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (startId.HasValue && endId.HasValue && startId > endId)
|
||||
{
|
||||
(startId, endId) = (endId, startId);
|
||||
}
|
||||
|
||||
var trimmed = new List<GeneratedLevel>(levels.Count);
|
||||
foreach (var level in levels)
|
||||
{
|
||||
if (startId.HasValue && level.Id < startId.Value) { trimmed.Add(level); continue; }
|
||||
if (endId.HasValue && level.Id > endId.Value) { trimmed.Add(level); continue; }
|
||||
|
||||
var newGrid = LevelTrimmer.Trim(level.Grid);
|
||||
trimmed.Add(new GeneratedLevel
|
||||
{
|
||||
Id = level.Id,
|
||||
Grid = newGrid,
|
||||
LowestPush = level.LowestPush,
|
||||
PushLimit = level.PushLimit
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(trimmed, options);
|
||||
File.WriteAllText(outputPath, json);
|
||||
Console.WriteLine($"[trim] 완료: {inputPath} -> {outputPath} (대상 id {startId ?? int.MinValue}~{endId ?? int.MaxValue})");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"[trim] 저장 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static LevelBandConfig[] LoadLevelBands()
|
||||
{
|
||||
try
|
||||
@@ -745,6 +832,39 @@ internal sealed class LevelGenerator
|
||||
}
|
||||
}
|
||||
|
||||
internal static class LevelTrimmer
|
||||
{
|
||||
// 그리드에서 바깥쪽이 전부 '0'인 행/열을 제거해 압축한다.
|
||||
public static List<string> Trim(List<string> grid)
|
||||
{
|
||||
if (grid.Count == 0) return grid;
|
||||
var height = grid.Count;
|
||||
var width = grid.Max(r => r.Length);
|
||||
if (width == 0) return grid;
|
||||
|
||||
// 패딩하여 동일 너비로 정규화
|
||||
var padded = grid.Select(r => r.PadRight(width, '0')).ToArray();
|
||||
|
||||
// 유지할 행/열 계산
|
||||
var keepRows = Enumerable.Range(0, height)
|
||||
.Where(y => padded[y].Any(ch => ch != '0'))
|
||||
.ToList();
|
||||
var keepCols = Enumerable.Range(0, width)
|
||||
.Where(x => padded.Any(row => row[x] != '0'))
|
||||
.ToList();
|
||||
|
||||
if (keepRows.Count == 0 || keepCols.Count == 0) return grid;
|
||||
|
||||
var trimmed = new List<string>(keepRows.Count);
|
||||
foreach (var y in keepRows)
|
||||
{
|
||||
var chars = keepCols.Select(x => padded[y][x]).ToArray();
|
||||
trimmed.Add(new string(chars));
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly record struct ParsedLevel(Board Board, int Player, int[] Boxes, HashSet<int> Goals);
|
||||
|
||||
internal readonly record struct VerificationResult(int Id, bool Success, int? Moves, int? Pushes, int? Turns, string? ErrorMessage);
|
||||
|
||||
Reference in New Issue
Block a user