Last active
August 29, 2015 13:57
-
-
Save finscn/9744730 to your computer and use it in GitHub Desktop.
检测 两组任意(不限个数 不限花色) 的扑克牌, 混到一起后能否构成任意长度(大于1 小于15)的顺子.A代表1或14,小王代表1--5,大王代表1--14
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
检测 两组任意(不限个数 不限花色) 的扑克牌, 混到一起后能否构成任意长度(大于1 小于15)的顺子. | |
A可表示1或14,小王可表示1--5,大王可表示1--14 | |
说明: | |
1 我微博里说 小王代表 1到9有误, 我这边实际遇到的场景是 小王代表 1--5 (当然 这个无所谓) | |
2 牌是可以有重复的 : 例如 可以 4个小王 9个大王 等等, 可以理解为是从无数副扑克牌当中随意抽取出两组 | |
3 组成的顺子 可以不是5张 , 其实严格说 就是 等差为1的等差数列 | |
4 能且只能组成一组顺子, 组成顺子后, 牌没有剩余 | |
*/ | |
// cards 结构: [ {point:牌面点数, num:对应数值}, .... ] | |
function checkSequence(cards1, cards2) { | |
var totalCount = cards1.length + cards2.length; | |
//总牌数>14, 必然无法构成等差数列 | |
if (totalCount > 14) { | |
return false; | |
} | |
var allCards = []; // 普通数字牌对应数组 | |
var countA = 0; // A数量 | |
var countRedJoker = 0; // 大王数量 | |
var countBlackJoker = 0; // 小王数量 | |
var _cards = cards1; | |
while (true) { | |
_cards.forEach(function(card) { | |
// 记录 A 大王 小王的个数 | |
if (card.point == "A") { | |
countA++; | |
} else if (card.point == "RED_JOKER") { | |
countRedJoker++; | |
} else if (card.point == "BLACK_JOKER") { | |
countBlackJoker++; | |
} else { | |
// 把普通数字牌混为一组 | |
allCards.push(card); | |
} | |
}); | |
if (_cards == cards2) { | |
break; | |
} | |
_cards = cards2; | |
} | |
// A大于2个 或者 虽然A等于2个,但总牌数小于14, 则必然无法构成等差数列 | |
if (countA > 2 || countA == 2 && totalCount < 14) { | |
return false | |
} | |
// 对普通数字牌排序 | |
allCards.sort(function(a, b) { | |
return a.num - b.num; | |
}); | |
var ANA, AN, NA; | |
if (countA == 2) { | |
//如果有两个A, 那么一个A当做1 放到最前面, 另一个A当做14, 放到后面 | |
ANA = [{ | |
point: "A", | |
num: 1 | |
}].concat(allCards).concat([{ | |
point: "A", | |
num: 14 | |
}]); | |
} else if (countA == 1) { | |
// 只有一个A 时, 把A放前面测一次, 放后面再测一次, 这样做代码上简单, 但是性能肯定不好 | |
AN = [{ | |
point: "A", | |
num: 1 | |
}].concat(allCards); | |
NA = [].concat(allCards).concat({ | |
point: "A", | |
num: 14 | |
}); | |
} | |
if (ANA) { | |
return _checkQueue(ANA, countRedJoker, countBlackJoker); | |
} else if (AN) { | |
return _checkQueue(AN, countRedJoker, countBlackJoker) || _checkQueue(NA, countRedJoker, countBlackJoker); | |
} else { | |
return _checkQueue(allCards, countRedJoker, countBlackJoker); | |
} | |
} | |
function _checkQueue(cardList, countRedJoker, countBlackJoker) { | |
console.log(cardList) | |
console.log(countRedJoker) | |
console.log(countBlackJoker) | |
// 小王代表的最大数 | |
var blackJokerMax = 5; | |
var prevNum = cardList[0].num; | |
for (var i = 1; i < cardList.length; ) { | |
var currentNum = cardList[i].num; | |
if (prevNum === currentNum) { | |
// 有重复的牌, 不是等差数列 | |
return false; | |
} | |
var useJoker = false | |
// 如果两张相邻牌的差不是1, 尝试用王补位 | |
if (prevNum + 1 != currentNum) { | |
//blackJokerMax之后的, 用大王补位 | |
if (prevNum + 1 > blackJokerMax) { | |
if (countRedJoker > 0) { | |
countRedJoker--; | |
useJoker = true; | |
} else { | |
return false; | |
} | |
} else { | |
//blackJokerMax或之前的, 有小王, 优先用小王补位 | |
if (countBlackJoker > 0) { | |
countBlackJoker--; | |
useJoker = true; | |
} else if (countRedJoker > 0) { | |
//blackJokerMax或之前的, 没有小王 尝试用大王补位 | |
countRedJoker--; | |
useJoker = true; | |
} else { | |
// 没有王, 则无法构成等差数列 | |
return false; | |
} | |
} | |
} | |
if (useJoker) { | |
//如果用王补过位, 则做相应的处理 | |
prevNum += 1; | |
} else { | |
prevNum = currentNum; | |
i++; | |
} | |
} | |
var firstNum = cardList[0].num; | |
var lastNum = cardList[cardList.length - 1].num; | |
// 此时队列中间部分已经排列好, 剩余的小王只能往前分配, 大王可能往前 可能往后 | |
// 剩余小王数大于队列前端能分配的最大数量, 则不是等差数列 | |
if (countBlackJoker >= firstNum) { | |
return false | |
} | |
// 如果有未分配的小王 | |
if (countBlackJoker > 0) { | |
// 如果此时数列最小值>blackJokerMax+1, 则小王不能直接分配到数列前面,需要先用若干个大王来补位 | |
if (firstNum > blackJokerMax + 1) { | |
//有大王 用大王补位,否则返回false | |
if (countRedJoker >= firstNum - (blackJokerMax + 1)) { | |
countRedJoker -= firstNum - (blackJokerMax + 1); | |
firstNum = blackJokerMax + 1; | |
} else { | |
return false; | |
} | |
} | |
// 分配所有剩余的小王 因为前面的一些预判断, 下面两行代码总是能得到预期结果的 | |
firstNum -= countBlackJoker; | |
countBlackJoker = 0; | |
} | |
// 至此, 小王全部分配完毕 | |
// 如果有未分配的大王 | |
if (countRedJoker > 0) { | |
// 优先尝试往后分配,且尽可能多的分配 | |
if (lastNum < 14) { | |
countRedJoker -= (14 - lastNum); | |
} | |
// 如果还有未分配的 大王, 且队列前面已经装不下了, 返回false | |
if (countRedJoker >= firstNum) { | |
return false; | |
} | |
countRedJoker = 0; | |
} | |
//如果大小王都分配完毕, 则符合等差数列 | |
if (countBlackJoker == 0 && countRedJoker == 0) { | |
return true; | |
} | |
return false; | |
} | |
//////////////////////////////////// | |
//////////////////////////////////// | |
//////////////////////////////////// | |
//////////////////////////////////// | |
// 以下为测试用例 | |
// 定义常量 | |
// 牌面点数 : 对应数值 | |
var Card = { | |
"2": 2, | |
"3": 3, | |
"4": 4, | |
"5": 5, | |
"6": 6, | |
"7": 7, | |
"8": 8, | |
"9": 9, | |
"10": 10, | |
"J": 11, | |
"Q": 12, | |
"K": 13, | |
"A": null, | |
"RED_JOKER": null, | |
"BLACK_JOKER": null, | |
}; | |
function test(c1, c2) { | |
var cards1 = [], | |
cards2 = []; | |
c1.forEach(function(c) { | |
cards1.push({ | |
point: c, | |
num: Card[c] | |
}) | |
}); | |
c2.forEach(function(c) { | |
cards2.push({ | |
point: c, | |
num: Card[c] | |
}) | |
}); | |
console.log(checkSequence(cards1, cards2)); | |
} | |
// 返回 true | |
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3,8]) | |
// 返回 false | |
test(["BLACK_JOKER", "BLACK_JOKER"], ["RED_JOKER", "RED_JOKER", 8, 9,10,"J","Q","A"]) |
Updated,约40行,成功会返回合法的顺子,失败返回false,小王代表1--5,可配置。
function checkSequence(deck1, deck2) {
var cards = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //cards长度是大于15的0串,具体长度不重要
val = 0, // tmp
deck = deck1.concat(deck2),
boundary = 6, // 小王的边界
magic = {A: [], B: [], R: []}; //用于存储A, 小王, 大王的栈
if (deck.length > 14) return false;
// 收集A,小王,大王;填上辅助数组cards,要求cards[i] = i,无法满足情况的则cards[i] = 0
for (var i = 0; val = deck[i]; i++) {
if (val === 'A' || /^B/.test(val) || /^R/.test(val)) {
magic[val.charAt(0)].push(val);
if (magic.A.length > 2) return false; //超过两个A,直接返回false
} else {
if (cards[val]) return false; // 有重复的牌,返回False
cards[val] = val;
}
}
// 枚举, head表示用A填上1,tail表示用A填上14
function tryFill(head, tail) {
for (var start = 1; start <= 14; start++) {
var temp = cards.concat(),
B = magic.B.concat(),
R = magic.R.concat();
temp[1] = head ? 'A' : 0;
temp[14] = tail ? 'A' : 0;
for (var i = start; i <= 14; i++) {
temp[i] = temp[i] || ((i < boundary && B.length) ? B.pop() : R.pop()) || 0;
// 把大小王用尽,检查temp数列是否是顺子,如果是,则直接返回结果
if ((B.length + R.length === 0) && !/,0,/.test(temp.join(',').replace(/^(0,)*|(,0)*$/g, ''))) return temp;
}
}
return false;
}
if (magic.A.length === 1) return tryFill(true, false) || tryFill(false, true);
return tryFill(!!magic.A.length, !!magic.A.length);
}
/*
测试
*/
function test(deck1, deck2, val) {
console.log('----------------------');
console.log("input", deck1, deck2);
var res = checkSequence(deck1, deck2);
if (!res) {
console.log("failed")
} else {
res = res.join(',').replace(/^(0,)*|(,0)*$/g, '').replace(/,/g, ', ');
console.log("success: ["+ res +"]");
}
if (!!res === val) console.log('assertion passed!');
}
// Only accept "A",2,3,4,5,6,7,8,9,10,11,12,13,"BLACK_JOKER","RED_JOKER"
test([4, 6, 8, 9, 10, 2, 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER', 'RED_JOKER'], true); // true
test(['A', 2, 3, 4, 5, 6], [7, 8, 9, 'BLACK_JOKER', 'RED_JOKER'], false); //fail, 小王没地方放
test([12, 13], ['BLACK_JOKER'], false); //false, 小王与12和13连不上
test(['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER'], false); // 超过了5个小王,第六个放不下
test(['BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER'], true); // success
test(['A', 5, 'A', 7], [8, 10, 'BLACK_JOKER', 'RED_JOKER'], false); // fail
test(['A', 'A', 'A', 6, 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'RED_JOKER'], false); // fail
test([3, 4, 5, 6, 7, 8, 9], [10], true); // success
test(['A', 4], ['BLACK_JOKER'], false); // fail
test(['A', 12], [13], true); // success
test(['A', 2, 3, 4], [5, 6, 7, 8, 9, 10, 11, 12, 13, 'RED_JOKER'], false); // success
test(['A', 3, 3], [4, 5, 'BLACK_JOKER'], false); // fail
// 抄了楼下的测试用例(*_*)
test([2,9,"A","RED_JOKER","BLACK_JOKER"],["RED_JOKER","BLACK_JOKER",3,8], true);//true
test([5,6,"A","A",8,9,10,11,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER", 3,3], false);//false
test([5,6,"A","A",8,9,10,11,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER", 3,4], true);//true
test(["BLACK_JOKER","BLACK_JOKER"],["RED_JOKER","RED_JOKER",8,9,10,11,12,"A"], false);//false
test([6,"RED_JOKER","A",8,9,10,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER"], true);//true
test([6,"A",8,9,10,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER"], false);//false
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3,8], true); // true
test(['A',2,3,4,5,6,7,8,9,10, 11, 12, 13], ['A'], true); //true
test(['A',2,3,4,5,6,7,8,9], ['A', 'A'], false); // false
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10, 11, 12, 13], ['A'], true); // true
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10, 11, 12], ['A'], false); //false
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10, 11, 12, 13], ['BLACK_JOKER'], false); //false
这一条好像过不了
test(['BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER',10,'J','Q'], ['A']);
@ssnau 的程序好像也一样
test([15,15,15,15,15,15,15,15,10,11,12,1]);
输出判定失败
贴个渣实现
/**
* Created by JetBrains PhpStorm.
* User: xliu
* Date: 24/03/14
* Time: 17:22
*/
/**
* @param {String} name
* */
function CardVO(name)
{
this.name = name;
this.value = CardVO.VALUE[name];
}
CardVO.VALUE = {
A: 1,
2: 2,
3: 3,
4: 4,
5: 5,
6: 6,
7: 7,
8: 8,
9: 9,
10: 10,
J: 11,
Q: 12,
K: 13,
BLACK_JOKER: 100,
RED_JOKER: 101
};
/**
* @param {CardVO} cardA
* @param {CardVO} cardB
* */
CardVO.GreaterThan = function(cardA, cardB)
{
return cardA.value - cardB.value;
};
/**
* @param {Array} cards1
* @param {Array} cards2
*
* @return {boolean}
* */
function checkSequence(cards1, cards2) {
var BLACK_JOKER_BOUNDARY = 5;
var hand = cards1.concat(cards2);
if(hand.length > 14)
return false;
hand.sort(CardVO.GreaterThan);
//extract wild cards
var wildCards = {
A: [],
BLACK_JOKER: [],
RED_JOKER: []
};
for(var i = 0; i < hand.length; ++i)
{
var card = hand[i];
if(1 == card.value || card.value >= CardVO.VALUE.BLACK_JOKER)
{
wildCards[card.name].push(card);
hand.splice(i--, 1);
}
}
//more than 2 Ace is sure non-straight
if(wildCards.A.length > 2)
return false;
//Main flag
var isStraight = true;
//sort out non-wild cards with Joker patching, easy peasy
for(i = 1; i < hand.length; ++i)
{
card = hand[i];
var lastCard = hand[i-1];
if(1 != card.value - lastCard.value)
{
if(((lastCard.value < BLACK_JOKER_BOUNDARY) && wildCards.BLACK_JOKER.pop()) || wildCards.RED_JOKER.pop())
{
i--;
lastCard.value++;
}
else
isStraight = false;
}
else if( lastCard.value == card.value)
isStraight = false;
}
//reset hand in case value was changed during joker patching
hand.forEach(function(card) {
card.value = CardVO.VALUE[card.name];
});
//Crasy shit happens here
var bJokers = wildCards.BLACK_JOKER.length;
var rJokers = wildCards.RED_JOKER.length;
//split zone A and B based on hand coverage, e.g for a hand 6-10:
// 6789T
//--------------
//| A | | B |
var indexA = hand[0] ? hand[0].value : 2;
var indexB = hand[0] ? hand[hand.length-1].value : 1;
var zoneA = indexA - 2;
var aSpendBJ = Math.min(bJokers, zoneA, BLACK_JOKER_BOUNDARY - 1);
var aSpendRJ = zoneA - aSpendBJ;
var zoneB = 13 - indexB;
var bSpendBJ = Math.min(bJokers, zoneB, Math.max(BLACK_JOKER_BOUNDARY - indexB, 0));
var bSpendRJ = zoneB - bSpendBJ;
var coverTwoAces = aSpendRJ + bSpendRJ <= rJokers && aSpendBJ + bSpendBJ + aSpendRJ + bSpendRJ <= bJokers + rJokers;
if(wildCards.A.length > 1)
isStraight = coverTwoAces;
else if(wildCards.A.length > 0)
isStraight = (aSpendBJ <= bJokers && aSpendRJ <= rJokers) || (bSpendBJ <= bJokers && bSpendRJ <= rJokers);
if(bJokers > aSpendBJ + bSpendBJ)
{
if(1 == bJokers - (aSpendBJ + bSpendBJ))
{
if(wildCards.A.length > 1 ||
(wildCards.A.length > 0 && coverTwoAces == false))
isStraight = false;
}
else
isStraight = false;
}
return isStraight;
}
////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
// 以下为测试用例
function test(c1, c2) {
var cards1 = [],
cards2 = [];
c1.forEach(function(c) {
cards1.push(new CardVO(c));
});
c2.forEach(function(c) {
cards2.push(new CardVO(c));
});
console.log(checkSequence(cards1, cards2));
}
//true
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3,8]);
//true
test(['A',2,3,4,5,6,7,8,9,10,'J','Q','K'], ['A']);
//false
test(['A',2,3,4,5,6,7,8,9], ['A', 'A']);
//true
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10,'J','Q','K'], ['A']);
//false
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10,'J','Q'], ['A']);
//false
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10,'J','Q','K'], ['BLACK_JOKER']);
//true
test(['BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER',6,7,8,9,10,'J','Q'], ['A']);
//true
test(['BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER'], ['A']);
//true
test(['BLACK_JOKER','BLACK_JOKER','BLACK_JOKER','BLACK_JOKER'], ['BLACK_JOKER']);
@ssnau 感觉你之前写的那一版更好。
(function() {
var deckA, deckNum, deckBlackJoker, deckRedJoker;
var checkList = function(cards1, cards2) {
var maxNum, minNum, list;
deckA = deckBlackJoker = deckRedJoker = 0;
deckNum = [];
list = [cards1, cards2];
for (var i in list) {
if (!loopDeck(list[i])) {
return false;
}
}
// 提取边界
if (deckA + deckNum.length + deckBlackJoker + deckRedJoker > 14) {
return false;
}
deckNum.sort();
maxNum = deckNum[deckNum.length - 1];
minNum = deckNum[0];
if (deckA === 1) {
(13 - maxNum) > (minNum - 2) ? (minNum = 2) : (maxNum = 13);
}
if (deckA === 2) {
minNum = 2;
maxNum = 13;
}
return check(minNum, maxNum);
}
// 格式化卡堆
var loopDeck = function(cards) {
for(var i = cards.length - 1; i >= 0; i--) {
if (cards[i] === 'A') {
deckA += 1;
if (deckA > 2) {
return false;
}
} else if (cards[i] === 'BLACK_JOKER') {
deckBlackJoker += 1;
} else if (cards[i] === 'RED_JOKER') {
deckRedJoker += 1;
} else {
if (deckNum.indexOf(cards[i]) !== -1) {
return false;
}
deckNum.push(Number(cards[i]));
}
}
return true;
}
// 条件校验
var check = function(minNum, maxNum) {
for (var i = minNum; i <= maxNum; i++) {
if (deckNum.indexOf(i) !== -1) {
continue;
}
if (i < 9) { // BLACK_JOKER limit
deckBlackJoker > 0 ? deckBlackJoker-- : deckRedJoker--;
} else {
deckRedJoker--;
}
}
return deckRedJoker >= 0;
}
this.checkList = checkList;
}).call(this);
写完对比下感觉差不多...基本没优化orz
我一个不会用gist的朋友写的 , 我发上来
// JavaScript Document
function checkSequence(cards1, cards2) {
var allCards = [];
allCards.concat(cards1, cards2); //把两组牌合并成一组
var cardArr = Array(14); //一旦牌数确定,所有顺子的组合只有14种
for (var i = 0; i < 14; i++) {
// 每种组合都用一个数组来代表
// 0: 代表总判断,一旦为零就代表该顺子不能成立
// 1~14:代表牌的1~14还允许出现的个数
// 15: 代表最多允许"A"的个数
// 16: 代表最多允许小王的个数
// 17: 代表最多允许"A"加小鬼的个数
cardArr[i] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6];
for (var j = 1; j < 15; j++) {
if (j - 1 < i || j - 1 >= i + allCards.length) {
cardArr[i][j] = 0; // 初始化牌1~14的设置,如果把相应的数字变为0,表示该数字牌不可以再出现
// 以下这段代码不解释 :-(
if (j == 1) {
cardArr[i][15]--;
cardArr[i][16]--;
cardArr[i][17]--;
}
if (j == 14) {
cardArr[i][15]--;
cardArr[i][17]--;
}
if (j >= 2 && j <= 5) {
cardArr[i][16]--;
cardArr[i][17]--;
}
}
}
}
for (var i = 0; i < totalCount; i++) { // 针对每一张牌进行判断
for (var j = 0; j < 14; j++) { // 循环确认每一种顺子组合
if (allCards[i].point == "A") { // 出现"A"的话
cardArr[j][15]--;
if (cardArr[j][15] < 0) {
cardArr[j][0] == 0;
} // 该组合还允许出现"A"的数字,为负数表示该顺子已经不能成立
cardArr[j][17]--;
if (cardArr[j][17] < 0) {
cardArr[j][0] == 0;
} // 该组合还允许出现"A"或小王的数字,为负数表示该顺子已经不能成立
} else if (allCards[i].point == "BLACK_JOKER") { // 出现小王的话
cardArr[j][16]--;
if (cardArr[j][16] < 0) {
cardArr[j][0] == 0;
} // 该组合还允许出现小王的数字,为负数表示该顺子已经不能成立
cardArr[j][17]--;
if (cardArr[j][17] < 0) {
cardArr[j][0] == 0;
} // 该组合还允许出现"A"或小王的数字,为负数表示该顺子已经不能成立
} else if (allCards[i].point == "RED_JOKER") { // 出现大王的话:大王很可怜,不需要被考虑。原因不解释
} else { // 出现其它牌的话
cardArr[j][allCards[i].num]--;
if (cardArr[j][allCards[i].num] < 0) {
cardArr[j][0] == 0;
} // 该组合还允许出现某牌的数字,为负数表示该顺子已经不能成立
// 以下这段代码也不解释 :-(
if (allCards[i].num == 1) {
cardArr[j][15]--;
cardArr[j][16]--;
cardArr[j][17]--;
}
if (allCards[i].num == 14) {
cardArr[j][15]--;
cardArr[j][17]--;
}
if (allCards[i].num >= 2 && allCards[i].num <= 5) {
cardArr[j][15]--;
cardArr[j][17]--;
}
if (cardArr[j][15] < 0 || cardArr[j][16] < 0 || cardArr[j][15] < 0) {
cardArr[j][0] == 0;
}
}
}
}
// 当以上代码执行完成后,所有牌都被放到各个顺子的组合里去,并确认时候成立。如果某顺子成立,那该顺子数组的[0]任然为1
for (var i = 0; i < 14; j++) {
if (cardArr[i][0] == 1) {
return ture;
}
}
return false;
}
function checkStraight(deck1, deck2) {
var cards = [],
deck = deck1.concat(deck2),
boundary = 6, // 小王的边界
magic = { A: 0, B: 0, R: 0, M:0, N:100 };
if (deck.length > 14) return false;
// 填上辅助数组cards,要求cards[i] === i
for (var i = 0; val = deck[i]; i++) {
if (val === 'A') {
magic.A++;
} else if (/^B/.test(val)) {
magic.B++;
} else if (/^R/.test(val)) {
magic.R++;
} else {
if (cards[val]) return false;
cards[val] = true;
magic.M = Math.max(magic.M, val);
magic.N = Math.min(magic.N, val);
val < boundary ? magic.B++ : magic.R++;
}
}
if (magic.A > 2) {
return false;
} else if (magic.A == 2) {
return magic.B + 1 < boundary && magic.B + magic.R == 12;
} else if (magic.A == 1) {
return (magic.B + 1 < boundary && magic.B + magic.R + 1 >= magic.M) ||
(magic.B < boundary && magic.B + magic.R >= 14 - magic.N && (magic.B > 0 ? magic.R >= 14 - boundary : true));
} else {
return magic.B < boundary && magic.B + magic.R > magic.M - magic.N &&
(magic.B > 0 ? magic.R > magic.M - boundary : true);
}
return false;
}
/*
测试
*/
function test(deck1, deck2) {
var res = checkStraight(deck1, deck2);
if (!res) {
console.log("false")
} else {
console.log("success")
}
}
// Only accept "A",2,3,4,5,6,7,8,9,10,11,12,13,"BLACK_JOKER","RED_JOKER"
var timeStart = +new Date;
console.log('--- No A ---');
test([4, 6, 8, 9, 10, 2, 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER', 'RED_JOKER']); // true
test(['BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']); // success
test([3, 4, 5, 6, 7, 8, 9], [10]); // success
test([1, 2], [3, 4, 5]); //true
test([12, 13], [11]);// true
test([1, 2], [8, 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']); // false
test([7, 8], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER']); //false, 小王与12和13连不上
test(['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']); // 超过了5个小王,第六个放不下
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10, 11, 12, 13], ['BLACK_JOKER']); //false
console.log('--- 1 A ---');
test(['A', 12], [13]); // success
test([2,9,"A","RED_JOKER","BLACK_JOKER"],["RED_JOKER","BLACK_JOKER",3,8]);//true
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3,8]); // true
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10, 11, 12, 13], ['A']); // true
test([6,"RED_JOKER","A",8,9,10,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER"]);//true
test(['A', 2, 3, 4], [5, 6, 7, 8, 9, 10, 11, 12, 13, 'RED_JOKER']); // success
test(['A', 2, 3, 4, 5, 6], [7, 8, 9, 'BLACK_JOKER', 'RED_JOKER']); //fail, 小王没地方放
test(['A', 4], ['BLACK_JOKER']); // fail
test(['A', 3, 3], [4, 5, 'BLACK_JOKER']); // fail
test(["BLACK_JOKER","BLACK_JOKER"],["RED_JOKER","RED_JOKER",8,9,10,11,12,"A"]);//false
test([6,"A",8,9,10,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER"]);//false
test(['BLACK_JOKER',2,3,4,5,6,7,8,9,10, 11, 12], ['A']); //false
console.log('--- 2 A ---');
test([5,6,"A","A",8,9,10,11,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER", 3,4]);//true
test(['A',2,3,4,5,6,7,8,9,10, 11, 12, 13], ['A']); //true
test(['A', 5, 'A', 7], [8, 10, 'BLACK_JOKER', 'RED_JOKER']); // fail
test([5,6,"A","A",8,9,10,11,12],["RED_JOKER","RED_JOKER", "BLACK_JOKER", 3,3]);//false
console.log('--- 2+ A ---');
test(['A', 'A', 'A', 6, 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'RED_JOKER']); // fail
test(['A',2,3,4,5,6,7,8,9], ['A', 'A']); // false
console.log('Using time: ' + (+new Date - timeStart));
参照@ssnau的改了下,无节操。
@finscn 你那位朋友的代码里面totalCount没定义,最后几行有个地方的true 写成了ture。
var _Count = {
A: [1, 14],
BLACK_JOKER: [1, 2, 3, 4, 5],
RED_JOKER: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
};
function check(card1, card2) {
var cards = card1.concat(card2);
if (cards.length > 14)
return false;
var list = new Array(14);
var A = 0;
var BLACK_JOKER = 0;
var RED_JOKER = 0;
for (var x = 0; x < cards.length; x++) {
var index = new Number(cards[x]);
if (isNaN(index))
eval(cards[x] + "+=1");
else
if (list[index - 1] == null)
list[index - 1] = true;
else
return false;
}
function checkQueue() {
function insert(array) {
var min = 15;
var index = 0;
for (var x in array) {
if (list[array[array.length - 1 - x] - 1] != null)
continue;
for (var i = 1; i < 15; i++) {
if (i == 14 && min == 15) {
index = array[array.length - 1 - x] - 1;
min = i;
break;
}
if (list[array[array.length - 1 - x] - 1 - i] != null && list[array[array.length - 1 - x] - 1 + i] != null) {
index = array[array.length - 1 - x] - 1;
min = -1;
break;
}
if (list[array[array.length - 1 - x] - 1 - i] != null || list[array[array.length - 1 - x] - 1 + i] != null) {
if (i < min) {
index = array[array.length - 1 - x] - 1;
min = i;
break;
}
}
}
}
if (min == 15)
return false;
list[index] = true;
return true;
}
for (var i = 0; i < A; i++)
if (!insert(_Count.A))
return false;
for (var i = 0; i < BLACK_JOKER; i++)
if (!insert(_Count.BLACK_JOKER))
return false;
for (var i = 0; i < RED_JOKER; i++)
if (!insert(_Count.RED_JOKER))
return false;
var t = null;
for (var x in list)
if (t != null && t != x - 1)
return false;
else
t = x;
return true;
}
return checkQueue();
}
document.writeln(check([4, 6, 8, 9, 10, 2, 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER', 'RED_JOKER'])); // true
document.writeln(check(['A', 2, 3, 4, 5, 6], [7, 8, 9, 'BLACK_JOKER', 'RED_JOKER'])); //fail, 小王没地方放
document.writeln(check([12, 13], ['BLACK_JOKER'])); //false, 小王与12和13连不上
document.writeln(check(['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER'])); // 超过了5个小王,第六个放不下
document.writeln(check(['BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER'])); // success
document.writeln(check(['A', 5, 'A', 7], [8, 10, 'BLACK_JOKER', 'RED_JOKER'])); // fail
document.writeln(check(['A', 'A', 'A', 6, 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'RED_JOKER'])); // fail
document.writeln(check([3, 4, 5, 6, 7, 8, 9], [10])); // success
document.writeln(check(['A', 4], ['BLACK_JOKER'])); // fail
document.writeln(check(['A', 12], [13])); // success
document.writeln(check(['A', 2, 3, 4], [5, 6, 7, 8, 9, 10, 11, 12, 13, 'RED_JOKER'])); // success
document.writeln(check(['A', 3, 3], [4, 5, 'BLACK_JOKER'])); // fail
// 抄了楼下的测试用例(*_*)
document.writeln(check([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8]));//true
document.writeln(check([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 3]));//false
document.writeln(check([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 4]));//true
document.writeln(check(["BLACK_JOKER", "BLACK_JOKER"], ["RED_JOKER", "RED_JOKER", 8, 9, 10, 11, 12, "A"]));//false
document.writeln(check([6, "RED_JOKER", "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]));//true
document.writeln(check([6, "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]));//false
document.writeln(check([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8])); // true
document.writeln(check(['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A'])); //true
document.writeln(check(['A', 2, 3, 4, 5, 6, 7, 8, 9], ['A', 'A'])); // false
document.writeln(check(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A'])); // true
document.writeln(check(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], ['A'])); //false
document.writeln(check(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['BLACK_JOKER'])); //false
我才发现你weibo里面发的不是小王当1-9么,这里又变成当1-5了……
@coswind 你这应该是性能最佳的方案了...
贴个渣实现
/*
测试
*/
function test(deck1, deck2) {
console.log('----------------------');
console.log("input", deck1, deck2);
var res = checkTwoArr(deck1, deck2);
if (!res) {
console.log("failed")
} else {
res = res.join(',').replace(/^(0,)*|(,0)*$/g, '').replace(/,/g, ', ');
console.log("success: [" + res + "]");
}
}
// Only accept "A",2,3,4,5,6,7,8,9,10,11,12,13,"BLACK_JOKER","RED_JOKER"
test([4, 6, 8, 9, 10, 2, 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER', 'RED_JOKER']);
// true
test(['A', 2, 3, 4, 5, 6], [7, 8, 9, 'BLACK_JOKER', 'RED_JOKER']);
//fail, 小王没地方放
test([12, 13], ['BLACK_JOKER']);
//false, 小王与12和13连不上
test(['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']);
// 超过了5个小王,第六个放不下
test(['BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']);
// success
test(['A', 5, 'A', 7], [8, 10, 'BLACK_JOKER', 'RED_JOKER']);
// fail
test(['A', 'A', 'A', 6, 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'RED_JOKER']);
// fail
test([3, 4, 5, 6, 7, 8, 9], [10]);
// success
test(['A', 4], ['BLACK_JOKER']);
// fail
test(['A', 12], [13]);
// success
test(['A', 2, 3, 4], [5, 6, 7, 8, 9, 10, 11, 12, 13, 'RED_JOKER']);
// success
test(['A', 3, 3], [4, 5, 'BLACK_JOKER']);
// fail
// 抄了楼下的测试用例(*_*)
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8]);
//true
test([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 3]);
//false
test([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 4]);
//true
test(["BLACK_JOKER", "BLACK_JOKER"], ["RED_JOKER", "RED_JOKER", 8, 9, 10, 11, 12, "A"]);
//false
test([6, "RED_JOKER", "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]);
//true
test([6, "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]);
//false
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8]);
// true
test(['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A']);
//true
test(['A', 2, 3, 4, 5, 6, 7, 8, 9], ['A', 'A']);
// false
test(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A']);
// true
test(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], ['A']);
//false
test(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['BLACK_JOKER']);
//false
function checkTwoArr(arr1, arr2) {
return checkSequence(arr1.concat(arr2));
}
function checkSequence(arr) {
if (arr.length > 14) {
return false;
}
var noJokerA_arr = [];
var b_joker_arr = [];
var r_joker_arr = [];
var a_arr = [];
var boundary = 5
var len = arr.length;
var checkFleg = true;
for (var i = 0; i < len; i++) {
if (arr[i] == "A") {
a_arr.push(arr[i]);
} else if (arr[i] == "BLACK_JOKER") {
b_joker_arr.push(arr[i]);
} else if (arr[i] == "RED_JOKER") {
r_joker_arr.push(arr[i]);
} else {
noJokerA_arr.push(arr[i]);
}
}
//noJokerA_arr = quickSort(noJokerA_arr);
//console.log("noJokerA_arr",noJokerA_arr);
for (i = 0; i < noJokerA_arr.length-1; i++) {
if(noJokerA_arr[i]==noJokerA_arr[i+1]){
return false;
}
}
switch(a_arr.length) {
case 1:
var checkArr1 = checkSequence(b_joker_arr.concat(r_joker_arr).concat(noJokerA_arr).concat([1]));
if (checkArr1) {
return checkArr1;
} else {
var checkArr2 = checkSequence(b_joker_arr.concat(r_joker_arr).concat(noJokerA_arr).concat([14]))
if (checkArr2) {
return checkArr2;
} else {
return false;
}
}
break;
case 2:
return checkSequence(noJokerA_arr.concat(b_joker_arr).concat(r_joker_arr).concat([1, 14]));
break;
default:
break;
}
if (noJokerA_arr.length > 0) {
var arrPock = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
noJokerA_arr = quickSort(noJokerA_arr);
var arrIndex = arrPock.indexOf(noJokerA_arr[0]);
var min = noJokerA_arr[0];
var max = noJokerA_arr[noJokerA_arr.length - 1];
for (var i = arrIndex; i < arrPock.length && arrPock[i] <= max; i++) {
var index = noJokerA_arr.indexOf(arrPock[i]);
if (index == -1) {
if (arrPock[i] <= boundary) {
checkFleg = (b_joker_arr.length > 0) ? (function() {
b_joker_arr.pop();
noJokerA_arr.push(arrPock[i]);
return true;
})() : (r_joker_arr.length > 0) ? (function() {
r_joker_arr.pop();
noJokerA_arr.push(arrPock[i]);
return true;
})() : false;
} else if (arrPock[i] <= 14) {
checkFleg = (r_joker_arr.length > 0) ? (function() {
r_joker_arr.pop();
noJokerA_arr.push(arrPock[i]);
return true;
})() : false;
}
}
}
if (!checkFleg) {
return checkFleg;
} else {
while (b_joker_arr.length > 0) {
var num1 = b_joker_arr.pop();
min--;
if (min <= boundary && min > 0) {
noJokerA_arr.push(min);
} else {
checkFleg = false;
break;
}
}
while (r_joker_arr.length > 0) {
var num2 = r_joker_arr.pop();
max++;
if (max <= 14) {
noJokerA_arr.push(max);
} else {
checkFleg = false;
break;
}
}
if (checkFleg) {
noJokerA_arr = quickSort(noJokerA_arr);
return noJokerA_arr;
} else {
return false;
}
}
} else {
if (b_joker_arr.length <= boundary) {
min = 6;
max = 5;
while (b_joker_arr.length) {
var num1 = b_joker_arr.pop();
min--;
noJokerA_arr.push(min);
}
while (r_joker_arr.length > 0) {
var num2 = r_joker_arr.pop();
max++;
noJokerA_arr.push(max);
}
noJokerA_arr = quickSort(noJokerA_arr);
return noJokerA_arr;
} else {
return false;
}
}
}
function quickSort(arr) {
var len = arr.length;
if (len <= 1) {
return arr;
} else {
var arrLeft = [], arrRight = [];
var nowArr=[];
for (var i = 1; i < len; i++) {
if (arr[0] <arr[i]) {
arrRight.push(arr[i]);
} else if (arr[0] > arr[i]) {
arrLeft.push(arr[i]);
}else{
nowArr.push(arr[0]);
}
}
return quickSort(arrLeft).concat(arr[0]).concat(nowArr).concat(quickSort(arrRight));
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
补充说明:
1 我微博里说 小王代表 1到9有误, 我这边实际遇到的场景是 小王代表 1--5 (当然 这个无所谓)
2 牌是可以有重复的 : 例如 可以 4个小王 9个大王 等等, 可以理解为是从无数副扑克牌当中随意抽取出两组
3 组成的顺子 可以不是5张 , 其实严格说 就是 等差为1的等差数列
4 能且只能组成一组顺子, 组成顺子后, 牌没有剩余
我这个代码 肯定不是最优, 又臭又长, 但是测试了一下, 至少结果都正确 (当然测试用例覆盖率可能不够)
求优化 求纠错 谢谢了