134 lines
3.3 KiB
Dart
134 lines
3.3 KiB
Dart
|
import 'dart:ui' as ui;
|
||
|
|
||
|
import 'package:dartterm/wfc/model.dart';
|
||
|
|
||
|
class Bitmap<T> {
|
||
|
final int sx;
|
||
|
final int sy;
|
||
|
final List<T> data;
|
||
|
|
||
|
const Bitmap(this.sx, this.sy, this.data);
|
||
|
}
|
||
|
|
||
|
class OverlappingModel<T> extends Model {
|
||
|
List<List<int>> _patterns = [];
|
||
|
List<T> _colors = [];
|
||
|
Map<T, int> _colorOf = {};
|
||
|
|
||
|
OverlappingModel(
|
||
|
Bitmap<T> bitmap,
|
||
|
int n,
|
||
|
int width,
|
||
|
int height,
|
||
|
bool periodicInput,
|
||
|
bool periodic,
|
||
|
int symmetry,
|
||
|
bool ground,
|
||
|
Heuristic heuristic)
|
||
|
: super(width, height, n, periodic, heuristic) {
|
||
|
List<int> sample = [];
|
||
|
for (var i = 0; i < bitmap.data.length; i++) {
|
||
|
var existing = bitmap.data[i];
|
||
|
var color = _colorOf[existing];
|
||
|
if (color == null) {
|
||
|
color = _colors.length;
|
||
|
_colorOf[existing] = color;
|
||
|
_colors.add(existing);
|
||
|
}
|
||
|
sample[i] = color;
|
||
|
}
|
||
|
|
||
|
var c = _colors.length;
|
||
|
|
||
|
List<int> pattern(int Function(int, int) f) {
|
||
|
return [
|
||
|
for (var y = 0; y < n; y++)
|
||
|
for (var x = 0; x < n; x++) f(x, y)
|
||
|
];
|
||
|
}
|
||
|
|
||
|
List<int> rotate(List<int> p) {
|
||
|
return pattern((x, y) => p[n - 1 - y + x * n]);
|
||
|
}
|
||
|
|
||
|
List<int> reflect(List<int> p) {
|
||
|
return pattern((x, y) => p[n - 1 - x + y * n]);
|
||
|
}
|
||
|
|
||
|
int hash(List<int> p) {
|
||
|
var result = 0, power = 1;
|
||
|
for (var i = 0; i < p.length; i++) {
|
||
|
result += p[p.length - 1 - i] * power;
|
||
|
power *= c;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
var sx = bitmap.sx;
|
||
|
var sy = bitmap.sy;
|
||
|
Map<int, int> patternIndices = {};
|
||
|
List<double> weightList = [];
|
||
|
var xmax = periodicInput ? sx : sx - n + 1;
|
||
|
var ymax = periodicInput ? sy : sy - n + 1;
|
||
|
for (var y = 0; y < ymax; y++) {
|
||
|
for (var x = 0; x < xmax; x++) {
|
||
|
var ps = [
|
||
|
pattern((dx, dy) => sample[(x + dx) % sx + (y + dy) % sy * sx])
|
||
|
];
|
||
|
ps.add(reflect(ps[0]));
|
||
|
ps.add(rotate(ps[0]));
|
||
|
ps.add(reflect(ps[2]));
|
||
|
ps.add(rotate(ps[2]));
|
||
|
ps.add(reflect(ps[4]));
|
||
|
ps.add(rotate(ps[4]));
|
||
|
ps.add(reflect(ps[6]));
|
||
|
|
||
|
for (var k = 0; k < symmetry; k++) {
|
||
|
var p = ps[k];
|
||
|
var h = hash(p);
|
||
|
var ix = patternIndices[h];
|
||
|
if (ix != null) {
|
||
|
weightList[ix] = weightList[ix] + 1;
|
||
|
} else {
|
||
|
patternIndices[h] = weightList.length;
|
||
|
weightList.add(1.0);
|
||
|
_patterns.add(p);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
weights = weightList;
|
||
|
cT = weights.length;
|
||
|
this.ground = ground;
|
||
|
|
||
|
bool agrees(List<int> p1, List<int> p2, int dx, int dy) {
|
||
|
int xmin = dx < 0 ? 0 : dx;
|
||
|
int xmax = dx < 0 ? dx + n : n;
|
||
|
int ymin = dy < 0 ? 0 : dy;
|
||
|
int ymax = dy < 0 ? dy + n : n;
|
||
|
for (var y = ymin; y < ymax; y++) {
|
||
|
for (var x = xmin; x < xmax; x++) {
|
||
|
if (p1[x + n * y] != p2[x - dx + n * (y - dy)]) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
propagator = [
|
||
|
for (var d = 0; d < 4; d++)
|
||
|
[
|
||
|
for (var t = 0; t < cT; t++)
|
||
|
[
|
||
|
for (var t2 = 0; t2 < cT; t2++)
|
||
|
if (agrees(
|
||
|
_patterns[t], _patterns[t2], Model.dx[d], Model.dy[d]))
|
||
|
t2
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
}
|
||
|
}
|