tripeaks-solitaire-solver-j.../main.js

181 lines
5.3 KiB
JavaScript

import "./style.scss";
import "./style-cards.css";
import Alpine from "alpinejs";
// import 'bootstrap/dist/js/bootstrap'
Alpine.store('global', {
cardsToSolve: Array(52).fill(0)
})
Alpine.data("playingCardsPreview", () => ({
rankText: {
'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'
},
suitText: {
'C': 'Clubs',
'D': 'Diamonds',
'H': 'Hearts',
'S': 'Spades'
},
rankSlug(rank) {
return `rank-${rank === 'T' ? '10' : rank}`
},
suitSlug: {
'C': 'clubs',
'D': 'diams',
'H': 'hearts',
'S': 'spades'
},
cardHtml(card, index) {
if (card === '0' || card === 0) {
return `<abbr title="Unknown" class="card" style="z-index:${this.stockCard(index)};"></abbr>`
} else {
return `<abbr title="${this.rankText[card[0]]} of ${this.suitText[card[1]]}" class="card ${this.rankSlug(card[0])} ${this.suitSlug[card[1]]}" style="z-index:${this.stockCard(index)};"><abbr class="rank" aria-hidden="true">${card[0]}</abbr><abbr class="suit" aria-hidden="true">&${this.suitSlug[card[1]]};</abbr><abbr class="suit-b" aria-hidden="true">&${this.suitSlug[card[1]]};</abbr><abbr class="rank-b" aria-hidden="true">${card[0]}</abbr></abbr>`
}
},
stockCard(index) {
return 500 - (10 * index)
}
}));
Alpine.data("cardsInputForm", () => ({
// "constants" for validation etc
nonAlphaNumRegEx: /[\W_]+/g,
suits: [],
ranks: [],
deck: [],
minCards: 34,
stockCount: 24,
peaksCount: 28,
onInit() {
this.suits = "CDHS".split("");
this.ranks = "A23456789TJQK".split("");
this.deck = this.suits.flatMap((suit) => {
return this.ranks.map((cval) => {
return cval + suit;
});
});
console.log(this.deck.join(", "));
console.log(`deck size: ${this.deck.length}`);
},
// input validation
inputValue: "",
validCards: [],
dupedCards: [],
invalidCards: [],
validMessages: [],
invalidMessages: [],
cardsToSolve: [],
get isFormValid() {
return this.isValidCardsLengthInRange && this.invalidMessages.length === 0;
},
get isValidCardsLengthTooSmall() {
return this.validCards.length < this.minCards;
},
get isValidCardsLengthTooBig() {
return this.validCards.length > this.deck.length;
},
get isValidCardsLengthInRange() {
return !this.isValidCardsLengthTooSmall && !this.isValidCardsLengthTooBig;
},
validateCardsInput() {
// reset arrays and parse the input
this.validCards = [];
this.invalidCards = [];
this.dupedCards = [];
this.validMessages = [];
this.invalidMessages = [];
// handle if input has alphanum chars - treat them as delimeters
// if no alphanum chars, split by 2 chars except for 0
let userCards = this.nonAlphaNumRegEx.test(this.inputValue)
? this.inputValue
.toUpperCase()
.replace(this.nonAlphaNumRegEx,' ')
.split(' ')
.filter((c) => c)
: this.inputValue
.toUpperCase()
.split(/0|(..)/g)
.filter(c => c !== '')
.map(c => !c ? '0' : c);
// check the input
userCards.forEach((card) => {
if (card === "0") {
// user marking a slot with an unknown card
this.validCards.push(card);
} else if (this.validCards.includes(card)) {
// this card was already seen in user's input, now it's a duplicate
this.dupedCards.push(card);
} else if (this.deck.includes(card)) {
// not a duplicate, and in the reference deck? Valid, add to valid cards
this.validCards.push(card);
} else {
// not a dupe, but not in reference deck: invalid, add to invalid cards
this.invalidCards.push(card);
}
});
// set validation messages based on length
if (this.isValidCardsLengthTooSmall) {
this.invalidMessages.push(`Must enter at least ${this.minCards} cards`);
} else if (this.isValidCardsLengthTooBig) {
this.invalidMessages.push(
`Must not enter more than ${this.deck.length} cards`
);
}
if (this.validCards.slice(this.validCards.length - 34).includes("0")) {
this.invalidMessages.push(
`Stock + bottom row (last 34 cards) must not contain unknown ('0') cards`
);
}
// set other validation messages
if (this.dupedCards.length > 0) {
let s = this.dupedCards.length > 1 ? "s" : "";
this.invalidMessages.push(
`${this.dupedCards.length} duplicate card${s}: ${this.dupedCards.join(
" "
)}`
);
}
if (this.invalidCards.length > 0) {
let s = this.invalidCards.length > 1 ? "s" : "";
this.invalidMessages.push(
`${this.invalidCards.length} invalid card${s}: ${this.invalidCards.join(
" "
)}`
);
}
if (this.validCards.length > 0) {
let s = this.validCards.length > 1 ? "s" : "";
this.validMessages.push(
`${this.validCards.length} valid card${s}: ${this.validCards.join(" ")}`
);
}
// set the game cards to try solving, based on current input
this.$store.global.cardsToSolve = Array(this.deck.length - this.validCards.length)
.fill(0)
.concat(this.validCards)
.map((c) => (c === "0" ? 0 : c));
},
}));
window.Alpine = Alpine;
Alpine.start();