Public
Edited
Dec 26, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const thirteen = Piece.fromString('-*--*** |**----* |-*---* |-*----* |-*--***');
return thirteen.toSVG();
}
Insert cell
{
const thirteen = Piece.fromString('-*--*** |**----* |-*---* |-*----* |-*--***');
return Piece.fromMask(getUnionOfMasks(getMask(thirteen, {x: 7, y: 5}),
initMask(13, 5, (x, y) => x < 8 ? 0 : 1))).toSVG();
}
Insert cell
new Array(10).fill(0).map(() => new Array(10).fill(1))
Insert cell
function initMask(width, height, func) {
return new Array(height).fill(0).map((_, i) => new Array(width).fill(0).map((_, j) => func(j, i)));
}
Insert cell
Insert cell
Insert cell
getMask(Piece.fromString('**|-**'), {x: 3, y: 2})
Insert cell
m1 = getMask(Piece.fromString('--|*'), {x: 2, y: 2})
Insert cell
m2 = getMask(Piece.fromString('-*-*|--'), {x: 4, y: 2})
Insert cell
Piece.fromMask(m1).toSVG()
Insert cell
testGetUnionMask()
Insert cell
isEqual([[1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3]])
Insert cell
function assert(value, message) {
if (!value) {
if (message === undefined) {
throw new Error(`Assertion Error`);
} else {
throw new Error(`Assertion Error: ${message}`);
}
}
}
Insert cell
Insert cell
Insert cell
Piece.fromMask(m2).toSVG()
Insert cell
Piece.fromMask(mUnion).toSVG()
Insert cell
mUnion = getUnionOfMask(m1, m2)
Insert cell
class Container { // Container of pieces
constructor(width, height) {
this.size = {x: width, y: height};
this.pieces = [];
}
checkPiece(piece, position) {
// let unionOfPieces = this.pieces.map(p => getMask(p)).reduce((p1, p2) => getUnion(p1, p2));
// let mask = intersectMask(getMask(piece), unionOfPieces);
// return isZeroMask(mask);
return true;
}
add(piece, position) {
if (this.checkPiece(piece, position)) {
piece.position = position;
this.pieces.push(piece);
return true;
} else {
return false;
}
}
getPossibleActions() {}
getNeighborStates() {}
}
Insert cell
{
let s = new Container(4, 5);
s.add(Piece.fromString("**|**", {x: 0, y: 1}));
return s;
}
Insert cell
state = ({
w: 4,
h: 5,
pieces: [Piece.fromString('**|**')]
})
Insert cell
Insert cell
function showPiece(svg, offset, piece) {
for (let cell of piece.cells) {
let [x, y] = [cell.x * rectSize + offset.x + margin.left, cell.y * rectSize + offset.y + margin.top];
graphics.rect(svg, x, y, rectSize, rectSize);
}
}
Insert cell
Piece.fromArray([
[1,1], [2,1],
[2,2], [3,2],
]).getSize();
Insert cell
Insert cell
class Piece { // polyomino piece
constructor(cells = []) {
this.cells = [];
for (let cell of cells) {
this.cells.push(cell.copy());
}
}
translate(v) {
let {x: dx, y: dy} = v;
for (let i = 0; i < this.cells.length; i++) {
this.cells[i].x += dx;
this.cells[i].y += dy;
}
return this;
}
normalize() {
let minSize = this.getLowerBound();
this.translate({x: -minSize.x, y: -minSize.y});
return this;
}
getSize() {
let upper = this.getUpperBound();
let lower = this.getLowerBound();
return {x: upper.x - lower.x, y: upper.y - lower.y};
}
getLowerBound() {
let minSize = {x: Infinity, y: Infinity};
for (let cell of this.cells) {
if (cell.x < minSize.x) { minSize.x = cell.x }
if (cell.y < minSize.y) { minSize.y = cell.y }
}
return minSize;
}
getUpperBound() {
let maxSize = {x: 0, y: 0};
for (let cell of this.cells) {
if (cell.x > maxSize.x) { maxSize.x = cell.x }
if (cell.y > maxSize.y) { maxSize.y = cell.y }
}
return {x: maxSize.x + 1, y: maxSize.y + 1};
}
static fromMask(mask) {
const piece = new Piece();
for (let i = 0; i < mask.length; i++) {
let row = mask[i];
for (let j = 0; j < row.length; j++) {
if (row[j] === 1) {
piece.cells.push(new Cell(j, i));
}
}
}
return piece;
}
static fromArray(pairs) {
const piece = new Piece();
for (let pair of pairs) {
let [x, y] = pair;
piece.cells.push(new Cell(x, y));
}
return piece;
}
/*
by gpt3.5
If the character is a pipe character ('|'), it means that the cursor has reached the end of a row in the game piece. In this case, the code increments the y variable to move to the next row and resets the x variable to 0 to start from the beginning of the next row.

If the character is an asterisk ('*'), it means that the cursor has encountered a cell in the game piece. In this case, the code creates a new instance of the Cell class with the current x and y coordinates and adds it to the p.cells array.
*/

/**
* Converts a string representation of a game piece into a Piece object.
*
* @param {string} s - The string representation of the game piece.
* @returns {Piece} - The converted Piece object.
*/
static fromString(s) {
let [x, y] = [0, 0];
let p = new Piece();
for (let ch of s) {
if ('\n\t\r '.includes(ch)) { continue; }
if (ch === '|') { y++; x=0; continue; }
if (ch === '*') { p.cells.push(new Cell(x, y)); }
x++;
}
return p;
}
toSVG() {
const pieceSize = this.getUpperBound();
let svgSize = {x: rectSize * pieceSize.x + margin.left, y: rectSize * pieceSize.y + margin.top};
const svg = d3.create('svg').attr('width', svgSize.x).attr('height', svgSize.y);
showPiece(svg, {x: 0, y: 0}, this);
graphics.line(svg, [margin.left, margin.top], [svgSize.x, margin.top]);
graphics.line(svg, [margin.left, margin.top], [margin.left, svgSize.y]);
return svg.node();
}
}
Insert cell
Insert cell
Insert cell
testPieceFromString(examplePiece.str, examplePiece.out)
Insert cell
Insert cell
Insert cell
Insert cell
examplePiece = ({
str:
`-*|
**|
-*|`,
out: [[1, 0], [0, 1], [1, 1], [1, 2]],
})
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more