Skip to content

Instantly share code, notes, and snippets.

@raganwald
Created January 14, 2022 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raganwald/e9d5e570533a698bfb541675d5cddc70 to your computer and use it in GitHub Desktop.
Save raganwald/e9d5e570533a698bfb541675d5cddc70 to your computer and use it in GitHub Desktop.
Sketching out some solutions to the Pyramid Problem
// handles primitives like integers and arrays of simple primitives
// all other behaviour is undefined
function superSimpleEquivalent(a, b) {
if (a instanceof Array && b instanceof Array) {
if (a.length != b.length) return false;
for (let i = 0; i < a.length; ++i) {
if (!superSimpleEquivalent(a[i], b[i])) return false;
}
return true;
} else if (a instanceof Position && b instanceof Position) {
return superSimpleEquivalent(a.rods, b.rods);
} else {
return a === b;
}
}
class Position {
constructor(rods = [[], [], []]) {
this.rods = rods;
}
toString() {
const rodStrings = this.rods.map(r => r.join(', '));
return `<< ${rodStrings.join('; ')} >>`;
}
errors() {
if (this.rods.length != 3) {
return `There should be three rods, not ${this.rods.length}`;
}
const elements = this.elements();
const elementSet = new Set(elements);
if (elements.length !== elementSet.size) {
const dups = [...elements];
for (const uniq of elementSet) {
const i = dups.indexOf(uniq);
dups[i] = null;
}
const duplicatedElements = dups.filter(a => a != null);
return `Duplicate element(s): ${duplicatedElements.join(', ')}`;
}
for (const rodElements of this.rods) {
const sortedElements = [...rodElements].sort();
if (!superSimpleEquivalent(rodElements, sortedElements)) {
return `Rod ${rodElements.join(', ')} is out-of-order`;
}
}
return false;
}
valid() {
return this.errors() === false;
}
havingMoved(fromIndex, toIndex) {
const fromRod = this.rods[fromIndex];
const toRod = this.rods[toIndex];
if (fromRod === undefined) {
return undefined;
}
if (toRod === undefined) {
return undefined;
}
if (fromIndex === toIndex) {
return undefined;
}
const topFrom = fromRod[0];
const topTo = toRod[0];
if (topFrom === undefined) {
return undefined;
}
if (topTo != undefined && topTo < topFrom) {
return undefined;
}
const resultRods = this.rods.map(rod => [...rod]);
resultRods[toIndex].push(resultRods[fromIndex].pop());
return new Position(resultRods);
}
wouldBeValidMove(fromIndex, toIndex) {
return this.havingMoved(fromIndex, toIndex) != undefined;
}
elements() {
return this.rods.flatMap(x => x);
}
resembles(other) {
const mySortedElements = [...this.elements()].sort();
const otherSortedElements = [...other.elements()].sort();
return superSimpleEquivalent(mySortedElements, otherSortedElements);
}
}
console.log('----------------------------------------------------------------------');
const testCases = [
[[], false],
[[[], [], []], true],
[[[1], [2], [3, 4]], true],
[[[1], [2, 3], [3, 4]], false],
[[[1], [2, 3], [5, 4]], false]
];
for (const [testCase, expectation] of testCases) {
const p = new Position(testCase);
const validity = p.valid();
const passed = validity === expectation;
const passMessage = passed ? "Pass" : "Fail";
if (validity) {
console.log(`${passMessage}: ${p.toString()} is valid`);
} else {
console.log(`${passMessage}: ${p.toString()} is invalid: ${p.errors()}`);
}
}
const testPosition = new Position([[1, 2], [], [3, 4]]);
const testMoveCases = [
[0, 0, false],
[0, 1, true],
[0, 2, true],
[1, 0, false],
[1, 2, false],
[2, 0, false],
[2, 1, true]
];
for (const [fromIndex, toIndex, expectation] of testMoveCases) {
const validity = testPosition.wouldBeValidMove(fromIndex, toIndex);
const passed = validity === expectation;
const passMessage = passed ? "Pass" : "Fail";
console.log(`${passMessage}: ${fromIndex} -> ${toIndex} is ${expectation ? '' : 'not '}a valid move`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment