#!/usr/bin/env nodejs const fs = require("fs"); let CellType = { EMPTY: 0, WALL: 1, FOOD: 2, NEST: 3, }; class C { state; constructor(e) { ((this.state = 0 | e), 0 === this.state && (this.state = 1)); } next() { let e = 0 | (this.state += 0x9e3779b9); return ( (((e = Math.imul( (e = Math.imul(e ^ (e >>> 16), 0x85ebca6b)) ^ (e >>> 13), 0xc2b2ae35, )) ^ (e >>> 16)) >>> 0) / 0x100000000 ); } nextInt(e) { return (this.next() * e) | 0; } nextIntRange(e, t) { return e + this.nextInt(t - e); } shuffle(e) { for (let t = e.length - 1; t > 0; t--) { let r = this.nextInt(t + 1); [e[t], e[r]] = [e[r], e[t]]; } return e; } } function P(e, t, r, l) { let a = e * t; return { width: e, height: t, cells: new Uint8Array(a), food: new Uint16Array(a), pheromones: new Uint16Array(a * 4), visitCounts: new Uint32Array(a), nestX: Math.floor(e / 2), nestY: Math.floor(t / 2), totalFood: 0, seed: r, name: l, }; } function H(e) { for (let t = 0; t < e.width; t++) (_(e, t, 0, CellType.WALL), _(e, t, e.height - 1, CellType.WALL)); for (let t = 0; t < e.height; t++) (_(e, 0, t, CellType.WALL), _(e, e.width - 1, t, CellType.WALL)); } let V = { open: function (e, t, r) { let n = P(e, t, r, `open-${r}`), l = new C(r), a = e / 128; (H(n), J(n, l), $(n)); let s = 5 + l.nextInt(4); for (let r = 0; r < s; r++) { let r = 4 + l.nextInt(e - 8), s = 4 + l.nextInt(t - 8); if (W(r, s, n.nestX, n.nestY) < 15 * a) continue; let o = 3 + l.nextInt(3), i = 2 + l.nextInt(3); for (let e = -o; e <= o; e++) for (let t = -o; t <= o; t++) { if (t * t + e * e > o * o) continue; let l = r + t, a = s + e; G(n, l, a) && F(n, l, a, i); } } return n; }, maze: function (e, t, r) { let l = P(e, t, r, `maze-${r}`), a = new C(r), s = e / 128; H(l); for (let r = 1; r < t - 1; r++) for (let t = 1; t < e - 1; t++) _(l, t, r, CellType.WALL); let o = Math.floor((e - 2) / 4), i = Math.floor((t - 2) / 4), c = new Uint8Array(o * i), d = []; function u(e, t) { return [1 + 4 * e + 1, 1 + 4 * t + 1]; } function h(r, a) { let [s, i] = u(r, a); for (let r = 0; r < 2; r++) for (let a = 0; a < 2; a++) s + a < e - 1 && i + r < t - 1 && _(l, s + a, i + r, CellType.EMPTY); c[a * o + r] = 1; } function p(r, a, s, o) { let [i, c] = u(r, a), [d, h] = u(s, o), p = Math.min(i, d), f = Math.min(c, h), m = Math.max(i, d) + 1, x = Math.max(c, h) + 1; for (let r = f; r <= x; r++) for (let a = p; a <= m; a++) a > 0 && a < e - 1 && r > 0 && r < t - 1 && _(l, a, r, CellType.EMPTY); } let f = Math.floor(o / 2), m = Math.floor(i / 2); (h(f, m), d.push(f, m)); let x = [ [0, -1], [1, 0], [0, 1], [-1, 0], ]; for (; d.length > 0; ) { let e = d[d.length - 1], t = d[d.length - 2], r = []; for (let n = 0; n < 4; n++) { let l = t + x[n][0], a = e + x[n][1]; l >= 0 && l < o && a >= 0 && a < i && !c[a * o + l] && r.push(n); } if (0 === r.length) { d.length -= 2; continue; } let n = r[a.nextInt(r.length)], l = t + x[n][0], s = e + x[n][1]; (p(t, e, l, s), h(l, s), d.push(l, s)); } for (let e = 0; e < i; e++) for (let t = 0; t < o; t++) if (c[e * o + t]) for (let [r, n] of [ [1, 0], [0, 1], ]) { let l = t + r, s = e + n; !(l >= o) && !(s >= i) && c[s * o + l] && 0.25 > a.next() && p(t, e, l, s); } for (let r = 0; r < 100; r++) { let r = 4 + a.nextInt(e - 8), s = 4 + a.nextInt(t - 8); if (l.cells[U(l, r, s)] === CellType.EMPTY) { ((l.nestX = r), (l.nestY = s)); break; } } $(l); let g = 16 + a.nextInt(7); for (let r = 0; r < g; r++) for (let r = 0; r < 50; r++) { let r = 2 + a.nextInt(e - 4), o = 2 + a.nextInt(t - 4); if ( l.cells[U(l, r, o)] === CellType.EMPTY && W(r, o, l.nestX, l.nestY) > 12 * s ) { let e = 1 + a.nextInt(3), t = 3 + a.nextInt(6); for (let a = -e; a <= e; a++) for (let s = -e; s <= e; s++) !(s * s + a * a > e * e) && G(l, r + s, o + a) && l.cells[U(l, r + s, o + a)] === CellType.EMPTY && F(l, r + s, o + a, t); break; } } return (Y(l), l); }, spiral: function (e, t, r) { let l = P(e, t, r, `spiral-${r}`), a = new C(r); (H(l), $(l)); let s = e / 2, o = t / 2, i = Math.min(e, t) / 2 - 2, c = Math.max(5, Math.floor(0.06 * e)); for (let e = c + 2; e < i; e += c) { let t = a.next() * Math.PI * 2, r = 0.6 + 0.4 * a.next(), i = 2 + a.nextInt(3), c = 1 + 1.5 * a.next(), d = a.next() * Math.PI * 2; for (let a = 0; a < 2 * Math.PI; a += 0.02) { let u = Math.abs( ((a - t + 3 * Math.PI) % (2 * Math.PI)) - Math.PI, ); if (u < r) continue; let h = e + c * Math.min(1, (u - r) / 0.5) * Math.sin(a * i + d), p = Math.floor(s + Math.cos(a) * h), f = Math.floor(o + Math.sin(a) * h); G(l, p, f) && _(l, p, f, CellType.WALL); } } for (let e = c; e < i; e += c) { let t = e + c / 2, r = 3 + a.nextInt(3); for (let e = 0; e < r; e++) { let e = a.next() * Math.PI * 2, r = t + (a.next() - 0.5) * (0.3 * c), n = Math.floor(s + Math.cos(e) * r), i = Math.floor(o + Math.sin(e) * r), d = 1 + a.nextInt(2), u = 3 + a.nextInt(3); for (let e = -d; e <= d; e++) for (let t = -d; t <= d; t++) { if (t * t + e * e > d * d) continue; let r = n + t, a = i + e; G(l, r, a) && F(l, r, a, u); } } } return (Y(l), l); }, field: function (e, t, r) { let l = P(e, t, r, `field-${r}`), a = new C(r), s = e / 128; (H(l), J(l, a), $(l), (function (e, t, r, l) { for (let a = 0; a < r; a++) { let r = 4 + t.nextInt(e.width - 8), a = 4 + t.nextInt(e.height - 8); if (8 > W(r, a, e.nestX, e.nestY)) continue; let s = l[0] + t.nextInt(l[1] - l[0]), o = t.next() * Math.PI * 2, i = 0, c = !1; for ( let l = 0; l < s && ((o += (t.next() - 0.5) * 1), G( e, (r += Math.round(Math.cos(o))), (a += Math.round(Math.sin(o))), )); l++ ) !(5 > W(r, a, e.nestX, e.nestY)) && (i++, !c && i > 8 + t.nextInt(12) ? ((c = !0), (i = 0)) : c && i > 2 + t.nextInt(3) && ((c = !1), (i = 0)), c || _(e, r, a, CellType.WALL)); } })(l, a, 3 + a.nextInt(3), [70, 130])); let o = 6 + a.nextInt(3); for (let r = 0; r < o; r++) { let r = 4 + a.nextInt(e - 8), n = 4 + a.nextInt(t - 8); if (W(r, n, l.nestX, l.nestY) < 12 * s) continue; let o = 2 + a.nextInt(4), i = 2 + a.nextInt(4); for (let e = -o; e <= o; e++) for (let t = -o; t <= o; t++) { if (t * t + e * e > o * o) continue; let a = r + t, s = n + e; G(l, a, s) && F(l, a, s, i); } } return (Y(l), l); }, bridge: function (e, t, r) { let l = P(e, t, r, `bridge-${r}`), a = new C(r); H(l); let s = Math.floor(e / 2), o = Math.floor(0.1 * e), i = new Int32Array(t), c = s; for (let r = 1; r < t - 1; r++) { (0.3 > a.next() && (c += a.nextInt(3) - 1), (c = Math.max(s - o, Math.min(s + o, c))), (i[r] = c)); for (let t = -1; t <= 1; t++) { let a = c + t; a > 0 && a < e - 1 && _(l, a, r, CellType.WALL); } } let d = 2 + a.nextInt(3), u = Math.floor(t / (d + 1)); for (let r = 0; r < d; r++) { let s = u * (r + 1), o = 2 + a.nextInt(2); for (let r = -o; r <= o; r++) { let a = s + r; if (a > 0 && a < t - 1) for (let t = -1; t <= 1; t++) { let r = i[a] + t; r > 0 && r < e - 1 && _(l, r, a, CellType.EMPTY); } } } ((l.nestX = Math.floor(e / 4)), (l.nestY = Math.floor(t / 2)), $(l)); let h = 6 + a.nextInt(4); for (let r = 0; r < h; r++) { let r = s + 4 + a.nextInt(Math.floor(e / 2) - 6), o = 4 + a.nextInt(t - 8), i = 2 + a.nextInt(3), c = 3 + a.nextInt(4); for (let e = -i; e <= i; e++) for (let t = -i; t <= i; t++) { if (t * t + e * e > i * i) continue; let a = r + t, s = o + e; G(l, a, s) && l.cells[U(l, a, s)] !== CellType.WALL && F(l, a, s, c); } } return (B(l, a), l); }, gauntlet: function (e, t, r) { let l = P(e, t, r, `gauntlet-${r}`), a = new C(r); (H(l), (l.nestX = 5), (l.nestY = Math.floor(t / 2)), $(l)); let s = 3 + a.nextInt(2), o = Math.floor((e - 20) / (s + 1)); for (let r = 0; r < s; r++) { let s = 12 + o * (r + 1), i = r % 2 == 0 ? 4 + a.nextInt(Math.floor(t / 3)) : Math.floor((2 * t) / 3) + a.nextInt(Math.floor(t / 3) - 4), c = 4 + a.nextInt(4); for (let r = 1; r < t - 1; r++) !(Math.abs(r - i) < c) && s > 0 && s < e - 1 && _(l, s, r, CellType.WALL); } for (let r = 1; r <= s; r++) { let n = 12 + r * o + 4, i = r < s ? 12 + (r + 1) * o - 4 : e - 6; if (i <= n) continue; let c = (r - 1) / Math.max(1, s - 1), d = 2 + a.nextInt(2) + Math.round(2 * c), u = 1 + Math.round(2 * c), h = 2 + a.nextInt(2) + Math.round(3 * c); for (let e = 0; e < d; e++) { let e = n + a.nextInt(Math.max(1, i - n)), r = 4 + a.nextInt(t - 8); for (let t = -u; t <= u; t++) for (let n = -u; n <= u; n++) { if (n * n + t * t > u * u) continue; let a = e + n, s = r + t; G(l, a, s) && F(l, a, s, h); } } } return (B(l, a), l); }, pockets: function (e, t, r) { let l = P(e, t, r, `pockets-${r}`), a = new C(r); (H(l), J(l, a), $(l)); let s = [], o = 7 + a.nextInt(4); for (let r = 0; r < 300 && s.length < o; r++) { let r = 7 + a.nextInt(6), o = r + 4 + a.nextInt(e - 2 * r - 8), i = r + 4 + a.nextInt(t - 2 * r - 8); if (W(o, i, l.nestX, l.nestY) < r + 8) continue; let c = !1; for (let e of s) if (W(o, i, e.cx, e.cy) < r + e.r + 5) { c = !0; break; } if (c) continue; s.push({ cx: o, cy: i, r }); let d = a.next() * Math.PI * 2, u = 0.2 + 0.1 * a.next(); for (let e = 0; e < 2 * Math.PI; e += 0.025) { if ( Math.abs( ((e - d + 3 * Math.PI) % (2 * Math.PI)) - Math.PI, ) < u ) continue; let t = Math.round(o + Math.cos(e) * r), a = Math.round(i + Math.sin(e) * r); G(l, t, a) && _(l, t, a, CellType.WALL); } let h = 3 + a.nextInt(2), p = 2 + a.nextInt(3); for (let e = -h; e <= h; e++) for (let t = -h; t <= h; t++) { if (t * t + e * e > h * h) continue; let r = o + t, a = i + e; G(l, r, a) && l.cells[U(l, r, a)] === CellType.EMPTY && F(l, r, a, p); } } return (Y(l), l); }, fortress: function (e, t, r) { let l = P(e, t, r, `fortress-${r}`), a = new C(r); H(l); let s = Math.floor(e / 2), o = Math.floor(t / 2), i = 3 + a.nextInt(2), c = Math.max(4, Math.floor(Math.min(e, t) / (2 * i + 4))); ((l.nestX = 4), (l.nestY = 4), $(l)); for (let e = 1; e <= i; e++) { let t = e * c, r = a.next() * Math.PI * 2, i = 0.35 + 0.2 * a.next(), d = 3 + a.nextInt(3), u = 1.5 + 2 * a.next(), h = a.next() * Math.PI * 2; for (let e = 0; e < 2 * Math.PI; e += 0.015) { if ( Math.abs( ((e - r + 3 * Math.PI) % (2 * Math.PI)) - Math.PI, ) < i ) continue; let a = t + Math.sin(e * d + h) * u, c = Math.floor(s + Math.cos(e) * a), p = Math.floor(o + Math.sin(e) * a); G(l, c, p) && _(l, c, p, CellType.WALL); } } let d = c - 2; for (let e = -d; e <= d; e++) for (let t = -d; t <= d; t++) { if (t * t + e * e > d * d) continue; let r = s + t, n = o + e; G(l, r, n) && F(l, r, n, 3 + a.nextInt(3)); } for (let r = 1; r < i; r++) { let i = r * c + Math.floor(c / 2), d = 4 + a.nextInt(4); for (let r = 0; r < d; r++) { let r = a.next() * Math.PI * 2, c = Math.floor(s + Math.cos(r) * i), d = Math.floor(o + Math.sin(r) * i); c > 1 && c < e - 2 && d > 1 && d < t - 2 && l.cells[U(l, c, d)] === CellType.EMPTY && F(l, c, d, 2 + a.nextInt(4)); } } return (Y(l), l); }, islands: function (e, t, r) { let l = P(e, t, r, `islands-${r}`), a = new C(r); for (let r = 0; r < t; r++) for (let t = 0; t < e; t++) _(l, t, r, CellType.WALL); let s = Math.floor((e - 2) / 4), o = Math.floor((t - 2) / 4), i = []; for (let e = 0; e < 4; e++) for (let t = 0; t < 4; t++) { let r = 1 + t * s + 2, a = 1 + e * o + 2, c = 1 + (t + 1) * s - 2, d = 1 + (e + 1) * o - 2, u = Math.floor((r + c) / 2), h = Math.floor((a + d) / 2); i.push({ cx: u, cy: h, ri: e, ci: t }); for (let e = a; e <= d; e++) for (let t = r; t <= c; t++) G(l, t, e) && _(l, t, e, CellType.EMPTY); } let c = i.map(() => []), d = 2 + a.nextInt(2); for (let e = 0; e < 4; e++) for (let t = 0; t < 4; t++) { let r = 4 * e + t; if (t < 3) { let i = 1 + (t + 1) * s, u = 1 + e * o + 2 + a.nextInt(Math.max(1, o - 4 - d)), h = u + Math.floor(d / 2); (c[r].push({ x: i, y: h }), c[r + 1].push({ x: i, y: h })); for (let e = 0; e < d; e++) for (let t = -2; t <= 2; t++) G(l, i + t, u + e) && _(l, i + t, u + e, CellType.EMPTY); } if (e < 3) { let i = 1 + (e + 1) * o, u = 1 + t * s + 2 + a.nextInt(Math.max(1, s - 4 - d)), h = u + Math.floor(d / 2); (c[r].push({ x: h, y: i }), c[r + 4].push({ x: h, y: i })); for (let e = 0; e < d; e++) for (let t = -2; t <= 2; t++) G(l, u + e, i + t) && _(l, u + e, i + t, CellType.EMPTY); } } let u = i[a.nextInt(i.length)]; ((l.nestX = u.cx), (l.nestY = u.cy), $(l)); let h = s - 4, p = o - 4, f = ["empty", "blob", "walls", "diffuse", "corners"], m = [], x = d + 5; for (let e = 0; e < i.length; e++) { let t = i[e]; if (t === u) continue; 0 === m.length && (m.push(...f), a.shuffle(m)); let r = m.pop(), n = t.cx - Math.floor(h / 2), s = t.cy - Math.floor(p / 2), o = c[e]; if ("empty" !== r) { if ("blob" === r) { let e = Math.max(1, Math.floor(Math.min(h, p) / 8)), r = t.cx + a.nextInt(5) - 2, n = t.cy + a.nextInt(5) - 2, s = 1 + a.nextInt(2); for (let t = -e; t <= e; t++) for (let a = -e; a <= e; a++) !(a * a + t * t > e * e) && G(l, r + a, n + t) && F(l, r + a, n + t, s); } else if ("walls" === r) { let e = n + h - 1, t = s + p - 1, r = (e, t) => o.some( (r) => Math.abs(e - r.x) + Math.abs(t - r.y) < x, ); for (let o = n; o <= e; o++) (0.5 > a.next() && G(l, o, s) && !r(o, s) && F(l, o, s, 1), 0.5 > a.next() && G(l, o, t) && !r(o, t) && F(l, o, t, 1)); for (let o = s + 1; o < t; o++) (0.5 > a.next() && G(l, n, o) && !r(n, o) && F(l, n, o, 1), 0.5 > a.next() && G(l, e, o) && !r(e, o) && F(l, e, o, 1)); } else if ("diffuse" === r) for (let e = s; e < s + p; e++) for (let t = n; t < n + h; t++) 0.12 > a.next() && G(l, t, e) && F(l, t, e, 1); else if ("corners" === r) { let e = Math.max(1, Math.floor(Math.min(h, p) / 7)); for (let [t, r] of [ [n + e + 1, s + e + 1], [n + h - e - 2, s + e + 1], [n + e + 1, s + p - e - 2], [n + h - e - 2, s + p - e - 2], ]) { if (0.3 > a.next()) continue; let n = 1 + a.nextInt(3); for (let a = -e; a <= e; a++) for (let s = -e; s <= e; s++) !(s * s + a * a > e * e) && G(l, t + s, r + a) && F(l, t + s, r + a, n); } } } } return l; }, chambers: function (e, t, r) { let l = P(e, t, r, `chambers-${r}`), a = new C(r); for (let r = 0; r < t; r++) for (let t = 0; t < e; t++) _(l, t, r, CellType.WALL); let s = [], o = 11 + a.nextInt(3); for (let r = 0; r < o; r++) { let r = 4 + a.nextInt(4), o = 4 + a.nextInt(4), i = r + 2 + a.nextInt(Math.max(1, e - 2 * r - 4)), c = o + 2 + a.nextInt(Math.max(1, t - 2 * o - 4)), d = !1; for (let e of s) if ( Math.abs(i - e.cx) < r + e.hw + 2 && Math.abs(c - e.cy) < o + e.hh + 2 ) { d = !0; break; } if (!d) { s.push({ cx: i, cy: c, hw: r, hh: o }); for (let e = c - o; e <= c + o; e++) for (let t = i - r; t <= i + r; t++) G(l, t, e) && _(l, t, e, CellType.EMPTY); } } for (let e = 1; e < s.length; e++) { let t = s[e - 1], r = s[e], a = t.cx, o = t.cy; for (; a !== r.cx; ) { for (let e = -1; e <= 1; e++) G(l, a, o + e) && _(l, a, o + e, CellType.EMPTY); a += a < r.cx ? 1 : -1; } for (; o !== r.cy; ) { for (let e = -1; e <= 1; e++) G(l, a + e, o) && _(l, a + e, o, CellType.EMPTY); o += o < r.cy ? 1 : -1; } } { let e = s[s.length - 1], t = s[0], r = e.cx, a = e.cy; for (; r !== t.cx; ) { for (let e = -1; e <= 1; e++) G(l, r, a + e) && _(l, r, a + e, CellType.EMPTY); r += r < t.cx ? 1 : -1; } for (; a !== t.cy; ) { for (let e = -1; e <= 1; e++) G(l, r + e, a) && _(l, r + e, a, CellType.EMPTY); a += a < t.cy ? 1 : -1; } } let i = s.reduce( (r, n) => { let l = W(n.cx, n.cy, e / 2, t / 2); return l < r.d ? { c: n, d: l } : r; }, { c: s[0], d: 1 / 0 }, ); for (let e of ((l.nestX = i.c.cx), (l.nestY = i.c.cy), $(l), s)) { if (e === i.c) continue; let t = Math.min(Math.min(e.hw, e.hh) - 1, 3); if (t < 1) continue; let r = 3 + a.nextInt(3); for (let n = -t; n <= t; n++) for (let a = -t; a <= t; a++) { if (a * a + n * n > t * t) continue; let s = e.cx + a, o = e.cy + n; G(l, s, o) && F(l, s, o, r); } } return l; }, prairie: function (e, t, r) { let n = P(e, t, r, `prairie-${r}`), l = new C(r); (H(n), J(n, l), $(n)); let a = 6 + l.nextInt(4), s = []; for (let r = 0; r < a; r++) s.push({ x: 4 + l.nextInt(e - 8), y: 4 + l.nextInt(t - 8), strength: 0.25 + 0.3 * l.next(), radius: 6 + l.nextInt(10), }); for (let r = 2; r < t - 2; r++) for (let t = 2; t < e - 2; t++) { if (5 > W(t, r, n.nestX, n.nestY)) continue; let e = 0.016; for (let n of s) { let l = W(t, r, n.x, n.y); l < n.radius && (e += n.strength * (1 - l / n.radius)); } ((e = Math.min(e, 0.25)), l.next() < e && F( n, t, r, e > 0.12 ? 1 + l.nextInt(3) : 1 + l.nextInt(2), )); } return n; }, brush: function (e, t, r) { let l = P(e, t, r, `brush-${r}`), a = new C(r), s = e / 128; (H(l), J(l, a), $(l)); for (let r = 2; r < t - 2; r++) for (let t = 2; t < e - 2; t++) !(5 > W(t, r, l.nestX, l.nestY)) && 0.28 > a.next() && _(l, t, r, CellType.WALL); for (let e = -3; e <= 3; e++) for (let t = -3; t <= 3; t++) { let r = l.nestX + t, a = l.nestY + e; G(l, r, a) && l.cells[U(l, r, a)] === CellType.WALL && _(l, r, a, CellType.EMPTY); } let o = 10 + a.nextInt(3); for (let r = 0; r < o; r++) for (let r = 0; r < 80; r++) { let r = 4 + a.nextInt(e - 8), o = 4 + a.nextInt(t - 8); if ( W(r, o, l.nestX, l.nestY) < 10 * s || l.cells[U(l, r, o)] !== CellType.EMPTY ) continue; let i = 2 + a.nextInt(3), c = 3 + a.nextInt(3); for (let e = -i; e <= i; e++) for (let t = -i; t <= i; t++) { if (t * t + e * e > i * i) continue; let n = r + t, a = o + e; G(l, n, a) && F(l, n, a, c); } break; } return (Y(l), l); }, }; function Y(e) { let t = new Uint8Array(e.width * e.height), r = [e.nestX, e.nestY]; t[e.nestY * e.width + e.nestX] = 1; let l = 0; for (; l < r.length; ) { let a = r[l++], s = r[l++]; for (let [l, o] of [ [0, -1], [1, 0], [0, 1], [-1, 0], ]) { let i = a + l, c = s + o; if (i < 0 || i >= e.width || c < 0 || c >= e.height) continue; let d = c * e.width + i; t[d] || e.cells[d] === CellType.WALL || ((t[d] = 1), r.push(i, c)); } } for (let r = 0; r < e.width * e.height; r++) if (e.cells[r] === CellType.FOOD && !t[r]) { let l = Math.floor(r / e.width), a = r % e.width, s = new Uint8Array(e.width * e.height), o = new Int32Array(e.width * e.height).fill(-1), i = [a, l]; s[r] = 1; let c = -1, d = 0; for (; d < i.length && c < 0; ) { let r = i[d++], n = i[d++]; for (let [l, a] of [ [0, -1], [1, 0], [0, 1], [-1, 0], ]) { let d = r + l, u = n + a; if (d < 1 || d >= e.width - 1 || u < 1 || u >= e.height - 1) continue; let h = u * e.width + d; if (!s[h]) { if (((s[h] = 1), (o[h] = n * e.width + r), t[h])) { c = h; break; } i.push(d, u); } } } if (c >= 0) { let r = c; for (; r >= 0; ) (e.cells[r] === CellType.WALL && (e.cells[r] = CellType.EMPTY), (t[r] = 1), (r = o[r])); } } } function W(e, t, r, n) { return Math.sqrt((e - r) ** 2 + (t - n) ** 2); } function G(e, t, r) { return t > 0 && t < e.width - 1 && r > 0 && r < e.height - 1; } function J(e, t, r) { let n = r ?? Math.floor(0.15 * Math.min(e.width, e.height)); ((e.nestX = n + t.nextInt(e.width - 2 * n)), (e.nestY = n + t.nextInt(e.height - 2 * n))); } function $(e) { let t = e.nestX, r = e.nestY; for (let l = -1; l <= 1; l++) for (let a = -1; a <= 1; a++) { let s = t + a, o = r + l; s >= 0 && s < e.width && o >= 0 && o < e.height && _(e, s, o, CellType.NEST); } } function U(e, t, r) { return r * e.width + t; } function _(e, t, r, n) { e.cells[U(e, t, r)] = n; } function X(e, t, r) { return e.cells[U(e, t, r)]; } function G(e, t, r) { return t > 0 && t < e.width - 1 && r > 0 && r < e.height - 1; } function F(e, t, r, l) { let a = U(e, t, r); e.cells[a] === CellType.EMPTY && ((e.cells[a] = CellType.FOOD), (e.food[a] = l), (e.totalFood += l)); } function B(e, t) { if (e.width !== e.height) return; let r = e.width, n = 1 === t.nextInt(2), l = 1 === t.nextInt(2), a = 1 === t.nextInt(2); if (!n && !l && !a) return; let s = new Uint8Array(r * r), o = new Uint16Array(r * r); for (let t = 0; t < r; t++) for (let i = 0; i < r; i++) { let c = n ? r - 1 - i : i, d = l ? r - 1 - t : t; if (a) { let e = c; ((c = d), (d = e)); } ((s[d * r + c] = e.cells[t * r + i]), (o[d * r + c] = e.food[t * r + i])); } (e.cells.set(s), e.food.set(o)); let i = n ? r - 1 - e.nestX : e.nestX, c = l ? r - 1 - e.nestY : e.nestY; if (a) { let e = i; ((i = c), (c = e)); } ((e.nestX = i), (e.nestY = c)); } function renderMapASCII(map) { const symbols = { 0: " ", // EMPTY 1: "#", // WALL 2: "o", // FOOD 3: "S", // NEST }; let output = ""; for (let y = 0; y < map.height; y++) { let row = ""; for (let x = 0; x < map.width; x++) { const cell = X(map, x, y); if (symbols[cell] !== undefined) { row += symbols[cell]; } } output += row + "\n"; } console.log(output); } function randomize_r(r, n) { return ( 0xfffffff & Math.imul( (l = Math.imul(0x45d9f3b ^ r, 0x9e3779b9) ^ Math.imul(n + 1, 0x6c62272e)) ^ (l >>> 16), 0x85ebca6b, ) || 1 ); } function generate_random_maps(e, t, r, n) { let l = []; for (let a = 0; a < n; a++) l.push( (function (e, t, r, n) { let l, a = new C(0x5a5a5a5a ^ r), s = Object.entries(V); a.shuffle(s); let [o, i] = s[n % s.length], c = randomize_r(r, n); d = i(e, t, c); return ((d.name = `${o}-${c.toString(36)}`), d); })(e, t, r, a), ); return l; } function generate_maps(e, t, r, n, typ) { let l = []; for (let a = 0; a < n; a++) l.push( (function (e, t, r, n) { let a = new C(0x5a5a5a5a ^ r); let i = V[typ]; let c = randomize_r(r, n); d = i(e, t, c); return ((d.name = `${typ}-${c.toString(36)}`), d); })(e, t, r, a), ); return l; } function map_from_name(name) { let parts = name.split("-"); let generator = parts[0]; let code = parts[1]; let c = Number.parseInt(code, 36); return V[generator](WIDTH, HEIGHT, c); } const WIDTH = 128; const HEIGHT = 128; r = 42; n = 120; const { program } = require("commander"); program.name("maps").description("Generate and view maps").version("1.0.0"); program.command("view ").action((name, options) => { console.log(`Viewing ${name}`); let map = map_from_name(name); renderMapASCII(map); }); program .command("generate") .option("-s, --seed ", "Define seed", Number, 42) .option("-n, --number ", "Amount of maps", Number, 120) .option("-o, --output ", "Output file", "generated.maps") .option("-t, --type ", "Map type", "random") .action((options) => { let maps = null; if (options.type == "random") { maps = generate_random_maps( WIDTH, HEIGHT, options.seed, options.number, ); } else { maps = generate_maps( WIDTH, HEIGHT, options.seed, options.number, options.type, ); } const ws = fs.createWriteStream(options.output); let header = Buffer.alloc(4); header.writeInt32LE(maps.length); ws.write(header); const MAX_NAME_LENGTH = 31; for (var i = 0; i < maps.length; i++) { let header = Buffer.alloc(MAX_NAME_LENGTH + 3); let name = maps[i].name; let cells = Buffer.from(maps[i].cells); let nest_cell = maps[i].nestY * WIDTH + maps[i].nestX; header.fill(0); header.write(name, 0, MAX_NAME_LENGTH); header.writeInt16LE(nest_cell, MAX_NAME_LENGTH + 1); ws.write(header); ws.write(cells); } ws.end(); }); program.parse(); //let map = map_from_name("gauntlet-41jczs"); //renderMapASCII(map);