From 60971a2d1350c8d17a3df0b67cc01514129081c3 Mon Sep 17 00:00:00 2001 From: Adam Piontek Date: Thu, 15 Sep 2022 07:31:26 -0400 Subject: [PATCH] fix issue 2, report proper cards cleared progress --- dist/assets/{index.b5c45835.js => index.53789001.js} | 4 ++-- dist/assets/solverWorker.25a6ccd7.js | 1 - dist/assets/solverWorker.737bce24.js | 1 + dist/index.html | 2 +- package.json | 2 +- solver.js | 2 +- src/js/main.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename dist/assets/{index.b5c45835.js => index.53789001.js} (99%) delete mode 100644 dist/assets/solverWorker.25a6ccd7.js create mode 100644 dist/assets/solverWorker.737bce24.js diff --git a/dist/assets/index.b5c45835.js b/dist/assets/index.53789001.js similarity index 99% rename from dist/assets/index.b5c45835.js rename to dist/assets/index.53789001.js index 281ebef..0c79833 100644 --- a/dist/assets/index.b5c45835.js +++ b/dist/assets/index.53789001.js @@ -57,8 +57,8 @@ ${i?'Expression: "'+i+`" `,Ai=` `,Mi=` `,_i=` -`;let n0={"1B":_2,"2B":L2,"1J":T2,AC:R2,"2C":B2,"3C":D2,"4C":H2,"5C":E2,"6C":V2,"7C":O2,"8C":F2,"9C":Y2,TC:$2,JC:I2,QC:U2,KC:K2,AD:q2,"2D":P2,"3D":Z2,"4D":j2,"5D":N2,"6D":J2,"7D":Q2,"8D":z2,"9D":W2,TD:G2,JD:X2,QD:ei,KD:ti,AH:ii,"2H":si,"3H":ri,"4H":ni,"5H":oi,"6H":li,"7H":hi,"8H":ai,"9H":di,TH:ui,JH:ci,QH:fi,KH:xi,AS:gi,"2S":wi,"3S":pi,"4S":Ci,"5S":yi,"6S":vi,"7S":mi,"8S":ki,"9S":Si,TS:bi,JS:Ai,QS:Mi,KS:_i};function Li(){return new Worker(""+new URL("solverWorker.25a6ccd7.js",import.meta.url).href)}const Ti='',Ri=` +`;let n0={"1B":_2,"2B":L2,"1J":T2,AC:R2,"2C":B2,"3C":D2,"4C":H2,"5C":E2,"6C":V2,"7C":O2,"8C":F2,"9C":Y2,TC:$2,JC:I2,QC:U2,KC:K2,AD:q2,"2D":P2,"3D":Z2,"4D":j2,"5D":N2,"6D":J2,"7D":Q2,"8D":z2,"9D":W2,TD:G2,JD:X2,QD:ei,KD:ti,AH:ii,"2H":si,"3H":ri,"4H":ni,"5H":oi,"6H":li,"7H":hi,"8H":ai,"9H":di,TH:ui,JH:ci,QH:fi,KH:xi,AS:gi,"2S":wi,"3S":pi,"4S":Ci,"5S":yi,"6S":vi,"7S":mi,"8S":ki,"9S":Si,TS:bi,JS:Ai,QS:Mi,KS:_i};function Li(){return new Worker(""+new URL("solverWorker.737bce24.js",import.meta.url).href)}const Ti='',Ri=` `,Bi=` -`,Lt={C:"Clubs",D:"Diamonds",H:"Hearts",S:"Spades"},Tt={A:"Ace",2:"Two",3:"Three",4:"Four",5:"Five",6:"Six",7:"Seven",8:"Eight",9:"Nine",T:"Ten",J:"Jack",Q:"Queen",K:"King"},q0=Object.keys(Lt).flatMap(e=>Object.keys(Tt).map(t=>t+e)),Di=e=>q0.includes(e)?`${Tt[e[0]]} of ${Lt[e[1]]}`:"Unknown Card";Object.keys(n0).forEach(e=>{var t=new DOMParser().parseFromString(n0[e],"image/svg+xml"),i=t.documentElement;i.removeAttribute("height"),i.removeAttribute("width"),i.removeAttribute("class");var s=t.createElementNS(i.lookupNamespaceURI(null),"title"),r=document.createTextNode(Di(e));s.appendChild(r),i.insertBefore(s,i.firstElementChild),n0[e]=new XMLSerializer().serializeToString(t.documentElement)});E.store("global",{deck:q0,cardsToSolve:Array(q0.length).fill(0),solvingInProgress:!1});E.data("navbar",()=>({svg73k:Ti.replaceAll('="16"','="24"'),biTwitter:Ri.replaceAll('="16"','="24"'),biGithub:Bi.replaceAll('="16"','="24"')}));E.data("playingCardsPreview",()=>({cardSvgs:n0,cardsBySlice(e,t){return this.$store.global.cardsToSolve.slice(e,t)},cardSvg(e){return e===0?this.cardSvgs["2B"]:this.cardSvgs[e]}}));E.data("cardsInputForm",()=>({nonAlphaNumRegEx:/[\W_]+/g,inputValue:"",validCards:[],dupedCards:[],invalidCards:[],validMessages:[],invalidMessages:[],get isFormValid(){return this.isValidCardsLengthInRange&&this.invalidMessages.length===0},get isValidCardsLengthTooSmall(){return this.validCards.length<34},get isValidCardsLengthTooBig(){return this.validCards.length>this.$store.global.deck.length},get isValidCardsLengthInRange(){return!this.isValidCardsLengthTooSmall&&!this.isValidCardsLengthTooBig},validateCardsInput(){if(this.validCards=[],this.invalidCards=[],this.dupedCards=[],this.validMessages=[],this.invalidMessages=[],(this.nonAlphaNumRegEx.test(this.inputValue)?this.inputValue.toUpperCase().replace(this.nonAlphaNumRegEx," ").split(" ").filter(t=>t):this.inputValue.toUpperCase().split(/0|(..)/g).filter(t=>t!=="").map(t=>t||"0")).forEach(t=>{t==="0"?this.validCards.push(t):this.validCards.includes(t)?this.dupedCards.push(t):this.$store.global.deck.includes(t)?this.validCards.push(t):this.invalidCards.push(t)}),this.isValidCardsLengthTooSmall?this.invalidMessages.push("Must enter at least 34 cards"):this.isValidCardsLengthTooBig&&this.invalidMessages.push(`Must not enter more than ${this.$store.global.deck.length} cards`),this.validCards.slice(this.validCards.length-34).includes("0")&&this.invalidMessages.push("Stock + bottom row (last 34 cards) must not contain unknown ('0') cards"),this.dupedCards.length>0){let t=this.dupedCards.length>1?"s":"";this.invalidMessages.push(`${this.dupedCards.length} duplicate card${t}: ${this.dupedCards.join(" ")}`)}if(this.invalidCards.length>0){let t=this.invalidCards.length>1?"s":"";this.invalidMessages.push(`${this.invalidCards.length} invalid card${t}: ${this.invalidCards.join(" ")}`)}if(this.validCards.length>0){let t=this.validCards.length>1?"s":"";this.validMessages.push(`${this.validCards.length} valid card${t}: ${this.validCards.join(" ")}`)}this.$store.global.cardsToSolve=Array(this.$store.global.deck.length-this.validCards.length).fill(0).concat(this.validCards).map(t=>t==="0"?0:t)}}));const Hi=["Hang in there!","Let go like a bird flies, not fighting the wind but gliding on it","Stay patient and trust the journey.","Everything is coming together\u2026","Solitaire is a journey, not a destination.","For things to reveal themselves to us, we need to be ready to abandon our views about them.","Patience is bitter, but its fruit is sweet.","Strive for progress, not perfection.","I wish only to be alive and to experience this living to the fullest.","This too shall pass.","Life is available only in the present moment.","Patience is the companion of wisdom.","The mountains are calling and I must go.","Give time time.","If you find a path with no obstacles, it probably doesn't lead anywhere","A smooth sea never made a good sailor.","To be upset over what you don\u2019t have is to waste what you do have.","The ultimate freedom lies in being able to wait patiently for a good thing.","If it isn't good, let it die. If it doesn't die, make it good.","A watched pot never boils without applying heat.","Stick with the winners.","I immerse myself in the experience of living without having to evaluate or understand it.","Why fit in when you were born to stand out?","Don't let yesterday take up too much of today.","The least I owe the mountains is a body.","Getting so close!","Many people think excitement is happiness. But when you are excited you are not peaceful.","Misery is optional.","Mistakes are proof that you're trying.","Life would be so much easier if we only had the source code.","A computer once beat me at chess, but it was no match for me at kickboxing.","Patience is not simply the ability to wait, it's how we behave while we're waiting.","We must let go of the life we have planned so as to accept the one that is waiting for us.","Somewhere, something incredible is waiting to be known.","If you spend your whole life waiting for the storm, you'll never enjoy the sunshine.","My actions are my only true belongings.","The way to have enough time is to never be in a hurry.","The more you know, the less you think you know.","Patience is also a form of action."];E.data("gameSolving",()=>({encouragements:Hi,encourageIndex:null,solverWorker:null,headerText:"Solution",moveCount:23,statusMessages:[],solutionMoves:[],nodesTried:0,nodesTriedFloor:0,reset(){this.$store.global.solvingInProgress=!1,this.moveCount=0,this.statusMessages=[],this.nodesTried=0,this.nodesTriedFloor=0,this.encourageIndex=null},onInit(){this.solverWorker=new Li,this.solverWorker.addEventListener("message",async e=>{if(e.data.msg==="solve-progress"){this.nodesTried++,this.moveCount=e.data.moveCount,this.statusMessages[0]=`Most moves found so far: ${this.moveCount}`;let t=Math.floor(this.nodesTried/1e4)*1e4;if(t>this.nodesTriedFloor&&(this.nodesTriedFloor=t,this.nodesTriedFloor>5e4&&(this.statusMessages[1]=`Over ${this.nodesTriedFloor.toLocaleString("en")} possibilities tried. Still working\u2026`),this.nodesTriedFloor%25e4===0)){this.encourageIndex===null&&(this.encourageIndex=Math.floor(Math.random()*this.encouragements.length)),this.statusMessages.splice(2,0,this.encouragements[this.encourageIndex]);let i=this.encourageIndex+1;this.encourageIndex=i===this.encouragements.length?0:i}}else e.data.msg==="solve-result"&&(e.data.result[0]?(this.headerText="Solution found:",this.solutionMoves=e.data.result[1],this.reset()):(this.headerText="Could not solve. Best moves found:",this.solutionMoves=e.data.result[2],this.reset()))})},async startSolver(){this.headerText="Solving\u2026",this.solutionMoves=[],this.$store.global.solvingInProgress=!0,await this.$nextTick();let e=JSON.parse(JSON.stringify(this.$store.global.cardsToSolve));this.solverWorker.postMessage({msg:"try-to-solve",game:e})}}));window.Alpine=E;E.start(); +`,Lt={C:"Clubs",D:"Diamonds",H:"Hearts",S:"Spades"},Tt={A:"Ace",2:"Two",3:"Three",4:"Four",5:"Five",6:"Six",7:"Seven",8:"Eight",9:"Nine",T:"Ten",J:"Jack",Q:"Queen",K:"King"},q0=Object.keys(Lt).flatMap(e=>Object.keys(Tt).map(t=>t+e)),Di=e=>q0.includes(e)?`${Tt[e[0]]} of ${Lt[e[1]]}`:"Unknown Card";Object.keys(n0).forEach(e=>{var t=new DOMParser().parseFromString(n0[e],"image/svg+xml"),i=t.documentElement;i.removeAttribute("height"),i.removeAttribute("width"),i.removeAttribute("class");var s=t.createElementNS(i.lookupNamespaceURI(null),"title"),r=document.createTextNode(Di(e));s.appendChild(r),i.insertBefore(s,i.firstElementChild),n0[e]=new XMLSerializer().serializeToString(t.documentElement)});E.store("global",{deck:q0,cardsToSolve:Array(q0.length).fill(0),solvingInProgress:!1});E.data("navbar",()=>({svg73k:Ti.replaceAll('="16"','="24"'),biTwitter:Ri.replaceAll('="16"','="24"'),biGithub:Bi.replaceAll('="16"','="24"')}));E.data("playingCardsPreview",()=>({cardSvgs:n0,cardsBySlice(e,t){return this.$store.global.cardsToSolve.slice(e,t)},cardSvg(e){return e===0?this.cardSvgs["2B"]:this.cardSvgs[e]}}));E.data("cardsInputForm",()=>({nonAlphaNumRegEx:/[\W_]+/g,inputValue:"",validCards:[],dupedCards:[],invalidCards:[],validMessages:[],invalidMessages:[],get isFormValid(){return this.isValidCardsLengthInRange&&this.invalidMessages.length===0},get isValidCardsLengthTooSmall(){return this.validCards.length<34},get isValidCardsLengthTooBig(){return this.validCards.length>this.$store.global.deck.length},get isValidCardsLengthInRange(){return!this.isValidCardsLengthTooSmall&&!this.isValidCardsLengthTooBig},validateCardsInput(){if(this.validCards=[],this.invalidCards=[],this.dupedCards=[],this.validMessages=[],this.invalidMessages=[],(this.nonAlphaNumRegEx.test(this.inputValue)?this.inputValue.toUpperCase().replace(this.nonAlphaNumRegEx," ").split(" ").filter(t=>t):this.inputValue.toUpperCase().split(/0|(..)/g).filter(t=>t!=="").map(t=>t||"0")).forEach(t=>{t==="0"?this.validCards.push(t):this.validCards.includes(t)?this.dupedCards.push(t):this.$store.global.deck.includes(t)?this.validCards.push(t):this.invalidCards.push(t)}),this.isValidCardsLengthTooSmall?this.invalidMessages.push("Must enter at least 34 cards"):this.isValidCardsLengthTooBig&&this.invalidMessages.push(`Must not enter more than ${this.$store.global.deck.length} cards`),this.validCards.slice(this.validCards.length-34).includes("0")&&this.invalidMessages.push("Stock + bottom row (last 34 cards) must not contain unknown ('0') cards"),this.dupedCards.length>0){let t=this.dupedCards.length>1?"s":"";this.invalidMessages.push(`${this.dupedCards.length} duplicate card${t}: ${this.dupedCards.join(" ")}`)}if(this.invalidCards.length>0){let t=this.invalidCards.length>1?"s":"";this.invalidMessages.push(`${this.invalidCards.length} invalid card${t}: ${this.invalidCards.join(" ")}`)}if(this.validCards.length>0){let t=this.validCards.length>1?"s":"";this.validMessages.push(`${this.validCards.length} valid card${t}: ${this.validCards.join(" ")}`)}this.$store.global.cardsToSolve=Array(this.$store.global.deck.length-this.validCards.length).fill(0).concat(this.validCards).map(t=>t==="0"?0:t)}}));const Hi=["Hang in there!","Let go like a bird flies, not fighting the wind but gliding on it","Stay patient and trust the journey.","Everything is coming together\u2026","Solitaire is a journey, not a destination.","For things to reveal themselves to us, we need to be ready to abandon our views about them.","Patience is bitter, but its fruit is sweet.","Strive for progress, not perfection.","I wish only to be alive and to experience this living to the fullest.","This too shall pass.","Life is available only in the present moment.","Patience is the companion of wisdom.","The mountains are calling and I must go.","Give time time.","If you find a path with no obstacles, it probably doesn't lead anywhere","A smooth sea never made a good sailor.","To be upset over what you don\u2019t have is to waste what you do have.","The ultimate freedom lies in being able to wait patiently for a good thing.","If it isn't good, let it die. If it doesn't die, make it good.","A watched pot never boils without applying heat.","Stick with the winners.","I immerse myself in the experience of living without having to evaluate or understand it.","Why fit in when you were born to stand out?","Don't let yesterday take up too much of today.","The least I owe the mountains is a body.","Getting so close!","Many people think excitement is happiness. But when you are excited you are not peaceful.","Misery is optional.","Mistakes are proof that you're trying.","Life would be so much easier if we only had the source code.","A computer once beat me at chess, but it was no match for me at kickboxing.","Patience is not simply the ability to wait, it's how we behave while we're waiting.","We must let go of the life we have planned so as to accept the one that is waiting for us.","Somewhere, something incredible is waiting to be known.","If you spend your whole life waiting for the storm, you'll never enjoy the sunshine.","My actions are my only true belongings.","The way to have enough time is to never be in a hurry.","The more you know, the less you think you know.","Patience is also a form of action."];E.data("gameSolving",()=>({encouragements:Hi,encourageIndex:null,solverWorker:null,headerText:"Solution",moveCount:23,statusMessages:[],solutionMoves:[],nodesTried:0,nodesTriedFloor:0,reset(){this.$store.global.solvingInProgress=!1,this.moveCount=0,this.statusMessages=[],this.nodesTried=0,this.nodesTriedFloor=0,this.encourageIndex=null},onInit(){this.solverWorker=new Li,this.solverWorker.addEventListener("message",async e=>{if(e.data.msg==="solve-progress"){this.nodesTried++,this.moveCount=e.data.moveCount,this.statusMessages[0]=`${this.moveCount} card-clearing moves found so far.`;let t=Math.floor(this.nodesTried/1e4)*1e4;if(t>this.nodesTriedFloor&&(this.nodesTriedFloor=t,this.nodesTriedFloor>5e4&&(this.statusMessages[1]=`Over ${this.nodesTriedFloor.toLocaleString("en")} possibilities tried. Still working\u2026`),this.nodesTriedFloor%25e4===0)){this.encourageIndex===null&&(this.encourageIndex=Math.floor(Math.random()*this.encouragements.length)),this.statusMessages.splice(2,0,this.encouragements[this.encourageIndex]);let i=this.encourageIndex+1;this.encourageIndex=i===this.encouragements.length?0:i}}else e.data.msg==="solve-result"&&(e.data.result[0]?(this.headerText="Solution found:",this.solutionMoves=e.data.result[1],this.reset()):(this.headerText="Could not solve. Best moves found:",this.solutionMoves=e.data.result[2],this.reset()))})},async startSolver(){this.headerText="Solving\u2026",this.solutionMoves=[],this.$store.global.solvingInProgress=!0,await this.$nextTick();let e=JSON.parse(JSON.stringify(this.$store.global.cardsToSolve));this.solverWorker.postMessage({msg:"try-to-solve",game:e})}}));window.Alpine=E;E.start(); diff --git a/dist/assets/solverWorker.25a6ccd7.js b/dist/assets/solverWorker.25a6ccd7.js deleted file mode 100644 index f101f46..0000000 --- a/dist/assets/solverWorker.25a6ccd7.js +++ /dev/null @@ -1 +0,0 @@ -(function(){"use strict";class O{constructor(t){this.rank=t[0],this.suit=t[1]}get integerValue(){return"A23456789TJQK".indexOf(this.rank)}isSequential(t){return(this.integerValue+13+1)%13===t.integerValue||(this.integerValue+13-1)%13===t.integerValue}get toString(){return this.rank+this.suit}}class v{constructor(t){this.array=t}get isCleared(){return this.array.every(t=>t===0)}get freeCardIndices(){let t=[];for(let e=this.array.length-1;e>=0;e--){if(this.array[e]===0)continue;const n=Math.floor((e-3)/2);(e>=18||e<=17&&e>=9&&this.array[e+9]===0&&this.array[e+10]===0||e<=8&&e>=3&&this.array[e+6+n]===0&&this.array[e+7+n]===0||e<=2&&e>=0&&this.array[e+3+e]===0&&this.array[e+4+e]===0)&&t.push(e)}return t}}class o{static gameWon(){return"You have won."}static gameLost(){return"There are no more valid moves."}static match(t){return"Move "+t+" onto the stock."}static flipStock(){return"Draw a new stock card."}}const l=Object.freeze({won:!0,lost:!1});function g(r,t){let e=r.filter(a=>a.startsWith("Move")).length;return t.filter(a=>a.startsWith("Move")).length>e?t:r}async function h(r,t,e=null,n=0,a=[],d=[]){let i=JSON.parse(JSON.stringify(a)),s=JSON.parse(JSON.stringify(d)),J=new v(r);if(s=g(s,i),s=JSON.parse(JSON.stringify(s)),e&&e.postMessage({msg:"solve-progress",moveCount:s.length}),J.isCleared)return i.push(o.gameWon()),[l.won,i,[]];if(n>=t.length)return i.push(o.gameLost()),[l.lost,i,s];const m=new O(t[n]);let f=J.freeCardIndices;for(let u=0;u{let t=await h(r.slice(0,28),r.slice(28,52),self);postMessage({msg:"solve-result",result:t})};addEventListener("message",async r=>{r.data.msg==="try-to-solve"&&w(r.data.game)})})(); diff --git a/dist/assets/solverWorker.737bce24.js b/dist/assets/solverWorker.737bce24.js new file mode 100644 index 0000000..fadb150 --- /dev/null +++ b/dist/assets/solverWorker.737bce24.js @@ -0,0 +1 @@ +(function(){"use strict";class O{constructor(t){this.rank=t[0],this.suit=t[1]}get integerValue(){return"A23456789TJQK".indexOf(this.rank)}isSequential(t){return(this.integerValue+13+1)%13===t.integerValue||(this.integerValue+13-1)%13===t.integerValue}get toString(){return this.rank+this.suit}}class y{constructor(t){this.array=t}get isCleared(){return this.array.every(t=>t===0)}get freeCardIndices(){let t=[];for(let e=this.array.length-1;e>=0;e--){if(this.array[e]===0)continue;const n=Math.floor((e-3)/2);(e>=18||e<=17&&e>=9&&this.array[e+9]===0&&this.array[e+10]===0||e<=8&&e>=3&&this.array[e+6+n]===0&&this.array[e+7+n]===0||e<=2&&e>=0&&this.array[e+3+e]===0&&this.array[e+4+e]===0)&&t.push(e)}return t}}class u{static gameWon(){return"You have won."}static gameLost(){return"There are no more valid moves."}static match(t){return"Move "+t+" onto the stock."}static flipStock(){return"Draw a new stock card."}}const o=Object.freeze({won:!0,lost:!1});function h(r,t){let e=r.filter(a=>a.startsWith("Move")).length;return t.filter(a=>a.startsWith("Move")).length>e?t:r}async function f(r,t,e=null,n=0,a=[],d=[]){let i=JSON.parse(JSON.stringify(a)),s=JSON.parse(JSON.stringify(d)),J=new y(r);if(s=h(s,i),s=JSON.parse(JSON.stringify(s)),e&&e.postMessage({msg:"solve-progress",moveCount:s.filter(l=>l.startsWith("Move")).length}),J.isCleared)return i.push(u.gameWon()),[o.won,i,[]];if(n>=t.length)return i.push(u.gameLost()),[o.lost,i,s];const M=new O(t[n]);let g=J.freeCardIndices;for(let l=0;l{let t=await f(r.slice(0,28),r.slice(28,52),self);postMessage({msg:"solve-result",result:t})};addEventListener("message",async r=>{r.data.msg==="try-to-solve"&&w(r.data.game)})})(); diff --git a/dist/index.html b/dist/index.html index bac9900..a1c4504 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1 +1 @@ -Tripeaks Solver 73k

Enter cards representing a Tripeaks game below. Enter each card as 2 characters representing the rank (A, 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K) and suit (C, D, H, S). For example, "TH" is the Ten of Hearts.

You don't have to know all the cards, this solver will give you as many moves as it can. Enter a "0" (a single zero) for unknown cards. You don't need to enter unknown cards before the first card you know. (However, the last 34 cards (base of peaks, stock) must be known.)

Entry is case-insensitive, and you can separate cards with any character (space, comma, etc), or use no separator.

Valid examples

These will complete quickly:

  • 7S 5D 7C 2D 0 0 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
  • 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
  • 7c03s0qsjc00JSasTSadtcqd9s4s2h9h8sjh6c3dks5s5c6h9C2Cac8C6d5DTH8dkckd9d4c5h8hqh6s

This example will take several minutes, but will provide a solution, and should demonstrate that the page stays responsive and provides feedback on the solving progress:

  • 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

Enter Your Cards

Game Row 1, Top of PeaksGame Row 2, Second RowGame Row 3, Third RowGame Row 4, Base of PeaksGame Stock, the Draw Cards

Enter cards and click Solve to get a solution.

\ No newline at end of file +Tripeaks Solver 73k

Enter cards representing a Tripeaks game below. Enter each card as 2 characters representing the rank (A, 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K) and suit (C, D, H, S). For example, "TH" is the Ten of Hearts.

You don't have to know all the cards, this solver will give you as many moves as it can. Enter a "0" (a single zero) for unknown cards. You don't need to enter unknown cards before the first card you know. (However, the last 34 cards (base of peaks, stock) must be known.)

Entry is case-insensitive, and you can separate cards with any character (space, comma, etc), or use no separator.

Valid examples

These will complete quickly:

  • 7S 5D 7C 2D 0 0 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
  • 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
  • 7c03s0qsjc00JSasTSadtcqd9s4s2h9h8sjh6c3dks5s5c6h9C2Cac8C6d5DTH8dkckd9d4c5h8hqh6s

This example will take several minutes, but will provide a solution, and should demonstrate that the page stays responsive and provides feedback on the solving progress:

  • 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

Enter Your Cards

Game Row 1, Top of PeaksGame Row 2, Second RowGame Row 3, Third RowGame Row 4, Base of PeaksGame Stock, the Draw Cards

Enter cards and click Solve to get a solution.

\ No newline at end of file diff --git a/package.json b/package.json index 905dbd4..cde2504 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tripeaks-solitaire-solver-js-73k", - "version": "1.0.2", + "version": "1.0.3", "description": "A brute force solver for tri peaks solitaire written in javascript. Forked from work by Courtney Pitcher at https://github.com/IgniparousTempest/javascript-tri-peaks-solitaire-solver", "keywords": [ "tripeaks", diff --git a/solver.js b/solver.js index dfc313a..e3e553b 100644 --- a/solver.js +++ b/solver.js @@ -127,7 +127,7 @@ async function solve( if (worker) { worker.postMessage({ msg: "solve-progress", - moveCount: newBestMoveArray.length, + moveCount: newBestMoveArray.filter((s) => s.startsWith("Move")).length, }); } diff --git a/src/js/main.js b/src/js/main.js index 8c47ab9..d362bf8 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -266,7 +266,7 @@ Alpine.data("gameSolving", () => ({ if (e.data.msg === "solve-progress") { this.nodesTried++; this.moveCount = e.data.moveCount; - this.statusMessages[0] = `Most moves found so far: ${this.moveCount}`; + this.statusMessages[0] = `${this.moveCount} card-clearing moves found so far.`; let newFloor = Math.floor(this.nodesTried / 10000) * 10000; if (newFloor > this.nodesTriedFloor) {