implemented tests for Card.isSequential method
This commit is contained in:
parent
d4f308d4bc
commit
54127871f9
3 changed files with 57 additions and 29 deletions
34
README.md
34
README.md
|
@ -2,32 +2,18 @@
|
||||||
|
|
||||||
A brute force solver for Microsoft Tri-Peaks solitaire written in javascript.
|
A brute force solver for Microsoft Tri-Peaks solitaire written in javascript.
|
||||||
|
|
||||||
This is a fork of [Courtney Pitcher's project](https://github.com/IgniparousTempest/javascript-tri-peaks-solitaire-solver), which I've modified for my own purposes.
|
This is a fork of [Courtney Pitcher's project](https://github.com/IgniparousTempest/javascript-tri-peaks-solitaire-solver), with several changes.
|
||||||
|
|
||||||
_NOTE:_ Due to a "hard" game being included in `test.js` now, testing takes longer (almost 3 minutes to complete on my computer).
|
## Changes
|
||||||
|
|
||||||
## Fix Card Matching
|
- fixed card matching, implemented card matching tests
|
||||||
|
- solver now returns a "first best set of moves found" for unsolvable games (the first set of moves found that removes the most cards from the board)
|
||||||
It seemed I was getting solutions that didn't make sense, which I tracked down to the logic used to compare cards. I believe I've fixed this, and have now been getting real solutions.
|
|
||||||
|
|
||||||
In fact, it's now able to solve the test game I thought was "unsolvable," so I had to disable that test until I can identify another unsolvable game! But the logic for unsolvable games should still work.
|
|
||||||
|
|
||||||
## Unsolvable Games
|
|
||||||
|
|
||||||
For unsolvable games, this solver will return one possible "best path" — a set of moves that clears the most cards from the board. If you're playing a game with a goal like "clear all Aces," and the full board is unsolvable, this might help you at least clear those Aces!
|
|
||||||
|
|
||||||
However, it could be that a given board has more than one path to removing most of the cards, and the one this solver returns might not remove the cards you need. If I get around to it, a better improvement might be to return, say, the top 5 best paths.
|
|
||||||
|
|
||||||
_NOTE:_ Unsolvable boards could take up to 10 minutes to process, so be patient.
|
|
||||||
|
|
||||||
## Playing
|
|
||||||
|
|
||||||
I have yet to implement this in a website but it can be run directly in node. Eventually I'll put up a sample into which you can enter a string like one of these and get a solution:
|
|
||||||
|
|
||||||
- solvable: "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"
|
|
||||||
- partial board: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2D KH 8C 6S 6H 2C 8H JC 9C 4D AD TH 2S AS QH 5H AH 3H 2H 4S 6D 3C TS JD 9H KD AC JS 9S 4H 4C 5S 5D 5C"
|
|
||||||
~~- unsolvable: "2D 6D AD 9S 4C 7C 7S 7D 9C 2S AC 8D 6S 6H 3C 5H QS JS 4S JH 5C AS 3H 3S AH TD 4D 5S TH 7H KS QH 6C KD 8S 2C TC JC 5D 3D 2H TS 4H JD KC KH 8H QC 8C QD 9D 9H"~~
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
Per Courtney Pitcher, "This is probably quite a poor implementation." Please don't fault either of us, he was teaching himself javascript, and I'm probably even less qualified...
|
- Unsolvable games can take 6 or more minutes to solve, so be patient.
|
||||||
|
- Per Courtney Pitcher, "This is probably quite a poor implementation." Please don't fault either of us, he was teaching himself javascript, and I'm probably even less qualified...
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [ ] HTML ui/demo _in progress_
|
||||||
|
|
|
@ -184,4 +184,4 @@ function solve(
|
||||||
return [GameStates.lost, moveArray, newBestMoveArray];
|
return [GameStates.lost, moveArray, newBestMoveArray];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { solve };
|
module.exports = { Card, solve };
|
||||||
|
|
50
test.js
50
test.js
|
@ -1,6 +1,48 @@
|
||||||
const assert = require("assert");
|
const assert = require("assert");
|
||||||
const solver = require("./solver");
|
const solver = require("./solver");
|
||||||
|
const Card = solver.Card;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tests for classes
|
||||||
|
*/
|
||||||
|
const sequentialCardPairs = [
|
||||||
|
["AH", "2D"],
|
||||||
|
["KC", "AS"],
|
||||||
|
["JD", "TC"],
|
||||||
|
["6S", "7H"],
|
||||||
|
["AC", "KH"],
|
||||||
|
["4S", "3S"],
|
||||||
|
];
|
||||||
|
const nonSequentialCardPairs = [
|
||||||
|
["JD", "9D"],
|
||||||
|
["QC", "AC"],
|
||||||
|
["8S", "3S"],
|
||||||
|
["KS", "2C"],
|
||||||
|
["4S", "6S"],
|
||||||
|
["5H", "7H"],
|
||||||
|
];
|
||||||
|
|
||||||
|
it("Card isSequential should return true for sequential cards", () => {
|
||||||
|
sequentialCardPairs.forEach((cp) => {
|
||||||
|
const cardA = new Card(cp[0]);
|
||||||
|
const cardB = new Card(cp[1]);
|
||||||
|
assert.equal(cardA.isSequential(cardB), true);
|
||||||
|
assert.equal(cardB.isSequential(cardA), true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Card isSequential should return false for non-sequential cards", () => {
|
||||||
|
nonSequentialCardPairs.forEach((cp) => {
|
||||||
|
const cardA = new Card(cp[0]);
|
||||||
|
const cardB = new Card(cp[1]);
|
||||||
|
assert.equal(cardA.isSequential(cardB), false);
|
||||||
|
assert.equal(cardB.isSequential(cardA), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tests for solve algorithm
|
||||||
|
*/
|
||||||
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",
|
||||||
|
@ -13,16 +55,16 @@ const partial_games = [
|
||||||
"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2D KH 8C 6S 6H 2C 8H JC 9C 4D AD TH 2S AS QH 5H AH 3H 2H 4S 6D 3C TS JD 9H KD AC JS 9S 4H 4C 5S 5D 5C",
|
"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2D KH 8C 6S 6H 2C 8H JC 9C 4D AD TH 2S AS QH 5H AH 3H 2H 4S 6D 3C TS JD 9H KD AC JS 9S 4H 4C 5S 5D 5C",
|
||||||
];
|
];
|
||||||
|
|
||||||
it("should solve known games", () => {
|
it("solve should solve known games", () => {
|
||||||
solvable_games.forEach(function (i) {
|
solvable_games.forEach((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);
|
||||||
});
|
});
|
||||||
}).timeout(200000);
|
}).timeout(200000);
|
||||||
|
|
||||||
it("should solve partial games", () => {
|
it("solve should solve partial games", () => {
|
||||||
partial_games.forEach(function (i) {
|
partial_games.forEach((i) => {
|
||||||
const array = i.split(" ").map((x) => (x === "0" ? 0 : x));
|
const array = i.split(" ").map((x) => (x === "0" ? 0 : x));
|
||||||
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