diff --git a/assets/scripts/modules/sketches/console.ts b/assets/scripts/modules/sketches/console.ts
new file mode 100644
index 0000000..089f85a
--- /dev/null
+++ b/assets/scripts/modules/sketches/console.ts
@@ -0,0 +1,66 @@
+import {
+ IntegerPoint as Point,
+ IntegerSize as Size,
+ Rect,
+} from "./geometry.js";
+
+export class Console {
+ #screen: Cell[];
+ #size: Size;
+
+ constructor(size: Size) {
+ const length = size.width * size.height;
+ this.#size = size
+
+ this.#screen = new Array(length);
+ for (let i = 0; i < length; i++) {
+ this.#screen[i] = new Cell(' ')
+ }
+ }
+
+ drawInRect(rect: Rect) {
+ const cellSize = new Size(
+ rect.size.width / this.#size.width,
+ rect.size.height / this.#size.height
+ );
+
+ for (let y = 0; y < this.#size.height; y++) {
+ for (let x = 0; x < this.#size.width; x++) {
+ const pt = new Point(x, y);
+ const character = this.characterAt(pt);
+ }
+ }
+ }
+
+ characterAt(pt: Point) {
+ return this.#cellAt(pt).character;
+ }
+
+ #cellAt(pt: Point): Cell {
+ return this.#screen[this.#size.width * pt.y + pt.x];
+ }
+}
+
+export class Color {
+ red: number;
+ green: number;
+ blue: number;
+
+ constructor(r: number, g: number, b: number) {
+ this.red = Math.min(1, Math.max(0, r));
+ this.green = Math.min(1, Math.max(0, g));
+ this.blue = Math.min(1, Math.max(0, b));
+ }
+}
+
+export class Cell {
+ character: String;
+ foregroundColor: Color;
+ backgroundColor?: Color;
+
+ constructor(character: String, foregroundColor?: Color, backgroundColor?: Color) {
+ this.character = character ? character : " ";
+ this.foregroundColor = foregroundColor ? foregroundColor : new Color(1, 1, 1);
+ this.backgroundColor = backgroundColor;
+ }
+}
diff --git a/assets/scripts/modules/sketches/geometry.ts b/assets/scripts/modules/sketches/geometry.ts
new file mode 100644
index 0000000..92f4608
--- /dev/null
+++ b/assets/scripts/modules/sketches/geometry.ts
@@ -0,0 +1,144 @@
+export class Point {
+ x = 0;
+ y = 0;
+
+ constructor(x: number = 0, y: number = 0) {
+ if (x !== null && x !== undefined) {
+ this.x = x;
+ }
+ if (y !== null && y !== undefined) {
+ this.y = y;
+ }
+ }
+
+ toString() {
+ return `(${this.x}, ${this.y})`;
+ }
+
+ equalsPoint(other: Point): boolean {
+ return this.x === other.x && this.y === other.y;
+ }
+}
+
+
+export class IntegerPoint extends Point {
+ constructor(x: number = 0, y: number = 0) {
+ super(x ? Math.floor(x) : 0, y ? Math.floor(y) : 0);
+ }
+
+ *neighbors() {
+ const x = this.x;
+ const y = this.y;
+
+ yield new IntegerPoint(x - 1, y - 1);
+ yield new IntegerPoint(x, y - 1);
+ yield new IntegerPoint(x + 1, y - 1);
+ yield new IntegerPoint(x - 1, y);
+ yield new IntegerPoint(x + 1, y);
+ yield new IntegerPoint(x - 1, y + 1);
+ yield new IntegerPoint(x, y + 1);
+ yield new IntegerPoint(x + 1, y + 1);
+ }
+}
+
+
+export class Size {
+ width = 0;
+ height = 0;
+
+ constructor(width: number = 0, height: number = 0) {
+ if (width !== null && width !== undefined) {
+ this.width = width;
+ }
+ if (height !== null && height !== undefined) {
+ this.height = height;
+ }
+ }
+
+ toString() {
+ return `(${this.width}, ${this.height})`
+ }
+}
+
+
+export class IntegerSize extends Size {
+ constructor(w: number = 0, h: number = 0) {
+ super(w ? Math.floor(w) : 0, h ? Math.floor(h) : 0);
+ }
+}
+
+
+export class Rect {
+ origin = new Point();
+ size = new Size();
+
+ static fromCoordinates(x: number, y: number, w: number, h: number) {
+ return new Rect(new Point(x, y), new Size(w, h));
+ }
+
+ constructor(origin: Point, size: Size) {
+ if (origin instanceof Point) {
+ this.origin = origin;
+ } else {
+ throw new Error("Invalid origin value");
+ }
+
+ if (size instanceof Size) {
+ this.size = size;
+ } else {
+ throw new Error("Invalid size value");
+ }
+ }
+
+ toString() {
+ return `{${this.origin.toString()}, ${this.size.toString()}}`
+ }
+
+ get minX() { return this.origin.x; }
+ get minY() { return this.origin.y; }
+ get maxX() { return this.origin.x + this.size.width; }
+ get maxY() { return this.origin.y + this.size.height; }
+
+ get width() { return this.size.width; }
+ get height() { return this.size.height; }
+ get area() { return this.size.width * this.size.height; }
+
+ *xCoordinates() {
+ for (let x = this.minX; x <= this.maxX; x++) {
+ yield x;
+ }
+ }
+
+ *yCoordinates() {
+ for (let y = this.minY; y <= this.maxY; y++) {
+ yield y;
+ }
+ }
+
+ insetRect(inset: number) {
+ const twiceInset = 2 * inset;
+
+ return Rect.fromCoordinates(
+ this.origin.x + inset,
+ this.origin.y + inset,
+ this.size.width - twiceInset,
+ this.size.height - twiceInset
+ );
+ }
+
+ intersects(other: Rect) {
+ if (other.minX > this.maxX)
+ return false;
+
+ if (other.maxX < this.minX)
+ return false;
+
+ if (other.minY > this.maxY)
+ return false;
+
+ if (other.maxY < this.minY)
+ return false;
+
+ return true;
+ }
+}
diff --git a/assets/scripts/nethack/dungeon.js b/assets/scripts/nethack/dungeon.js
index 0c8eabb..32b3dd7 100644
--- a/assets/scripts/nethack/dungeon.js
+++ b/assets/scripts/nethack/dungeon.js
@@ -1,6 +1,12 @@
const NUMBER_OF_ROOMS = 12;
const TUNNEL_PASSES = 3;
+import {
+ IntegerPoint as Point,
+ IntegerSize as Size,
+ Rect
+} from "scripts/modules/sketches/geometry.ts";
+
class Cell {
static CORRIDOR = "#";
static DOOR_CLOSED = "+";
@@ -11,6 +17,7 @@ class Cell {
constructor(char, charColor) {
this.character = char;
+ this.characterColor = charColor;
}
empty() { this.character = " "; }
@@ -33,104 +40,6 @@ class Cell {
canBecomeDoor() { return this.character === "─" || this.character === "│" }
}
-class Point {
- x = 0;
- y = 0;
-
- constructor(x, y) {
- if (x) { this.x = x; }
- if (y) { this.y = y; }
- }
-
- *neighbors() {
- const x = this.x;
- const y = this.y;
-
- yield new Point(x - 1, y - 1);
- yield new Point(x, y - 1);
- yield new Point(x + 1, y - 1);
- yield new Point(x - 1, y);
- yield new Point(x + 1, y);
- yield new Point(x - 1, y + 1);
- yield new Point(x, y + 1);
- yield new Point(x + 1, y + 1);
- }
-
- equalsPoint(other) { return this.x === other.x && this.y === other.y; }
-}
-
-class Size {
- width = 0;
- height = 0;
-
- constructor(width, height) {
- this.width = width;
- this.height = height;
- }
-}
-
-class Rect {
- origin = new Point();
- size = new Size();
-
- static fromCoordinates(x, y, w, h) {
- return new Rect(new Point(x, y), new Size(w, h));
- }
-
- constructor(origin, size) {
- this.origin = origin;
- this.size = size;
- }
-
- get minX() { return this.origin.x; }
- get minY() { return this.origin.y; }
- get maxX() { return this.origin.x + this.size.width; }
- get maxY() { return this.origin.y + this.size.height; }
-
- get width() { return this.size.width; }
- get height() { return this.size.height; }
- get area() { return this.size.width * this.size.height; }
-
- *xCoordinates() {
- for (let x = this.minX; x <= this.maxX; x++) {
- yield x;
- }
- }
-
- *yCoordinates() {
- for (let y = this.minY; y <= this.maxY; y++) {
- yield y;
- }
- }
-
- insetRect(inset) {
- const twiceInset = 2 * inset;
-
- return Rect.fromCoordinates(
- this.origin.x + inset,
- this.origin.y + inset,
- this.size.width - twiceInset,
- this.size.height - twiceInset
- );
- }
-
- intersects(otherRect) {
- if (otherRect.minX > this.maxX)
- return false;
-
- if (otherRect.maxX < this.minX)
- return false;
-
- if (otherRect.minY > this.maxY)
- return false;
-
- if (otherRect.maxY < this.minY)
- return false;
-
- return true;
- }
-}
-
class Grid {
#size;
#cells = [];
@@ -274,6 +183,7 @@ class NRandomRoomsGenerator {
#generateRooms() {
let rects = new Array();
+ const bounds = this.#bounds;
const sizeRange = NRandomRoomsGenerator.MAX_ROOM_DIMENSION - NRandomRoomsGenerator.MIN_ROOM_DIMENSION;
while (rects.length < this.#numberOfRooms) {
@@ -283,8 +193,8 @@ class NRandomRoomsGenerator {
);
const randomOrigin = new Point(
- this.#bounds.minX + randomInt(this.#bounds.maxX - randomSize.width),
- this.#bounds.minY + randomInt(this.#bounds.maxY - randomSize.height)
+ bounds.minX + randomInt(bounds.maxX - randomSize.width),
+ bounds.minY + randomInt(bounds.maxY - randomSize.height)
);
const proposedRoomRect = new Rect(randomOrigin, randomSize);
@@ -294,6 +204,8 @@ class NRandomRoomsGenerator {
continue;
}
+ console.log("Pushing new room rect", proposedRoomRect.toString());
+
rects.push(proposedRoomRect);
}
@@ -531,7 +443,7 @@ class TunnelGenerator {
let toPoint;
if (fromRoomBounds.maxX < toRoomBounds.minX) {
// fromRoom is farther left than toRoom
-
+
fromPoint = new Point(fromRoomBounds.maxX, fromRoomBounds.minY + 1 + randomInt(fromRoomBounds.height - 2));
foundFromPoint = this.#canPlaceDoorAt(fromPoint);
@@ -699,7 +611,7 @@ class TunnelGenerator {
}
function randomInt(n) {
- max = Math.floor(n);
+ const max = Math.floor(n);
return Math.floor(Math.random() * max);
}
@@ -709,10 +621,14 @@ new p5(p => {
const CELL_WIDTH = 20;
const CELL_HEIGHT = Math.floor(CELL_WIDTH * 1.3);
+ const cellSize = new Size(CELL_WIDTH, CELL_HEIGHT);
+
p.setup = () => {
const container = document.querySelector('#dungeon-background');
- canvasWidth = parseFloat(getComputedStyle(container).width);
- canvasHeight = parseFloat(getComputedStyle(container).height);
+ const canvasWidth = parseFloat(getComputedStyle(container).width);
+ const canvasHeight = parseFloat(getComputedStyle(container).height);
+
+ console.log(`Canvas size is ${(new Size(canvasWidth, canvasHeight)).toString()}`);
let canvas = p.createCanvas(canvasWidth, canvasHeight);
canvas.canvas.removeAttribute('style');
@@ -723,18 +639,25 @@ new p5(p => {
const gridBounds = Rect.fromCoordinates(
0, 0,
- Math.max(80, Math.ceil(canvasWidth / CELL_WIDTH) - 1),
- Math.max(24, Math.ceil(canvasHeight / CELL_HEIGHT) - 1)
+ Math.max(80, Math.floor(canvasWidth / CELL_WIDTH) - 1),
+ Math.max(24, Math.floor(canvasHeight / CELL_HEIGHT) - 1)
);
- console.log(`Generating grid with size ${gridBounds.size.width} x ${gridBounds.size.height}`);
+ if (gridBounds.width === 80) {
+ cellSize.width = Math.floor(canvasWidth / gridBounds.width);
+ }
+ if (gridBounds.height === 24) {
+ cellSize.height = Math.floor(canvasHeight / gridBounds.height);
+ }
+
+ console.log(`Generating grid with size ${gridBounds.size.toString()}, cell: ${cellSize.toString()}`);
grid = new Grid(gridBounds.size.width, gridBounds.size.height);
grid.generate(p, NRandomRoomsGenerator, TunnelGenerator);
}
p.draw = () => {
- p.textSize(CELL_HEIGHT);
+ p.textSize(cellSize.height);
for (let y = 0; y < grid.height; y++) {
for (let x = 0; x < grid.width; x++) {
@@ -744,7 +667,7 @@ new p5(p => {
p.fill(fillColor);
p.textAlign(p.CENTER, p.CENTER);
- p.text(cell.character, x * CELL_WIDTH, y * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT);
+ p.text(cell.character, x * cellSize.width, y * cellSize.height, cellSize.width, cellSize.height);
}
}
diff --git a/layouts/nethack/single.html b/layouts/nethack/single.html
index 8c8591d..726da62 100644
--- a/layouts/nethack/single.html
+++ b/layouts/nethack/single.html
@@ -25,8 +25,8 @@
{{- end -}}
- {{- with partial "secure_asset.html" "scripts/nethack/dungeon.js" -}}
-
+ {{- with resources.Get "scripts/nethack/dungeon.js" -}}
+
{{- end -}}
{{- range $script := .Resources.Match "*.js" -}}