Skip to content

Instantly share code, notes, and snippets.

@finscn
Last active August 29, 2015 13:57
Show Gist options
  • Save finscn/9744730 to your computer and use it in GitHub Desktop.
Save finscn/9744730 to your computer and use it in GitHub Desktop.
检测 两组任意(不限个数 不限花色) 的扑克牌, 混到一起后能否构成任意长度(大于1 小于15)的顺子.A代表1或14,小王代表1--5,大王代表1--14
/*
检测 两组任意(不限个数 不限花色) 的扑克牌, 混到一起后能否构成任意长度(大于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"])
@coswind
Copy link

coswind commented Mar 25, 2014

@finscn 你那位朋友的代码里面totalCount没定义,最后几行有个地方的true 写成了ture。

@Kation
Copy link

Kation commented Mar 25, 2014

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

@lyDASHsBOK
Copy link

我才发现你weibo里面发的不是小王当1-9么,这里又变成当1-5了……

@ssnau
Copy link

ssnau commented Mar 25, 2014

@coswind 你这应该是性能最佳的方案了...

@as3long
Copy link

as3long commented Mar 25, 2014

贴个渣实现

/*
 测试
 */
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