/// <summary>Used to create cache for the overlapping model</summary> public static bool testCompatibility(int from, Dir4 dir, int to, PatternStorage patterns, Map source) { int N = patterns.N; // patterns have size of NxN var fromPattern = patterns[from]; var toPattern = patterns[to]; // TODO: use row/col vector for performance for (int row = 0; row < N - 1; row++) { for (int col = 0; col < N; col++) { // Now, consider a concrete situation: `from` is down and `to` is up (direction = North) // get local positions in each pattern var downLocal = new Vec2i(col, row); var upLocal = new Vec2i(col, row + 1); // apply the direction downLocal = dir.applyAsRotation(downLocal, N); upLocal = dir.applyAsRotation(upLocal, N); // convert them (local positions) into global positions (position in the source) var downGlobal = fromPattern.localPosToSourcePos(downLocal, N); var upGlobal = toPattern.localPosToSourcePos(upLocal, N); // test the equaility if (source[downGlobal.x, downGlobal.y] != source[upGlobal.x, upGlobal.y]) { return(false); } } } // if all of the tiles are same, that's a compatible combination return(true); }
/// <summary>Creates an <c>AdjacencyRule</c> for the overlapping model</summary> public static RuleData buildRule(PatternStorage patterns, ref Map source) { var rule = new RuleData(); int nPatterns = patterns.len; rule.nPatterns = nPatterns; { // do not count symmetric combinations int nCombinations = (nPatterns + 1) * (nPatterns) / 2; rule.cache = new Grid2D <bool>(4, nCombinations); } for (int from = 0; from < nPatterns; from++) { for (int to = from; to < nPatterns; to++) { for (int d = 0; d < 4; d++) { var dir = (Dir4)d; bool canOverlap = OverlappingModel.testCompatibility(from, dir, to, patterns, source); rule.cache.add(canOverlap); } } } return(rule); }
public static void testEveryColumn(State state, ref RuleData rule, PatternStorage patterns) { System.Console.WriteLine($"=== Test every column ==="); var gridSize = state.gridSize; int h = gridSize.y; int w = gridSize.x; int n = patterns.len; for (int x = 0; x < w; x++) { for (int y = 0; y < h - 1; y++) { var fromId = state.patternIdAt(x, y, n); var toId = state.patternIdAt(x, y + 1, n); if (fromId == null || toId == null) { continue; } if (!rule.isLegal(fromId.Value, Dir4.S, toId.Value)) { System.Console.WriteLine($"illegal: {x}, {y} ({fromId.Value.asIndex}) -> {x}, {y+1} ({toId.Value.asIndex})"); } } } }
public Model(Vec2i gridSize, PatternStorage patterns, RuleData rule) { // this.input = input; this.gridSize = gridSize; this.patterns = patterns; this.rule = rule; }
public static PatternStorage extractEveryPattern(ref Map source, int N, PatternVariation[] variations) { var patterns = new PatternStorage(source, N); var nVariations = variations.Length; // TODO: handling periodic input for (int y = 0; y < source.height - N + 1; y++) { for (int x = 0; x < source.width - N + 1; x++) { for (int i = 0; i < nVariations; i++) { patterns.store(x, y, variations[i]); } } } return(patterns); }
public static EntropyCacheForCell initial(PatternStorage patterns) { int nPatterns = patterns.len; int totalWeight = 0; double entropyCache = 0; for (int i = 0; i < nPatterns; i++) { var weight = patterns[i].weight; totalWeight += weight; entropyCache += weight * Math.Log2(weight); } return(new EntropyCacheForCell { isDecided = false, totalWeight = totalWeight, cachedExpr = entropyCache, }); }
public static void printInitialEnableCounter(int width, int height, PatternStorage patterns, ref RuleData rule) { System.Console.WriteLine($"=== Initial enabler count ==="); var counts = EnablerCounter.initial(width, height, patterns, ref rule); int nPatterns = patterns.len; for (int id_ = 0; id_ < nPatterns; id_++) { System.Console.Write($"{id_}: "); var id = new PatternId(id_); for (int d = 0; d < 4; d++) { var dir = (Dir4)d; int count = counts[0, 0, id, dir]; System.Console.Write($"{dir}: {count}, "); } System.Console.WriteLine(""); } }
/// <summary>Used to create cache for the overlapping model</summary> public static bool testCompatibility(int from, Dir4 dir, int to, PatternStorage patterns, Map source) { int N = patterns.N; // patterns have size of NxN var fromPattern = patterns[from]; var toPattern = patterns[to]; // TODO: use row/col vector for performance int row = 0; bool anyExitDown = false; bool anyExitUp = false; for (int col = 0; col < N; col++) { // Now, consider a concrete situation: `from` is down and `to` is up (direction = North) // get local positions in each pattern var downLocal = new Vec2i(col, row); var upLocal = new Vec2i(col, row + 1); // apply the direction downLocal = dir.applyAsRotation(downLocal, N); upLocal = dir.applyAsRotation(upLocal, N); // convert them (local positions) into global positions (position in the source) var downGlobal = fromPattern.localPosToSourcePos(downLocal, N); var upGlobal = toPattern.localPosToSourcePos(upLocal, N); // check compatibilities bool down = source[downGlobal.x, downGlobal.y] == Tile.Floor; bool up = source[downGlobal.x, downGlobal.y] == Tile.Floor; if (down && up) { return(true); } anyExitDown &= down; anyExitUp &= up; } // if one of them has no exits, we enable the pattern return(!anyExitDown && !anyExitUp); }
public static PatternStorage extractEveryChunk(ref Map source, int N, PatternVariation[] variations) { if (source.width % N != 0 || source.height % N != 0) { throw new System.Exception($"source size ({source.width}, {source.height}) must be dividable with N={N}"); } var patterns = new PatternStorage(source, N); var nVariations = variations.Length; var gridSize = new Vec2i(source.width, source.height) / N; for (int y = 0; y < gridSize.y; y++) { for (int x = 0; x < gridSize.x; x++) { for (int i = 0; i < nVariations; i++) { patterns.store(x * N, y * N, variations[i]); } } } return(patterns); }