From e751bd31b77a96f91e3642ef74bc8455eb9eda0f Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Thu, 12 Oct 2023 11:05:29 -0700 Subject: [PATCH] Dots and Boxes v1 from the P5js editor --- content/games/dots-and-boxes/index.md | 10 ++ content/games/dots-and-boxes/sketch.js | 215 +++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 content/games/dots-and-boxes/index.md create mode 100644 content/games/dots-and-boxes/sketch.js diff --git a/content/games/dots-and-boxes/index.md b/content/games/dots-and-boxes/index.md new file mode 100644 index 0000000..04b7531 --- /dev/null +++ b/content/games/dots-and-boxes/index.md @@ -0,0 +1,10 @@ +--- +title: "Dots and Boxes" +draft: true +resource: + - src: sketch.js + params: + is_module: false +--- + +{{< figures/p5 >}} diff --git a/content/games/dots-and-boxes/sketch.js b/content/games/dots-and-boxes/sketch.js new file mode 100644 index 0000000..554185f --- /dev/null +++ b/content/games/dots-and-boxes/sketch.js @@ -0,0 +1,215 @@ +// Eryn Wells + +class Player { + name; + + #color; + + constructor(name, color) { + this.name = name; + this.#color = color; + } + + get color() { + + } +} + +class Point { + static fromEventCoordinates(x, y) { + return new Point(x - marginSize, y - marginSize); + } + + x = 0; + y = 0; + + constructor(x = 0, y = 0) { + this.x = x; + this.y = y; + } + + /// Return a value that uniquely identifies this Point. + get identifier() { + return `x:${this.x},y:${this.y}`; + } + + /// Convert this point to an array of coordinates. + get coordinates() { + return [this.x, this.y]; + } + + /// Convert a Point in grid space to pixel space. + toPixelPoint() { + return [marginSize + this.x * cellSize, marginSize + this.y * cellSize]; + } + + convertPixelPointToGridPointWithRemainder() { + let clickCol = Math.floor(this.x / cellSize); + let clickRow = Math.floor(this.y / cellSize); + + let clickColRemainder = this.x - (clickCol * cellSize); + let clickRowRemainder = this.y - (clickRow * cellSize); + + if (clickColRemainder >= (cellSize - hitBoxMargin)) { + clickCol += 1; + clickColRemainder = clickColRemainder - cellSize; + } + + if (clickRowRemainder >= (cellSize - hitBoxMargin)) { + clickRow += 1; + clickRowRemainder = clickRowRemainder - cellSize; + } + + return [new Point(clickCol, clickRow), new Point(clickColRemainder, clickRowRemainder)]; + } + + /// Return a string that's nice to read. + toString() { + return `(${this.x}, ${this.y})`; + } +} + +class Line { + player; + from; + to; + + constructor(player, from, to) { + this.player = player; + this.from = from; + this.to = to; + } + + get identifier() { + return `from:[${this.from.identifier}],to:[${this.to.identifier}]`; + } +} + +const sketch = p => { + const marginSize = 10; + const cellSize = 40; + const gridSize = 20; + const hitBoxMargin = 7; + + let player = 1; + let lines = new Map(); + + p.setup = () => { + const canvasSize = [ + cellSize * (gridSize - 1) + marginSize * 2, + cellSize * (gridSize - 1) + marginSize * 2 + ]; + createCanvas(...canvasSize); + }; + + let mouseBoundingBoxRect; + let debugNeighboringBoxA; + let debugNeighboringBoxB; + + p.draw = () => { + background(220); + + for (const l of lines.values()) { + const strokeColor = l.player === 1 ? color(255, 0, 0) : color(0, 0, 255); + p.stroke(strokeColor); + p.strokeWeight(2); + p.line( + ...l.from.toPixelPoint(), + ...l.to.toPixelPoint() + ); + } + + drawGrid(); + + debugDrawMouseBoundingBoxRect(); + debugDrawNeighboringBoxes(); + + p.noLoop(); + }; + + function drawGrid() { + for (let i = 0; i < gridSize; i++) { + for (let j = 0; j < gridSize; j++) { + const [x, y] = [marginSize + cellSize * j, marginSize + cellSize * i]; + p.noStroke(); + p.fill(128); + p.circle(x, y, 6); + } + } + } + + function debugDrawMouseBoundingBoxRect() { + if (!mouseBoundingBoxRect) { + return; + } + + p.stroke(255, 0, 0); + p.strokeWeight(1); + p.noFill(); + p.rect(...mouseBoundingBoxRect); + } + + function debugDrawNeighboringBoxes() { + + } + + p.mouseMoved = (event) => { + mouseBoundingBoxRect = findHitBox(event); + + if (mouseBoundingBoxRect) { + loop(); + } + }; + + p.mouseClicked = (event) => { + const clickPoint = Point.fromEventCoordinates(event.x, event.y); + + const [gridPoint, gridPointRemainder] = clickPoint.convertPixelPointToGridPointWithRemainder(); + + const isVertical = gridPointRemainder.x > -hitBoxMargin && gridPointRemainder.x < hitBoxMargin; + + const from = gridPoint; + const to = isVertical ? new Point(gridPoint.x, gridPoint.y + 1) : new Point(gridPoint.x + 1, gridPoint.y); + + console.log( + "Mouse clicked.", + clickPoint.toString(), + gridPoint.toString(), + gridPointRemainder.toString(), + from.toString(), + to.toString(), + event + ); + + const newLine = new Line(player, from, to); + + const newLineId = newLine.identifier; + if (!lines.has(newLineId)) { + lines.set(newLineId, newLine); + + player = (player === 1 ? 2 : 1); + + loop(); + } + }; + + function findHitBox(mouseEvent) { + const clickPoint = Point.fromEventCoordinates(mouseEvent.x, mouseEvent.y); + + const [gridPoint, gridPointRemainder] = clickPoint.convertPixelPointToGridPointWithRemainder(); + + const isHorizontal = gridPointRemainder.y > -hitBoxMargin && gridPointRemainder.y < hitBoxMargin; + const isVertical = gridPointRemainder.x > -hitBoxMargin && gridPointRemainder.x < hitBoxMargin; + + if (isHorizontal === isVertical) { + return null; + } + + return [ + marginSize + gridPoint.x * cellSize + (isVertical ? -hitBoxMargin : 0), + marginSize + gridPoint.y * cellSize + (!isVertical ? -hitBoxMargin : 0), + isVertical ? 2 * hitBoxMargin : cellSize, + isVertical ? cellSize : 2 * hitBoxMargin, + ]; + } +};