游戏规则:
这副牌包含 54*2 = 108 张卡片
。
注意:游戏中有两种类型的 clown 。
- 普通 clown
- 动态生成的 clown ,可以是任何牌值。
提交卡片时,正确提交将被视为
- 共有 4 组,总共 13 张牌(已处理)
- 只有 1 组可以包含 4 张卡片。休息,每人 3 张牌(已处理)
1 个组必须具有
纯序列
。示例:Ace、2、3 或 J、Q、K、Ace 或 3、4、5(相同花色)
另一个组必须有一个序列。它可以是
纯的或不纯的
。示例(不纯):Ace,2,Joker,4 或 5,6,Joker,8
- 其余 2 组可以包含序列
(纯或不纯)
,或者可以包含不同花色的相同值(value)牌(有或没有 clown )
。
示例:2(黑桃)、2(梅花)、 clown 、2(红桃)或 3(梅花)、3(红桃)、3(黑桃)
这是迄今为止已经做出的尝试。
var joker = 3; // dynamic joker card value
function getSummary(cards){
const isJoker = c => c.value===joker || c.suit ==="joker";
const getSortVal = c=> isJoker(c) ? 100 : c.value;
cards.sort((c1,c2)=> getSortVal(c1)-getSortVal(c2)); //sort cards by their value
let jokerCount = 0,jokersUsed =0, res;
for(let i = cards.length -1; i >= 0 ; i--) //start from end to handle jokers first (note this is assuming they will also have the larger value of 20)
{
if(isJoker(cards[i])){
jokerCount++; //handle jokers separately
// console.log("used joker");
} else {
let {suit,value:val} = cards[i]; //destructure suit and value properties into variables
if(res===undefined){ //first non joker card -> init values
res = {uniqueSuit: suit, startOfSequence: val};
if(jokerCount) res.jokersUsed =true;
}
else {
if(suit !== res.uniqueSuit) //check if there are more suits
delete res.uniqueSuit; //no unique suit -> remove the property (alternative: set the prop to 'none')
if(res.startOfSequence && --res.startOfSequence != val){ //check if the sequence is intact
if(val === 1 && i === 0 && res.startOfSequence ===10) //Ace
res.startOfSequence++; //Ace is used as 14
else {
let gap = res.startOfSequence - val;
if(gap > 0 &&jokerCount >= gap){ //if enough jokers remaining, use them (sequence still intact)
jokerCount-=gap;
jokersUsed+=gap;
res.startOfSequence=val;
}
else
delete res.startOfSequence; //no sequence -> remove property from res
}
}
}
}
}
if(res === undefined){
//only jokers (is this possible?) -> create sequence or matching values
res={};
//loop through suits or do what's needed to create best score
return res;
}
if(res.startOfSequence) //Sequence found => all cards handled => return result
return res;
if(jokersUsed) //jokers were used for sequence, but sequence was not complete
jokerCount += jokersUsed; //reclaim jokers
const addSameValue = (suit,val)=>{ //helper function to add cards of same value to collection
if(!res.sameValues)res.sameValues = {};
res.sameValues[val] = (res.sameValues[val] | 1) +1; //offset always 1 because adding is done from prev. value
};
//search for same values
let prev, cnt =cards.length - jokerCount;
for(let i=0 ; i < cnt ; i++){
let val = cards[i].value;
if(prev == val)
addSameValue(cards[i].suit,val);
else
prev = val;
}
if(jokerCount){
//use for highest value or add to existing sequences?
//for example, add to highest value: (might want to check for unused suits)
addSameValue('joker', cards[cards.length-jokerCount].value);
}
return JSON.stringify(res);
}
var arr4 = [{"value":2,"suit":"hearts"},{"value":5,"suit":"hearts"},{"value":3,"suit":"hearts"},{"value":4,"suit":"hearts"}];
var arr5 = [{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":3,"suit":"diams"},{"value":5,"suit":"spades"}];
var arr6 = [{"value":1,"suit":"hearts"},{"value":2,"suit":"hearts"},{"value":4,"suit":"hearts"},{"value":3,"suit":"hearts"}];
var arr7 = [{"value":4,"suit":"diams"},{"value":4,"suit":"hearts"},{"value":4,"suit":"hearts"},{"value":20,"suit":"joker"}];
for(let arr of [arr4,arr5,arr6,arr7])
console.log(getSummary(arr)); //test output
它根据卡组的排列方式返回对象并添加属性。
正确的分组是
纯序列(3或4张牌) - 纯序列或不纯序列(3或4张牌) - 纯序列或不纯序列或相同值卡(3或4张牌) - 纯序列或不纯序列或相同储值卡(3 或 4 张卡)
不一定要按这个顺序。只需寻找他们的存在即可。
纯序列不能包含任何类型的 clown 。
但是,上面的代码几乎没有问题。
对于序列卡 - 示例:[2(黑桃),3(黑桃),4(黑桃)]
- 对于
arr4
,它表示jokersUsed: true
将3(动态设置为joker)视为joker,即使数组已经是纯序列。稍后在识别哪个是纯序列或不纯序列
时会产生问题。如果 3 有不同的花色或者不是序列的一部分,则 3 可以被视为 clown 。
因此,对于像 [ 2(黑桃), 5(黑桃), 3 (黑桃), 4(黑桃) ]
这样的牌,即使 3 是一个,它也应该始终被视为纯序列 clown 动态生成。这里将 3 视为 clown 并添加 jokerUsed
属性。
如果它是 [ 2(黑桃), 5(黑桃), 3 (梅花), 4(黑桃)]
或 [ 7(黑桃),它可能会被认为是 clown , 8(黑桃),3(黑桃或梅花或其他),10(黑桃)]
对于相同值(value)的牌 - 示例:[2(黑桃),2(梅花),2(红心)]
在代码中,它只寻找相同值(value)的牌,无论它们的花色如何。这意味着,所有的牌都应该是不同花色的。
对于相同值(value)的卡片搜索,如果有 3 张相同值(value)的卡片,则计数将变为 4(而不是 3),而对于 4 张相同值(value)的卡片,计数将变为 6(而不是 4)。因此,计数应等于同值卡的数量。
此处不考虑 clown (正常和动态)。 [
2(黑桃)、2(梅花)、 clown (静态或动态)、2(直径)
]。我们可以将 clown 视为2(hearts)
,但这并没有发生。
如何在我的代码中实现上述 4 个条件?希望我说清楚了,否则我会再次解释。
这是一个fiddle如果你想从事..
最佳答案
好的,here's what I have 。它可能并不完全完整(多个组的聚合不在这里),但它使大量检查到位,并且可能为您提供更好的结构想法。它还期望没有多余的卡片:不要为 3 张卡片组提交 4 张卡片。
主要涉及将规则分解为他们想要的特定结构,为每个结构构建功能。然后我们将其包装在规则聚合函数 getSummary()
中。
// Ace spades: {"value":1, suit:"spades"}
// King diamonds: {"value":12, suit:"diams"}
// Joker: {"suit":"joker"}
// In addition to the regular jokers, cards with a certain value can also behave as jokers.
// Purity of the group is only removed if a card in the group was used as a joker
var jokerValue;
// check that values match and suits are unique
function isSameValue(cards){
var suits = ["clubs","hearts","spades","diams"];
var jokers = [];
var remainder = [];
cards.forEach(function(card){
(card.suit === "joker" ? jokers : remainder).push(card);
});
var pure = jokers.length === 0;
var value;
var matched = remainder.every(function(card){
if(value) {
if(value != card.value) {
return false;
}
var suit = suits.indexOf(card.suit);
if(suit < 0) {
return false;
}
suits.splice(suit,1);
return true;
}
value = card.value;
return true;
});
// if the non-wildcards matched, just assume any wildcards are also matches,
// otherwise, pull the fake jokers and try again
if(matched) {
return {isPure: pure, isSameValue: matched};
}
// move the fake jokers to the joker pile
remainder = remainder.filter(function(card){
if(card.value == jokerValue) {
jokers.push(card);
return false;
}
return true;
});
// reset
suits = ["clubs","hearts","spades","diams"];
pure = jokers.length === 0;
value = undefined;
matched = remainder.every(function(card){
if(value) {
if(value != card.value) {
return false;
}
var suit = suits.indexOf(card.suit);
if(suit < 0) {
return false;
}
suits.splice(suit,1);
return true;
}
value = card.value;
return true;
});
return {isPure: pure, isSameValue: matched};
}
// check that suits match; values are unchecked
function isSameSuit(cards){
var jokers = [];
var remainder = [];
cards.forEach(function(card){
(card.suit === "joker" ? jokers : remainder).push(card);
});
var pure = jokers.length === 0;
var suit;
var sameSuit = remainder.every(function(card){
if(!suit){
suit = card.suit;
return true;
}
return card.suit == suit;
});
if(sameSuit) {
return {isPure: pure, isSameSuit: sameSuit};
}
// pull the fake jokers and try again
remainder = remainder.filter(function(card){
if(card.value == jokerValue) {
jokers.push(card);
return false;
}
});
pure = jokers.length === 0;
suit = undefined;
sameSuit = remainder.every(function(card){
if(!suit){
suit = card.suit;
return true;
}
return card.suit == suit;
});
return {isPure: pure, isSameSuit: sameSuit};
}
// check for sequence; suits must match
function isSequence(cards){
var sameSuit = isSameSuit(cards);
if(!sameSuit.isSameSuit) {
return false;
}
var jokers = [];
var sequence = cards.filter(function(card){
if(card.suit === "joker") {
jokers.push(card);
return false;
}
return true;
});
var pure = jokers.length === 0;
// Sort the non-jokers
sequence = sequence.sort(function(a, b){
return a.value - b.value;
});
// skip this step is isSameSuit() reported !isPure because we know we had to
// use jokers so we can assume fake jokers are okay to use
if(pure && sameSuit.isPure){
// find a sequence
// rotate through each card to start and count through them, filling in with available jokers as necessary
for(var i = 0; i < sequence.length; i++){
var jokerCount = jokers.length;
var lastValue = sequence[0].value;
var fail = false;
for(var j = 1; j < sequence.length; j++){
if(lastValue + 1 == sequence[j].value) {
++lastValue;
continue;
}
if(lastValue == 12 && sequence[j].value == 1) {
lastValue = 1;
continue;
}
if(jokerCount > 0) {
jokerCount--;
j--;
lastValue++;
if(lastValue > 12) {
lastValue = 1;
}
continue;
}
fail = true;
break;
}
// Did we make it through a complete sequence?
if(!fail){
return {isPure: pure, isSequence: !fail };
}
// move bottom card to top and try again
sequence.unshift(sequence.pop());
}
}
var sequence = sequence.filter(function(card){
if(card.value == jokerValue) {
jokers.push(card);
return false;
}
return true;
});
pure = jokers.length === 0;
// already sorted from earlier; try again
for(var i = 0; i < sequence.length; i++){
var jokerCount = jokers.length;
var lastValue = sequence[0].value;
var fail = false;
for(var j = 1; j < sequence.length; j++){
if(lastValue + 1 == sequence[j].value) {
++lastValue;
continue;
}
if(lastValue == 12 && sequence[j].value == 1) {
lastValue = 1;
continue;
}
if(jokerCount > 0) {
jokerCount--;
j--;
lastValue++;
if(lastValue > 12) {
lastValue = 1;
}
continue;
}
fail = true;
break;
}
if(!fail) {
return {isPure: pure, isSequence: !fail};
}
}
return {isPure: undefined, isSequence: false};
}
function getSummary(cards){
if(cards.length != 3 && cards.length != 4) {
// invalid number of cards, return undefined
return;
}
var long = cards.length == 4;
var sameValue = isSameValue(cards);
var sequence = isSequence(cards);
var pure = (sameValue.isSameValue && sameValue.isPure) || (sequence.isSequence && sequence.isPure);
return JSON.stringify({
"isLong": long,
"isPure": pure,
"isSameValue": sameValue.isSameValue,
"isSequence": sequence.isSequence
});
}
function toString(cards) {
var results = [];
cards.forEach(function(card){
if(card.suit === "joker") {
results.push("JK");
}
else {
var value;
switch (card.value) {
case 1: value = "A"; break;
case 10: value = "J"; break;
case 11: value = "Q"; break;
case 12: value = "K"; break;
default:
value = card.value;
break;
}
results.push(value+card.suit.charAt(0));
}
});
return results.join(' ');
}
jokerValue = 3;
for(var arr of [
[{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":5,"suit":"clubs"},{"value":5,"suit":"spades"}],
[{"value":2,"suit":"hearts"},{"suit":"joker"},{"value":3,"suit":"hearts"},{"value":4,"suit":"hearts"}],
[{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":3,"suit":"diams"},{"value":5,"suit":"spades"}],
[{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":5,"suit":"spades"}],
[{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":10,"suit":"spades"}],
[{"value":1,"suit":"hearts"},{"value":3,"suit":"diams"},{"value":2,"suit":"hearts"}],
[{"value":1,"suit":"hearts"},{"value":3,"suit":"hearts"},{"value":3,"suit":"diams"}]
]) {
console.log(toString(arr) + " " + getSummary(arr)); //test output
}
关于javascript - 卡牌游戏的数组对象过滤和不同序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40958221/