after running a lint + format
This commit is contained in:
parent
1a47184c29
commit
2b2e1ec0c9
4 changed files with 131 additions and 111 deletions
|
@ -8,5 +8,5 @@ module.exports = {
|
||||||
node: true,
|
node: true,
|
||||||
mocha: true,
|
mocha: true,
|
||||||
},
|
},
|
||||||
extends: ["eslint:recommended", "prettier"]
|
extends: ["eslint:recommended", "prettier"],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# javascript-tri-peaks-solitaire-solver
|
# javascript-tri-peaks-solitaire-solver
|
||||||
|
|
||||||
A brute force solver for Microsoft Tri-Peaks solitaire written in javascript.
|
A brute force solver for Microsoft Tri-Peaks solitaire written in javascript.
|
||||||
|
|
||||||
You can see it in action on my [website](https://igniparoustempest.github.io/tri-peaks-solitaire-solver/):
|
You can see it in action on my [website](https://igniparoustempest.github.io/tri-peaks-solitaire-solver/):
|
||||||
|
|
||||||
1. Enter the string "8S TS 4D 7S 5D 7C 2D JH AC 3S 2H 3H 9H KC QC TD 8D 9C 7H 9D JS QS 4H 5C 5S 4C 2C QD 8C KD 3D KS JD 2S 7D KH AH 5H 9S 4S QH 6S 6D 3C JC TC 8H 6C TH AS AD 6H" into the textfield.
|
1. Enter the string "8S TS 4D 7S 5D 7C 2D JH AC 3S 2H 3H 9H KC QC TD 8D 9C 7H 9D JS QS 4H 5C 5S 4C 2C QD 8C KD 3D KS JD 2S 7D KH AH 5H 9S 4S QH 6S 6D 3C JC TC 8H 6C TH AS AD 6H" into the textfield.
|
||||||
2. Click "import"
|
2. Click "import"
|
||||||
3. Click "solve"
|
3. Click "solve"
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
This is probably quite a poor implementation. Please don't fault me, I am teaching myself javascript.
|
This is probably quite a poor implementation. Please don't fault me, I am teaching myself javascript.
|
||||||
|
|
||||||
|
|
62
solver.js
62
solver.js
|
@ -18,7 +18,10 @@ class Card {
|
||||||
* @returns {boolean} True if sequential, false otherwise.
|
* @returns {boolean} True if sequential, false otherwise.
|
||||||
*/
|
*/
|
||||||
isSequential(card) {
|
isSequential(card) {
|
||||||
return (this.integerValue + 1) % 13 === card.integerValue || (this.integerValue - 1) % 13 === card.integerValue;
|
return (
|
||||||
|
(this.integerValue + 1) % 13 === card.integerValue ||
|
||||||
|
(this.integerValue - 1) % 13 === card.integerValue
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get toString() {
|
get toString() {
|
||||||
|
@ -33,8 +36,7 @@ class Pyramid {
|
||||||
|
|
||||||
get isCleared() {
|
get isCleared() {
|
||||||
for (let i = 0; i < this.array.length; i++) {
|
for (let i = 0; i < this.array.length; i++) {
|
||||||
if (this.array[i] !== 0)
|
if (this.array[i] !== 0) return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -42,20 +44,33 @@ class Pyramid {
|
||||||
get freeCardIndices() {
|
get freeCardIndices() {
|
||||||
let freeIndices = [];
|
let freeIndices = [];
|
||||||
for (let i = this.array.length - 1; i >= 0; i--) {
|
for (let i = this.array.length - 1; i >= 0; i--) {
|
||||||
if (this.array[i] === 0)
|
if (this.array[i] === 0) continue;
|
||||||
continue;
|
|
||||||
const secondOffset = Math.floor((i - 3) / 2);
|
const secondOffset = Math.floor((i - 3) / 2);
|
||||||
// This is the last row
|
// This is the last row
|
||||||
if (i >= 18)
|
if (i >= 18) freeIndices.push(i);
|
||||||
freeIndices.push(i);
|
|
||||||
// Third row
|
// Third row
|
||||||
else if (i <= 17 && i >= 9 && this.array[i + 9] === 0 && this.array[i + 10] === 0)
|
else if (
|
||||||
|
i <= 17 &&
|
||||||
|
i >= 9 &&
|
||||||
|
this.array[i + 9] === 0 &&
|
||||||
|
this.array[i + 10] === 0
|
||||||
|
)
|
||||||
freeIndices.push(i);
|
freeIndices.push(i);
|
||||||
// Second row
|
// Second row
|
||||||
else if (i <= 8 && i >= 3 && this.array[i + 6 + secondOffset] === 0 && this.array[i + 7 + secondOffset] === 0)
|
else if (
|
||||||
|
i <= 8 &&
|
||||||
|
i >= 3 &&
|
||||||
|
this.array[i + 6 + secondOffset] === 0 &&
|
||||||
|
this.array[i + 7 + secondOffset] === 0
|
||||||
|
)
|
||||||
freeIndices.push(i);
|
freeIndices.push(i);
|
||||||
// First row
|
// First row
|
||||||
else if (i <= 2 && i >= 0 && this.array[i + 3 + i] === 0 && this.array[i + 4 + i] === 0)
|
else if (
|
||||||
|
i <= 2 &&
|
||||||
|
i >= 0 &&
|
||||||
|
this.array[i + 3 + i] === 0 &&
|
||||||
|
this.array[i + 4 + i] === 0
|
||||||
|
)
|
||||||
freeIndices.push(i);
|
freeIndices.push(i);
|
||||||
}
|
}
|
||||||
return freeIndices;
|
return freeIndices;
|
||||||
|
@ -63,13 +78,21 @@ class Pyramid {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoveString {
|
class MoveString {
|
||||||
static gameWon() {return "You have won.";}
|
static gameWon() {
|
||||||
static gameLost() {return "There are no more valid moves.";}
|
return "You have won.";
|
||||||
static match(cardA) {return "Move " + cardA + " onto the stock.";}
|
}
|
||||||
static flipStock() {return "Draw a new stock card.";}
|
static gameLost() {
|
||||||
|
return "There are no more valid moves.";
|
||||||
|
}
|
||||||
|
static match(cardA) {
|
||||||
|
return "Move " + cardA + " onto the stock.";
|
||||||
|
}
|
||||||
|
static flipStock() {
|
||||||
|
return "Draw a new stock card.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const GameStates = Object.freeze({"won": true, "lost": false});
|
const GameStates = Object.freeze({ won: true, lost: false });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Solves a Tri Peaks solitaire game.
|
* Solves a Tri Peaks solitaire game.
|
||||||
|
@ -101,8 +124,7 @@ function solve(pyramidArray, stockArray, stockIndex = 0, moveArray = []) {
|
||||||
// match free cards with stock
|
// match free cards with stock
|
||||||
for (let i = 0; i < freeCardsIndices.length; i++) {
|
for (let i = 0; i < freeCardsIndices.length; i++) {
|
||||||
let cardA = new Card(pyramidArray[freeCardsIndices[i]]);
|
let cardA = new Card(pyramidArray[freeCardsIndices[i]]);
|
||||||
if (!cardA.isSequential(topStock))
|
if (!cardA.isSequential(topStock)) continue;
|
||||||
continue;
|
|
||||||
let newStock = JSON.parse(JSON.stringify(stockArray));
|
let newStock = JSON.parse(JSON.stringify(stockArray));
|
||||||
newStock.splice(stockIndex + 1, 0, cardA.toString);
|
newStock.splice(stockIndex + 1, 0, cardA.toString);
|
||||||
stockIndex++;
|
stockIndex++;
|
||||||
|
@ -114,16 +136,14 @@ function solve(pyramidArray, stockArray, stockIndex = 0, moveArray = []) {
|
||||||
newPyramidArray[freeCardsIndices[i]] = 0;
|
newPyramidArray[freeCardsIndices[i]] = 0;
|
||||||
|
|
||||||
let result = solve(newPyramidArray, newStock, stockIndex, newMoveArray);
|
let result = solve(newPyramidArray, newStock, stockIndex, newMoveArray);
|
||||||
if (result[0] === GameStates.won)
|
if (result[0] === GameStates.won) return result;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flip over a new card
|
// Flip over a new card
|
||||||
newMoveArray = JSON.parse(JSON.stringify(moveArray));
|
newMoveArray = JSON.parse(JSON.stringify(moveArray));
|
||||||
newMoveArray.push(MoveString.flipStock());
|
newMoveArray.push(MoveString.flipStock());
|
||||||
let result = solve(pyramidArray, stockArray, stockIndex + 1, newMoveArray);
|
let result = solve(pyramidArray, stockArray, stockIndex + 1, newMoveArray);
|
||||||
if (result[0] === GameStates.won)
|
if (result[0] === GameStates.won) return result;
|
||||||
return result;
|
|
||||||
|
|
||||||
// This node was useless
|
// This node was useless
|
||||||
return [GameStates.lost, moveArray];
|
return [GameStates.lost, moveArray];
|
||||||
|
|
10
test.js
10
test.js
|
@ -1,15 +1,15 @@
|
||||||
const assert = require('assert');
|
const assert = require("assert");
|
||||||
const solver = require('./solver');
|
const solver = require("./solver");
|
||||||
|
|
||||||
const solvable_games = [
|
const solvable_games = [
|
||||||
"8S TS 4D 7S 5D 7C 2D JH AC 3S 2H 3H 9H KC QC TD 8D 9C 7H 9D JS QS 4H 5C 5S 4C 2C QD 8C KD 3D KS JD 2S 7D KH AH 5H 9S 4S QH 6S 6D 3C JC TC 8H 6C TH AS AD 6H",
|
"8S TS 4D 7S 5D 7C 2D JH AC 3S 2H 3H 9H KC QC TD 8D 9C 7H 9D JS QS 4H 5C 5S 4C 2C QD 8C KD 3D KS JD 2S 7D KH AH 5H 9S 4S QH 6S 6D 3C JC TC 8H 6C TH AS AD 6H",
|
||||||
"5D 9C 5S QS 8S 9D AS 5C 2S QD KC 9H 4H QC 2H 8D 4C 4D JC TS 6D 7H QH 3S 5H JH 6H 2D AC 7S 7C 3D KD 9S 3C TH 6C AH 8H TC 4S 8C AD 3H KS 6S JS 7D JD TD 2C KH"
|
"5D 9C 5S QS 8S 9D AS 5C 2S QD KC 9H 4H QC 2H 8D 4C 4D JC TS 6D 7H QH 3S 5H JH 6H 2D AC 7S 7C 3D KD 9S 3C TH 6C AH 8H TC 4S 8C AD 3H KS 6S JS 7D JD TD 2C KH",
|
||||||
];
|
];
|
||||||
|
|
||||||
it('should solve known games', () => {
|
it("should solve known games", () => {
|
||||||
assert.equal(true, true);
|
assert.equal(true, true);
|
||||||
solvable_games.forEach(function (i) {
|
solvable_games.forEach(function (i) {
|
||||||
const array = i.split(' ');
|
const array = i.split(" ");
|
||||||
const result = solver.solve(array.slice(0, 28), array.slice(28, 52), 0, []);
|
const result = solver.solve(array.slice(0, 28), array.slice(28, 52), 0, []);
|
||||||
assert.equal(result[0], true);
|
assert.equal(result[0], true);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue