/**
* Created by xujw on 2017/10/16.
* 斗地主
* 單副撲克
* 沒有癩子玩法
* 牌對象為{grade:3,face:1}
* grade 牌面點數(3-13:3-K, 14:A, 15:2, 16:小王 17:大王)
* face 牌面花色(1:黑桃、2:紅桃、3:梅花、4:方塊)
*/
var CARD_TYPE_INVALID = -1; // 無效手牌
var CARD_TYPE_SINGLE = 1; // 單張
var CARD_TYPE_DOUBLE = 2; // 對子
var CARD_TYPE_THREE = 3; // 三張
var CARD_TYPE_THREE_ONE = 4; // 三帶一(三帶一張或者一對)
var CARD_TYPE_BOMB = 5; // 炸彈
var CARD_TYPE_FORE_TWO = 6; // 四帶二
var CARD_TYPE_CONTINUOUS_SIGNGLE = 7; // 單順(5張起)
var CARD_TYPE_CONTINUOUS_DOUBLE = 8; // 雙順(3對起)
var CARD_TYPE_AIRPLANE = 9; // 飛機 (兩個三張起)
var CARD_TYPE_AIRPLANE_WING = 10; // 飛機帶翅膀 (三順+同數量單牌或者對牌)
var CARD_TYPE_KING = 11; // 火箭
/**
* 洗牌
* @param arr
* @return {*}
*/
function shuffle(arr) {
var i,
j,
temp;
for (i = arr.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
/***
* 從大到小排序手牌
* @param cardsArr 手牌數組
*/
function sortBig2Samll(cardsArr) {
cardsArr.sort(function (c1, c2) {
return c2.grade - c1.grade;
});
}
/**
* 判定手牌類型
* @param cardsArr 要判定的手牌信息數組(已經按照從大到小排好序)
* @return {Number}
*/
function judgeCardType(cardsArr) {
if (!cardsArr || cardsArr.length < 1) return CARD_TYPE_INVALID;
sortBig2Samll(cardsArr);
var cardType = CARD_TYPE_INVALID;
var len = cardsArr.length;
if (len === 1) {
cardType = CARD_TYPE_SINGLE;
cc.log('牌型:單張');
} else if (len === 2) {
if (checkDouble(cardsArr)) {
cardType = CARD_TYPE_DOUBLE;
cc.log('牌型:對子');
} else if (checkKingBomb(cardsArr)) {
cardType = CARD_TYPE_KING;
cc.log('牌型:王炸');
}
} else if (len === 3) {
if (checkAllCardSame(cardsArr)) {
cardType = CARD_TYPE_THREE;
cc.log('牌型:三張');
}
} else if (len === 4) {
if (checkAllCardSame(cardsArr)) {
cardType = CARD_TYPE_BOMB;
cc.log('牌型:炸彈');
} else if (checkThreeOne(cardsArr)) {
cardType = CARD_TYPE_THREE_ONE;
cc.log('牌型:三帶一張');
}
} else if (len === 5) {
if (checkContinuousSingle(cardsArr)) {
cardType = CARD_TYPE_CONTINUOUS_SIGNGLE;
cc.log('牌型:順子' + len + '張.');
} else if (checkThreeOne(cardsArr)) {
cardType = CARD_TYPE_THREE_ONE;
cc.log('牌型:三帶一對');
}
} else if (len === 6) {
if (checkContinuousSingle(cardsArr)) {
cardType = CARD_TYPE_SINGLE;
cc.log('牌型:順子' + len + '張.');
} else if (checkContinuousDouble(cardsArr)) {
cardType = CARD_TYPE_DOUBLE;
cc.log('牌型:連對(3對)');
} else if (checkAirplane(cardsArr)) {
cardType = CARD_TYPE_AIRPLANE;
cc.log('牌型:飛機');
} else if (checkFourWithTwo(cardsArr)) {
cardType = CARD_TYPE_FORE_TWO;
cc.log('牌型:4帶2');
}
} else {
// 6 張以上需要判斷單順、雙順、飛機、飛機帶翅膀、4帶2
if (checkContinuousSingle(cardsArr)) {
cardType = CARD_TYPE_CONTINUOUS_SIGNGLE;
cc.log('牌型:單順' + len + '張.');
} else if (checkContinuousDouble(cardsArr)) {
cardType = CARD_TYPE_CONTINUOUS_DOUBLE;
cc.log('牌型:連對' + len / 2 + '對');
} else if (checkAirplane(cardsArr)) {
cardType = CARD_TYPE_AIRPLANE;
cc.log('牌型:飛機');
} else if (checkAirplaneWithWing(cardsArr)) {
cardType = CARD_TYPE_AIRPLANE_WING;
cc.log('牌型:飛機帶翅膀');
} else if (checkFourWithTwo(cardsArr)) {
cardType = CARD_TYPE_FORE_TWO;
cc.log('牌型:4帶2');
}
}
/****************start**************/
// 檢測所有牌都相同
function checkAllCardSame(arr) {
var len = arr.length;
var isSame = true;
for (var i = 0; i < len - 1; i++) {
if (arr[i].grade !== arr[i + 1].grade) {
isSame = false;
break;
}
}
return isSame
}
// 檢測是不是遞增(3/4/5, 6/7/8/9...)
function checkIncrease(arr) {
var len = arr.length;
if (len < 2) {
return false;
}
var ret = true;
for (var i = 0; i < len - 1; i++) {
if (arr[i].grade !== (arr[i + 1].grade + 1)) {
ret = false;
break;
}
}
return ret;
}
// 檢測單張
function checkSignle(arr) {
return arr.length === 1;
}
// 檢測對子
function checkDouble(arr) {
if (arr.length !== 2) return false;
return checkAllCardSame(arr);
}
// 檢測王炸
function checkKingBomb(arr) {
if (arr.length !== 2) return false;
var kingCount = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i].grade === 16 || arr[i].grade === 17) {
kingCount++;
}
}
return kingCount === 2;
}
// 三張不帶
function checkThree(arr) {
if (arr.length !== 3) return false;
return checkAllCardSame(arr);
}
// 檢測三帶一(帶一張或者一對)
function checkThreeOne(arr) {
var len = arr.length;
if (len !== 4 && len !== 5) return false;
// 炸彈不算三帶一
if (checkBomb(arr)) return false;
var ret = false;
if (len === 4) {
if (checkAllCardSame(arr.slice(0, arr.length - 1)) || checkAllCardSame(arr.slice(arr.length - 3, arr.length))) {
ret = true;
}
} else if (len === 5) {
if (checkAllCardSame(arr.slice(0, arr.length - 2)) && checkAllCardSame(arr.slice(arr.length - 2, arr.length))) {
ret = true;
} else if (checkAllCardSame(arr.slice(0, arr.length - 3)) && checkAllCardSame(arr.slice(arr.length - 3, arr.length))) {
ret = true;
}
}
return ret;
}
// 檢測炸彈(5555)
function checkBomb(arr) {
if (arr.length !== 4) return false;
return checkAllCardSame(arr);
}
// 檢測單順(34567)
function checkContinuousSingle(arr) {
var len = arr.length;
if (len < 5 || len > 12) {
return false;
}
// 大小王、2不能算在順子里
var ret = true;
for (var i = 0; i < len - 1; i++) {
var pre = arr[i].grade;
var next = arr[i + 1].grade;
if (pre === 15 || pre === 16 || pre == 17 || next === 15 || next === 16 || next === 17) {
ret = false;
break;
}
else if (pre !== (next + 1)) {
ret = false;
break;
}
}
return ret;
}
// 檢測雙順(連對334455)
function checkContinuousDouble(arr) {
var len = arr.length;
if (len < 6 || len % 2 !== 0) {
return false;
}
var ret = true;
for (var i = 0; i < len; i = i + 2) {
// 2不能參與連對
if (arr[i].grade === 15) {
ret = false;
break;
}
if (!checkAllCardSame(arr.slice(i, i + 2))) {
ret = false;
break;
}
if (i < len - 2) {
if (arr[i].grade !== (arr[i + 2].grade + 1)) {
ret = false;
break;
}
}
}
return ret;
}
// 檢測飛機(333444)
function checkAirplane(arr) {
var len = arr.length;
if (len < 6 || len % 3 !== 0) {
return false;
}
var ret = true;
for (var i = 0; i < len; i += 3) {
// 2不參與飛機
if (arr[i].grade === 15) {
ret = false;
break;
}
if (!checkThree(arr.slice(i, i + 3))) {
ret = false;
break;
}
if (i < len - 3) {
if (arr[i].grade !== (arr[i + 3].grade + 1)) {
ret = false;
break;
}
}
}
return ret;
}
// 檢測飛機帶翅膀(33344456、3334445566)
function checkAirplaneWithWing(arr) {
var len = arr.length;
if (len < 8) {
return false;
}
var threeArr = [];
var othersArr = [];
// 先找出所有的三張
for (var i = 0; i < len;) {
// 剩余手牌已經不夠三張了
if (i >= (len - 2)) {
for (var k = i; k < len; k++) {
othersArr.push(arr[k]);
}
break;
}
// 剩余手牌大於二張
var key = arr[i].grade;
var count = 1;
for (var j = i + 1; j < len; j++) {
if (key === arr[j].grade) {
count++;
} else {
break;
}
}
// 如果count === 4 說明有炸彈,不符合規則
if (count === 4) {
return false;
} else if (count === 3) {
threeArr.push(arr[i], arr[i + 1], arr[i + 2]);
i = j;
} else {
for (var h = i; h < j; h++) {
othersArr.push(arr[h]);
}
i = j;
}
}
cc.log('-------飛機帶翅膀判定------');
cc.log('threes:' + JSON.stringify(threeArr));
cc.log('others:' + JSON.stringify(othersArr));
cc.log('-------------------------');
// 判定三張是不是飛機
if (!checkAirplane(threeArr)) {
// 有可能三張相同牌作為單牌帶出, 此時剔除一組三張作為帶牌
// 如:333444555+888
// 如:333444555666 + 8889
var threeLen = threeArr.length;
if (checkAirplane(threeArr.slice(0, threeLen - 3))) {
othersArr.push(threeArr[threeLen - 3], threeArr[threeLen - 2], threeArr[threeLen - 1]);
threeArr = threeArr.slice(0, threeLen - 3);
} else if (checkAirplane(threeArr.slice(3, arr.length))) {
othersArr.push(threeArr[0], threeArr[1], threeArr[2]);
threeArr = threeArr.slice(3, threeLen);
} else {
return false;
}
}
// 需要翅膀數(單牌或者對子個數)
var threeCounts = threeArr.length / 3;
// 翅膀是單牌
if (threeCounts === othersArr.length) {
// 翅膀不能同時包含大小王
var kingCount = 0;
for (var v = 0; v < othersArr.length; v++) {
if (othersArr[v].grade === 16 || othersArr[v].grade === 17) {
kingCount++;
}
}
return kingCount < 2;
} else if (threeCounts === othersArr.length / 2) {
// 翅膀是對子
// 判斷otherArr是不是全是對子
for (var u = 0; u < othersArr.length; u = u + 2) {
if (!checkAllCardSame(othersArr.slice(u, u + 2))) {
return false;
}
}
return true;
} else {
// 翅膀數目不對
return false;
}
}
// 檢測4帶二
function checkFourWithTwo(arr) {
var ret = false;
if (checkAllCardSame(arr.slice(0, arr.length - 2))) {
ret = true;
} else if (checkAllCardSame(arr.slice(1), arr.length - 1)) {
ret = true;
} else if (checkAllCardSame(arr.slice(2), arr.length)) {
ret = true;
}
return ret;
}
/****************end**************/
return cardType;
}
/**
* 比較兩組手牌大小
* @param cards1
* @param cards2
* @return {Boolean} true 表示 cards1 大於 cards2
*/
function compareCards(cards1, cards2) {
var cardType1 = judgeCardType(cards1);
var cardType2 = judgeCardType(cards2);
if (cardType1 === cardType2){
}else {
}
}