import std.bigint; import std.digest.crc; import std.random : unpredictableSeed; import std.range; import lru : LRUCache; import deimos.ncurses; private BigInt positive(BigInt n) { if (n >= 0) return n * 2; else return -n * 2 - 1; } private BigInt pair(BigInt n, BigInt m) { // https://stackoverflow.com/a/919661 return (positive(n) + positive(m)) * (positive(n) + positive(m) + 1) / 2 + positive(m); } struct Spot { private char _contents; this(char c) { _contents = c; } @property contents() { return _contents; } bool opEqual(const Spot s) { return s._contents == _contents; } bool isRock() { return _contents == '*'; } } interface SpotSource { Spot opIndex(BigInt y, BigInt x); } class RandomSource : SpotSource { uint seed; double density = .0025; private LRUCache!(BigInt[2], Spot) cache; this() { seed = unpredictableSeed; cache = new LRUCache!(BigInt[2], Spot)(50000); } this(uint seed) { this.seed = seed; } this(uint seed, double density) { this.density = density; this(seed); } private uint hash(BigInt n) { CRC32 crc; crc.start(); crc.put((cast(ubyte*)&seed)[0 .. seed.sizeof]); foreach (i; iota(n.ulongLength)) { auto digit = n.getDigit(i); crc.put((cast(ubyte*)&digit)[0 .. digit.sizeof]); } auto result = crc.finish(); auto hash = *(cast(uint*)&result); return hash; } public Spot opIndex(BigInt y, BigInt x) { if ([y, x] in cache) return cache[[y, x]]; auto roll = cast(double) hash(pair(y, x)) / uint.max; Spot ret; if (roll < density) ret = Spot('*'); else ret = Spot(' '); cache[[y, x]] = ret; return ret; } } class OverlaySource : SpotSource { private SpotSource _base; private Spot[BigInt[2]] _overlay; this(SpotSource base) { _base = base; } void opIndexAssign(Spot spot, BigInt y, BigInt x) { Spot* p = [y, x] in _overlay; if (p !is null && spot == _base[y, x]) { _overlay.remove([y, x]); } else { _overlay[[y, x]] = spot; } } Spot opIndex(BigInt y, BigInt x) { Spot* p = [y, x] in _overlay; if (p !is null) return *p; else return _base[y, x]; } unittest { auto base = new RandomSource(0, 0.0); auto src = new OverlaySource(base); src[BigInt(0), BigInt(0)] = Spot('*'); src[BigInt(0), BigInt(1)] = Spot('*'); assert(src[BigInt(0), BigInt(0)] == Spot('*')); assert(src[BigInt(0), BigInt(1)] == Spot('*')); } }