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,4 +1,5 @@
|
||||||
# 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/):
|
||||||
|
@ -10,4 +11,3 @@ You can see it in action on my [website](https://igniparoustempest.github.io/tri
|
||||||
## 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