feat: expand masks, structural filters, and solution similarity dedupe

This commit is contained in:
JiWoong Sul
2025-11-22 02:13:14 +09:00
parent a3b6dc0ce4
commit 8c351c5c05
5 changed files with 796 additions and 117 deletions

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
@@ -209,19 +210,161 @@ internal static class MaskLibrary
}
};
// 중형(약 11~13) 마스크: Microban보다 넓은 홀과 복도 길이를 제공.
public static readonly List<string[]> Medium = new()
{
new[]{
"00000000000",
"00#######00",
"00#.....#00",
"0##.###.##0",
"0#..#.#..#0",
"0#.......#0",
"0#..#.#..#0",
"0##.###.##0",
"00#.....#00",
"00#######00",
"00000000000"
},
new[]{
"0000000000000",
"000#######000",
"00##.....##00",
"00#..###..#00",
"0##.......##0",
"0#..#...#..#0",
"0##.......##0",
"00#..###..#00",
"00##.....##00",
"000#######000",
"0000000000000"
},
new[]{
"000000000000",
"00########00",
"00#......#00",
"0##.####.##0",
"0#..#..#..#0",
"0#..#..#..#0",
"0##.####.##0",
"00#......#00",
"00###..###00",
"000#....#000",
"000######000",
"000000000000"
},
new[]{
"000000000000",
"000######000",
"000#....#000",
"0###.##.###0",
"0#......#.#0",
"0#.##.##..#0",
"0#..#.....#0",
"0###.##.###0",
"000#....#000",
"000######000",
"000000000000"
},
new[]{
"0000000000000",
"000#######000",
"000#.....#000",
"0###.###.###0",
"0#...#.#...#0",
"0#...#.#...#0",
"0###.###.###0",
"000#.....#000",
"000#######000",
"0000000000000"
}
};
// 대형(약 15~16) 마스크: 입구/포켓이 늘어나고, 복도 길이가 길다.
public static readonly List<string[]> Large = new()
{
new[]{
"000000000000000",
"000#########000",
"000#.......#000",
"00##.#####.##00",
"00#..#...#..#00",
"0##..#...#..##0",
"0#...#...#...#0",
"0#...#####...#0",
"0#...........#0",
"0##..#...#..##0",
"00#..#...#..#00",
"00##.#####.##00",
"000#.......#000",
"000#########000",
"000000000000000"
},
new[]{
"000000000000000",
"000#########000",
"000#.......#000",
"00##.#####.##00",
"00#..#...#..#00",
"0##..#.#.#..##0",
"0#...##.##...#0",
"0#...#...#...#0",
"0#...##.##...#0",
"0##..#.#.#..##0",
"00#..#...#..#00",
"00##.#####.##00",
"000#.......#000",
"000#########000",
"000000000000000"
},
new[]{
"0000000000000000",
"0000#########000",
"0000#.......#000",
"00###.#####.###0",
"00#..#.....#..#0",
"0##..##...##..##",
"0#....#...#....#",
"0#.#..#####..#.#",
"0#....#...#....#",
"0##..##...##..##",
"00#..#.....#..#0",
"00###.#####.###0",
"0000#.......#000",
"0000#########000",
"0000000000000000"
},
new[]{
"000000000000000",
"000##########00",
"000#........#00",
"00##.######.#00",
"00#..#....#.#00",
"0##..#....#..##",
"0#...#.##.#...#",
"0#...#....#...#",
"0##..#....#..##",
"00#..#....#.#00",
"00##.######.#00",
"000#........#00",
"000##########00",
"000000000000000"
}
};
public static string[] PickRandom(Random rng, List<string[]> masks)
{
if (masks.Count == 0) throw new System.InvalidOperationException("No masks provided.");
return masks[rng.Next(masks.Count)];
}
public static List<string[]> ExpandWithTransforms(IEnumerable<string[]> baseMasks, bool includeScaled = true)
public static List<string[]> ExpandWithTransforms(IEnumerable<string[]> baseMasks, int padMin = -1, int padMax = 1)
{
var seen = new HashSet<string>();
var output = new List<string[]>();
foreach (var mask in baseMasks)
{
var seeds = includeScaled ? ScaleVariants(mask) : new List<string[]> { mask };
var seeds = ScaleVariants(mask, padMin, padMax);
foreach (var seed in seeds)
{
foreach (var variant in Variants(seed))
@@ -345,14 +488,34 @@ internal static class MaskLibrary
}
}
private static List<string[]> ScaleVariants(string[] mask)
private static List<string[]> ScaleVariants(string[] mask, int padMin, int padMax)
{
var scaled = new List<string[]>();
scaled.Add(mask);
var padded = Pad(mask, 1);
if (padded != null) scaled.Add(padded);
var trimmed = Pad(mask, -1);
if (trimmed != null) scaled.Add(trimmed);
var from = Math.Min(padMin, padMax);
var to = Math.Max(padMin, padMax);
var addedBase = false;
for (var delta = from; delta <= to; delta++)
{
if (delta == 0)
{
scaled.Add(mask);
addedBase = true;
continue;
}
var padded = Pad(mask, delta);
if (padded != null)
{
scaled.Add(padded);
}
}
if (!addedBase)
{
scaled.Insert(0, mask);
}
return scaled;
}