diff options
author | Holden Rohrer <hr@hrhr.dev> | 2021-08-03 00:40:58 -0400 |
---|---|---|
committer | Holden Rohrer <hr@hrhr.dev> | 2021-08-03 00:40:58 -0400 |
commit | 5f974d83677fc6d7ee229e6a2e2720a45677e4e0 (patch) | |
tree | 6c18ef8169ee4986bee3d7b2dc6f59582d7946da /source/spots.d |
created drocks
Diffstat (limited to 'source/spots.d')
-rw-r--r-- | source/spots.d | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/source/spots.d b/source/spots.d new file mode 100644 index 0000000..0f9d8b7 --- /dev/null +++ b/source/spots.d @@ -0,0 +1,145 @@ +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('*')); + } +} |