진행 시간 표시 추가 및 231~250 스테이지 체크포인트 반영
This commit is contained in:
55
Program.cs
55
Program.cs
@@ -161,8 +161,9 @@ internal static class Program
|
||||
|
||||
var rng = new Random(seed);
|
||||
var levelBands = LoadLevelBands();
|
||||
var totalWatch = Stopwatch.StartNew();
|
||||
var status = new StatusReporter();
|
||||
var generator = new LevelGenerator(rng, Tuning, levelBands, status);
|
||||
var generator = new LevelGenerator(rng, Tuning, levelBands, status, totalWatch);
|
||||
|
||||
var startId = levelBands.Min(b => b.StartId);
|
||||
var endId = levelBands.Max(b => b.EndId);
|
||||
@@ -208,7 +209,6 @@ internal static class Program
|
||||
}
|
||||
}
|
||||
|
||||
var totalWatch = Stopwatch.StartNew();
|
||||
var levels = generator.BuildRange(startId, endId, SaveCheckpoint);
|
||||
totalWatch.Stop();
|
||||
|
||||
@@ -458,13 +458,15 @@ internal sealed class LevelGenerator
|
||||
private readonly HashSet<string> _seenLayouts = new();
|
||||
private readonly HashSet<string> _seenPatterns = new();
|
||||
private readonly StatusReporter _status;
|
||||
private readonly Stopwatch _totalWatch;
|
||||
|
||||
public LevelGenerator(Random rng, GenerationTuning tuning, IReadOnlyList<LevelBandConfig> bands, StatusReporter status)
|
||||
public LevelGenerator(Random rng, GenerationTuning tuning, IReadOnlyList<LevelBandConfig> bands, StatusReporter status, Stopwatch totalWatch)
|
||||
{
|
||||
_rng = rng;
|
||||
_tuning = tuning;
|
||||
_bands = bands;
|
||||
_status = status;
|
||||
_totalWatch = totalWatch;
|
||||
_trace = Environment.GetEnvironmentVariable("NEKOBAN_DEBUG") == "1";
|
||||
}
|
||||
|
||||
@@ -483,7 +485,8 @@ internal sealed class LevelGenerator
|
||||
for (var id = startId; id <= endId; id++)
|
||||
{
|
||||
var band = ResolveBand(id);
|
||||
var level = BuildSingle(id, band);
|
||||
var levelStopwatch = Stopwatch.StartNew();
|
||||
var level = BuildSingle(id, band, levelStopwatch);
|
||||
level = TrimLevel(level);
|
||||
output.Add(level);
|
||||
onCheckpoint?.Invoke(output, id);
|
||||
@@ -502,7 +505,7 @@ internal sealed class LevelGenerator
|
||||
return new PocketSettings(min, max, radius);
|
||||
}
|
||||
|
||||
private GeneratedLevel BuildSingle(int id, LevelBandConfig band)
|
||||
private GeneratedLevel BuildSingle(int id, LevelBandConfig band, Stopwatch levelStopwatch)
|
||||
{
|
||||
// 완화 단계를 순차적으로 적용한다. (총 5단계 + 비상 1단계)
|
||||
var stages = new List<RelaxStage>
|
||||
@@ -546,26 +549,7 @@ internal sealed class LevelGenerator
|
||||
c.MinBoxDistance = Math.Max(1, c.MinBoxDistance - 1);
|
||||
c.MinWallDistance = Math.Max(0, c.MinWallDistance - 1);
|
||||
return c;
|
||||
}),
|
||||
new RelaxStage("완화6-최종", bandConfig =>
|
||||
{
|
||||
var c = CloneBand(bandConfig);
|
||||
c.BoxCountLow = 1;
|
||||
c.BoxCountHigh = Math.Max(1, c.BoxCountHigh - 2);
|
||||
c.MinAllowedPushes = 1;
|
||||
c.MinAllowedTurns = 0;
|
||||
c.MinAllowedBranching = 0;
|
||||
c.MinGoalDistance = Math.Max(1, c.MinGoalDistance - 2);
|
||||
c.MinBoxDistance = Math.Max(1, c.MinBoxDistance - 2);
|
||||
c.MinWallDistance = 0;
|
||||
c.ReverseDepthScale = Math.Max(1.0, c.ReverseDepthScale * 2.8);
|
||||
c.ReverseBreadthScale = Math.Max(1.0, c.ReverseBreadthScale * 2.8);
|
||||
c.MaskPadMin = -2;
|
||||
c.MaskPadMax = -2;
|
||||
c.ShapeMasks = MaskLibrary.Medium.Concat(MaskLibrary.Microban).ToList();
|
||||
c.ShapeMasksExpanded = null;
|
||||
return c;
|
||||
}, OverrideRelaxSteps: 6)
|
||||
})
|
||||
};
|
||||
|
||||
// 밴드 강등 시도: 현재 밴드 -> 직전 10레벨 밴드 -> 직전 20레벨 밴드
|
||||
@@ -584,10 +568,10 @@ internal sealed class LevelGenerator
|
||||
}
|
||||
|
||||
// 시드 변조 재시도 + 완화 단계 루프
|
||||
const int seedRetries = 5;
|
||||
foreach (var bandCandidate in bandCandidates)
|
||||
var retry = 0;
|
||||
while (true)
|
||||
{
|
||||
for (var retry = 0; retry < seedRetries; retry++)
|
||||
foreach (var bandCandidate in bandCandidates)
|
||||
{
|
||||
var jitterSeed = _rng.Next() ^ (id * 7919) ^ (retry * 104729);
|
||||
var localRng = new Random(jitterSeed);
|
||||
@@ -596,18 +580,17 @@ internal sealed class LevelGenerator
|
||||
{
|
||||
var bandForStage = stage.Adjust(bandCandidate);
|
||||
var relaxOverride = stage.OverrideRelaxSteps;
|
||||
if (TryBuildStage(id, bandForStage, stage.Label, localRng, relaxOverride, out var level))
|
||||
if (TryBuildStage(id, bandForStage, stage.Label, localRng, relaxOverride, levelStopwatch, out var level))
|
||||
{
|
||||
return level;
|
||||
}
|
||||
}
|
||||
}
|
||||
retry++;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"레벨 {id} 생성 실패 (모든 완화 단계 시도됨)");
|
||||
}
|
||||
|
||||
private bool TryBuildStage(int id, LevelBandConfig band, string stageLabel, Random rng, int? overrideRelaxSteps, out GeneratedLevel level)
|
||||
private bool TryBuildStage(int id, LevelBandConfig band, string stageLabel, Random rng, int? overrideRelaxSteps, Stopwatch levelStopwatch, out GeneratedLevel level)
|
||||
{
|
||||
var failReasons = _trace ? new Dictionary<string, int>() : null;
|
||||
var baseMasks = band.ShapeMasks.Count > 0 ? band.ShapeMasks : MaskLibrary.Microban;
|
||||
@@ -631,16 +614,16 @@ internal sealed class LevelGenerator
|
||||
var reverseDepth = Math.Max(16, (int)Math.Round(_tuning.ReverseSearchMaxDepth * depthScale));
|
||||
var reverseBreadth = Math.Max(200, (int)Math.Round(_tuning.ReverseSearchBreadth * breadthScale));
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var stageStopwatch = Stopwatch.StartNew();
|
||||
var attempts = 0;
|
||||
|
||||
while (attempts < attemptsLimit &&
|
||||
stopwatch.ElapsedMilliseconds < timeLimit)
|
||||
stageStopwatch.ElapsedMilliseconds < timeLimit)
|
||||
{
|
||||
attempts++;
|
||||
// 진행 상태가 살아 있음을 보여주기 위해, 1초 단위 점(.) 애니메이션을 출력한다.
|
||||
// 예) "레벨 214 [기본] 생성중.", "..", "..." 식으로 순환.
|
||||
_status.Show($"레벨 {id} [{stageLabel}] 생성중", withDots: true);
|
||||
_status.ShowProgress($"레벨 {id} [{stageLabel}] 생성중", levelStopwatch.Elapsed, _totalWatch.Elapsed);
|
||||
var mask = MaskLibrary.CreateVariant(
|
||||
MaskLibrary.PickRandom(rng, band.ShapeMasksExpanded),
|
||||
rng,
|
||||
@@ -734,7 +717,7 @@ internal sealed class LevelGenerator
|
||||
_seenPatterns.Add(patternKey);
|
||||
}
|
||||
|
||||
_status.Show($"레벨 {id} [{stageLabel}] 생성완료 ({StatusReporter.FormatDuration(stopwatch.Elapsed)})");
|
||||
_status.Show($"레벨 {id} [{stageLabel}] 생성완료 ({StatusReporter.FormatDuration(levelStopwatch.Elapsed)})");
|
||||
level = new GeneratedLevel
|
||||
{
|
||||
Id = id,
|
||||
|
||||
Reference in New Issue
Block a user