신규등록

This commit is contained in:
JiWoong Sul
2025-11-22 01:08:44 +09:00
commit e81218576d
32 changed files with 3046 additions and 0 deletions

414
mask_library.cs Normal file
View File

@@ -0,0 +1,414 @@
using System.Collections.Generic;
using System.Linq;
internal static class MaskLibrary
{
public static readonly List<string[]> Microban = new()
{
new[]{
"0000000",
"0####00",
"0#..#00",
"0#..###",
"0#....#",
"0######",
"0000000"
},
new[]{
"0000000",
"0#####0",
"0#...#0",
"0#.#.#0",
"0#...#0",
"0#####0",
"0000000"
},
new[]{
"0000000",
"0###000",
"0#.#000",
"0#.#000",
"0#..###",
"0#####0",
"0000000"
},
new[]{
"00000000",
"0######0",
"0#....#0",
"0###..#0",
"000#..#0",
"000####0",
"00000000"
},
new[]{
"000000000",
"00#####00",
"00#...#00",
"0##...##0",
"0#.....#0",
"0##...##0",
"00#...#00",
"00#####00",
"000000000"
},
new[]{
"00000000",
"0######0",
"0#....#0",
"0#.####0",
"0#....#0",
"0###..#0",
"000####0",
"00000000"
},
new[]{
"00000000",
"0####000",
"0#..###0",
"0#....#0",
"0###..#0",
"000####0",
"00000000"
},
new[]{
"0000000",
"0#####0",
"0#...#0",
"0#...#0",
"0#...#0",
"0###.#0",
"000###0",
"0000000"
},
new[]{
"0000000",
"0####00",
"0#..#00",
"0#..###",
"0#..#.#",
"0####.#",
"000000#"
},
new[]{
"00000000",
"0######0",
"0#....#0",
"0#.#..#0",
"0#.#.##0",
"0#...#00",
"0#####00",
"00000000"
},
new[]{
"0000000",
"0#####0",
"0#...#0",
"###.###",
"0#...#0",
"0#...#0",
"0#####0"
},
new[]{
"0000000000",
"00#######0",
"00#.....#0",
"###.###.#0",
"0#.....#0",
"0#######0",
"000000000"
},
// 13: 얇은 리본형
new[]{
"000000000",
"00####000",
"00#..###0",
"0##..#.#0",
"0#....#00",
"0##..###0",
"00####000",
"000000000"
},
// 14: 작은 도넛
new[]{
"0000000",
"0#####0",
"0#...#0",
"0#.#.#0",
"0#...#0",
"0#####0",
"0000000"
},
// 15: ㄴ자 계단형
new[]{
"00000000",
"0####000",
"0#..###0",
"0#....#0",
"0###..#0",
"000#..#0",
"000####0",
"00000000"
},
// 16: 짧은 S자 복도
new[]{
"00000000",
"0####000",
"0#..###0",
"0#..#.#0",
"0###..#0",
"000####0",
"00000000"
},
// 17: 코너 방 + 넓은 홀
new[]{
"000000000",
"00#####00",
"00#...#00",
"0##.#.##0",
"0#.....#0",
"0#.#.###0",
"0#...#000",
"0#####000",
"000000000"
},
// 18: 긴 복도 + 옆 포켓
new[]{
"0000000000",
"00#######0",
"00#.....#0",
"0##.###.#0",
"0#.....#00",
"0#.#.###00",
"0#.....#00",
"0#######00",
"0000000000"
},
// 19: 두꺼운 U자 (안쪽 공간 넓음)
new[]{
"000000000",
"0#######0",
"0#.....#0",
"0#.....#0",
"0#.....#0",
"0#..#..#0",
"0######0",
"000000000"
},
// 20: 작은 십자 변형 (팔 길이 짧음)
new[]{
"000000000",
"00###0000",
"00#.#0000",
"0###.###0",
"0#.....#0",
"0###.###0",
"000#.#000",
"000###000",
"000000000"
}
};
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)
{
var seen = new HashSet<string>();
var output = new List<string[]>();
foreach (var mask in baseMasks)
{
var seeds = includeScaled ? ScaleVariants(mask) : new List<string[]> { mask };
foreach (var seed in seeds)
{
foreach (var variant in Variants(seed))
{
var key = CanonicalKey(variant);
if (seen.Add(key))
{
output.Add(variant);
}
}
}
}
return output;
}
public static string[] CreateVariant(string[] mask, Random rng, bool applyTransforms, int wallJitter)
{
var candidates = applyTransforms ? Variants(mask).ToList() : new List<string[]> { mask };
var picked = candidates[rng.Next(candidates.Count)];
if (wallJitter <= 0)
{
return picked;
}
var jittered = ApplyWallJitter(picked, rng, wallJitter);
return jittered;
}
private static IEnumerable<string[]> Variants(string[] mask)
{
var current = mask;
for (var i = 0; i < 4; i++)
{
yield return current;
yield return FlipHorizontal(current);
current = Rotate90(current);
}
}
private static string[] Rotate90(string[] mask)
{
var h = mask.Length;
var w = mask.Max(r => r.Length);
var arr = new char[h, w];
for (var y = 0; y < h; y++)
{
var row = mask[y];
for (var x = 0; x < w; x++)
{
arr[y, x] = x < row.Length ? row[x] : '0';
}
}
var rotated = new string[w];
for (var y = 0; y < w; y++)
{
var chars = new char[h];
for (var x = 0; x < h; x++)
{
chars[x] = arr[h - 1 - x, y];
}
rotated[y] = new string(chars);
}
return rotated;
}
private static string[] FlipHorizontal(string[] mask)
{
return mask.Select(row => new string(row.Reverse().ToArray())).ToArray();
}
private static string CanonicalKey(string[] mask) => string.Join("\n", mask);
private static string[] ApplyWallJitter(string[] mask, Random rng, int maxJitter)
{
var h = mask.Length;
var w = mask.Max(r => r.Length);
var grid = mask.Select(line => line.PadRight(w, '0').ToCharArray()).ToArray();
int changes = rng.Next(1, maxJitter + 1);
var candidates = new List<(int x, int y)>();
for (var y = 0; y < h; y++)
{
for (var x = 0; x < w; x++)
{
var c = grid[y][x];
if (c == '0') continue;
// avoid outermost void border flipping into wall
if (y == 0 || x == 0 || y == h - 1 || x == w - 1) continue;
candidates.Add((x, y));
}
}
Shuffle(candidates, rng);
var applied = 0;
foreach (var (x, y) in candidates)
{
if (applied >= changes) break;
var c = grid[y][x];
if (c == '#') grid[y][x] = '.';
else if (c == '.') grid[y][x] = '#';
else continue;
applied++;
}
var result = new string[h];
for (var y = 0; y < h; y++)
{
result[y] = new string(grid[y]);
}
return result;
}
private static void Shuffle<T>(IList<T> list, Random rng)
{
for (var i = list.Count - 1; i > 0; i--)
{
var j = rng.Next(i + 1);
(list[i], list[j]) = (list[j], list[i]);
}
}
private static List<string[]> ScaleVariants(string[] mask)
{
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);
return scaled;
}
private static string[]? Pad(string[] mask, int delta)
{
if (delta == 0) return mask;
var h = mask.Length;
var w = mask.Max(r => r.Length);
if (delta < 0)
{
if (h + delta * 2 < 3 || w + delta * 2 < 3) return null;
var newH = h + delta * 2;
var newW = w + delta * 2;
var output = new string[newH];
for (var y = 0; y < newH; y++)
{
var srcY = y - delta;
if (srcY < 0 || srcY >= h)
{
output[y] = new string('0', newW);
continue;
}
var row = mask[srcY];
var src = row.Skip(delta).Take(newW).ToArray();
if (src.Length < newW)
{
output[y] = new string(src).PadRight(newW, '0');
}
else
{
output[y] = new string(src);
}
}
return output;
}
else
{
var newH = h + delta * 2;
var newW = w + delta * 2;
var output = new string[newH];
for (var y = 0; y < newH; y++)
{
if (y < delta || y >= h + delta)
{
output[y] = new string('0', newW);
continue;
}
var row = mask[y - delta];
var paddedRow = new string('0', delta) + row.PadRight(w, '0') + new string('0', delta);
if (paddedRow.Length < newW)
{
paddedRow = paddedRow.PadRight(newW, '0');
}
output[y] = paddedRow;
}
return output;
}
}
}