自动打牌
Posted yuvejxke
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自动打牌相关的知识,希望对你有一定的参考价值。
package com.hb.module.ddz.service.ai; import java.util.ArrayList; import com.chester.commons.utils.LogUtil; import com.hb.module.ddz.service.DdzCtrlConfig; import com.hb.module.ddz.service.DdzLog; /** * 斗地主AI出牌规则 * * @author pan * */ public class DdzCardAI extends DdzCard{ public static final int VALUE_DAN = 1; public static final int VALUE_DUI = 2; public static final int VALUE_SAN = 3; public static final int VALUE_SUN = 4; public static final int VALUE_SUN_DUI = 5; public static final int VALUE_FLY = 6; public static final int VALUE_BOMB = 7; /** 已经出的牌 */ private int[] sentCards; /** 出牌者队列 */ private ArrayList<Integer> sender = new ArrayList<Integer>(); /** * 清除所有出牌记录 */ public void clearSentCards() { sentCards = new int[18]; } public int[] getSentCards() { return sentCards; } public ArrayList<Integer> getSender(){ return sender; } /** * 添加已经出的牌 * * @param points */ public void addSentCards(int[] points) { for(int i=0;i<points.length;i++) { sentCards[points[i]]++; } } /** * 根据手牌情况获得记牌器 * * @param cards * @return */ public int[] getJpq(int[] cards) { int[] points = getPoints(cards); int[] jpq = new int[] { 2 - sentCards[C_D] - sentCards[C_X], 4 - sentCards[C_2], 4 - sentCards[C_A], 4 - sentCards[C_K], 4 - sentCards[C_Q], 4 - sentCards[C_J], 4 - sentCards[C_10], 4 - sentCards[C_9], 4 - sentCards[C_8], 4 - sentCards[C_7], 4 - sentCards[C_6], 4 - sentCards[C_5], 4 - sentCards[C_4], 4 - sentCards[C_3], 0//默认炸弹数量为0个,-1为未知数量 }; int[] tmp = new int[sentCards.length]; System.arraycopy(sentCards, 0, tmp, 0, sentCards.length); for(int i=0;i<points.length;i++) { int p = points[i]; tmp[p]++; switch(p) { case C_D: case C_X: jpq[0]--; break; default: jpq[C_2 - p + 1]--; break; } } //王炸没出 if(jpq[0] == 2) { jpq[14] = -1; }else { //是否其它炸弹没出 for(int i=3;i<=C_2;i++) { if(tmp[i]==0) { jpq[14] = -1; break; } } } return jpq; } /** * 出牌者位置 * * @param senderSeatId */ public void addSender(int senderSeatId) { sender.add(senderSeatId); } /** * 寻找当前状态下合适的可出的牌型 * * @return */ public CardGroup findSendCards(DdzTableState state) { int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; int sendCardPlayer = state.sendCardPlayer; DdzLog.info(-1, "aa"); //手里剩下的是炸弹 if(state.isAllBombs()) { if( //只有一个炸弹直接炸 state.isOnlyOneBomb() || //敌人没有王炸 !state.hasEnemyBombKingMaybe()) { CardGroup cg = useBomb(state); if(cg!=null) { return cg; } } } //除了炸弹,只剩下一手牌 CardGroup onlyOneCg = state.getOnlyOneCardGroupNoBomb(); if(onlyOneCg!=null) { state.setIsLastExceptBomb(true); //最后一手牌数量和敌人最小单牌数量一样的时候,压炸弹(防止牌数量一样时,出单牌、三带等被对方压了) if(state.hasBomb() && state.pointsNoBomb.length == enemyMinCardNum && //敌人没有王炸 !state.hasEnemyBombKingMaybe()){ CardGroup cg = useBomb(state); if(cg!=null) { return cg; } } //创建最后一手非炸弹牌,能走就走,有压就压 if(state.isBigger(onlyOneCg)) { return onlyOneCg; } } //独立牌型,敌人可能没有王炸,直接使用炸弹 if(state.isAloneCards() && !state.hasEnemyBombKingMaybe()) { CardGroup cg = useBomb(state); if(cg!=null) { return cg; } } //别人没有出牌,自己出牌 if (state.lastCard == null) { return _autoSendCard(state); } //压牌 CardGroup cg = _sendBiggerCard(state); if(cg!=null) { return cg; } //检查使用炸弹 if( //队友为上家,敌方手牌只有一张,且我方手牌不出现单牌,压之 parnerPos==-1 && enemyMinCardNum==1 && getAllDanCards(state.points, false, false)==null || //队友为上家,敌方打出8张以上牌型,且手牌数量小于等于5张,压之 parnerPos==-1 && sendCardPlayer == 0 && enemyMinCardNum<5 && state.lastCard.points.length >= 8 || //敌方打牌,牌型数量少于7,且连续两轮都是他打牌没人接 sendCardPlayer == 0 && enemyMinCardNum<7 && state.isSameEnemySender() || //队友为下家,手牌数量为1 state.isNextParnerOnlyOneCard() || //我方为地主,敌方牌小于5张,且我方单牌和对子数量小于等于1手 parnerPos==0 && enemyMinCardNum <= 5 && state.getLeftStep() <= 1 || //剩余的牌是很好的牌 state.isStrong() || //普通的出牌提示,需要提示炸弹 parnerPos==2 ) { if(!state.hasEnemyBombKingMaybe()) { return useBomb(state); } } return null; } /** * AI主动出牌 * * @return */ public CardGroup _autoSendCard(DdzTableState state) { int[] cards = state.cards; int[] points = state.points; int parnerCardNum = state.parnerCardNum; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; int[] points_no_boms = state.pointsNoBomb; // 队友为下家,手牌数量小于等于2张的时候,帮助队友 if (parnerPos == 1 && parnerCardNum <= 2) { // 队友手牌数量为2,出最小的对子 if (parnerCardNum == 2 && state.me.getHelp(TYPE_DUI)==-1) { int dui = _checkRepeat(points_no_boms, 2, false, -1); //设置帮助队友标记 state.me.setHelp(TYPE_DUI, dui); if (dui != -1) { return new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); } } //特殊处理AI优化: //自己最小的单牌小于J //队友只有一张牌, //先检查有没有炸弹,如果有,先出炸弹,以便将倍数翻倍 if(points_no_boms[0] < C_J) { CardGroup cg = useBomb(state); if(cg!=null) { return cg; } } if(state.me.getHelp(TYPE_DAN)==-1) { // 出最小的单牌帮助队友 state.me.setHelp(TYPE_DAN, points_no_boms[0]); return new CardGroup(new int[] { points_no_boms[0] }, TYPE_DAN, points_no_boms[0], cards); } } //============================================================================ //================== AUTO SEND CARD =============== //============================================================================ // 敌方只有一张牌,且有可能比自己手里的大,则出四带2 // 敌方只有两张牌,且有可能比自己手里的对子大,则出四带2 if((enemyMinCardNum == 1 && points.length==6 && //最大的单牌和桌面上未出的单牌比较 state.hasBiggerMy())|| (enemyMinCardNum==2 && points.length == 8 && //最大的对子和桌面上未出的对子比较 state.hasBiggerMyDui())) { int[] si2 = state.getCutCard().getSi2(-1, -1, C_D); if(si2!=null) { return new CardGroup(si2,TYPE_SI_2,si2[0],cards); } } int pendingCard = -1; // 单牌太多,且敌人手牌数量还充足,先走单牌 ArrayList<Integer> dans = state.getCutCard().dans; if(dans.size() > 1 && enemyMinCardNum > 2) { int p = dans.get(0); if(p < C_J && (!(state.getCutCard().isInSun(p) || state.getCutCard().isInSan(p) || state.getCutCard().isInDui(p)) || !state.hasBiggerMy())) { return new CardGroup(new int[] {p},TYPE_DAN,p,cards); } } //单顺 int[] sun = state.getCutCard().getSun(); if(sun!=null) { if(sun[0] < C_8 || pendingCard==-1 || pendingCard == sun[0]) return new CardGroup(sun,TYPE_SUN_DAN,sun[0],cards); } //飞机 int[] fly = state.getCutCard().getFly(-1,-1,-1,true); if(fly!=null) { return new CardGroup(fly, TYPE_FLY, fly[0], cards); } //顺对 int[] sun2 = state.getCutCard().getSun2(); if(sun2!=null) { int num = sun2.length*2; int[] tmp = new int[num]; for (int i = 0, k = 0; i < num / 2; i++, k += 2) { tmp[k] = sun2[i]; tmp[k + 1] = sun2[i]; } if(sun2[0] < C_8 || pendingCard==-1) return new CardGroup(tmp,TYPE_SUN_DUI,sun2[0],cards); } // 三带一、三带二 int[] san_1 = state.getCutCard().getSan1(-1, false, //三带不拆王炸 cards.length <= 5 ? (state.hasMyBombKing() ? C_X : C_D + 1 ) : C_2, cards.length <= 5 ? C_X : C_2); int[] san_2 = state.getCutCard().getSan2(-1, false, true,cards.length <= 6 ? C_X : C_2); if (san_1 != null && ( (san_2 == null || san_2.length == 3) || san_1[3] < C_J || (san_2 !=null && san_2[3] >= C_J) )) { if(san_1[0] < C_J || pendingCard==-1 || san_1[3] == pendingCard) return new CardGroup(san_1, TYPE_SAN_1, san_1[0], cards); }else if(san_2!=null){ return new CardGroup(san_2, san_2.length==3?TYPE_SAN:TYPE_SAN_2, san_2[0], cards); } //敌人不止两张,而自己手里只有两张 if(enemyMinCardNum>2 && cards.length == 2) { int dui = _checkRepeat(points_no_boms, 2, false, -1); if(dui!=-1) {//有对子直接出对子 return new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); }else {//手里是单张 //从小往大大 int minIndex = cards[0]>cards[1]?cards[1]:cards[0]; //直接出单牌,小的 int dan = DdzCard.getPoint(minIndex); return new CardGroup(new int[] { dan}, TYPE_DAN, dan, cards); } } //自己只有2张牌,或者敌方非2张牌的时候,出对子 if(enemyMinCardNum!=2 || cards.length==2) { int dui = _checkRepeat(points_no_boms, 2, false, -1); //剩余牌大于3张,对子大于10,优先出完单牌 if(cards.length > 3 && dui>=C_10 && enemyMinCardNum>1) { int[] allDans = getAllDanCards(points_no_boms,false,true); if(allDans.length > 0 && allDans[0] < dui) { return new CardGroup(new int[] {allDans[0]},TYPE_DAN,allDans[0],cards); } } if (dui != -1 && (dui != C_2 || state.getLeftStep() <= 2 || enemyMinCardNum==1)) { return new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); } } //敌人牌只有2张,从最大的对子开始打 if(enemyMinCardNum==2) { int dui = -1; if(state.getCutCard().getDuiNum()>0) { dui = state.getCutCard().duis.get(state.getCutCard().duis.size() - 1); } if(dui==-1) { dui = state.getCutCard().findDui(-1); } //敌人牌数量是2张,但自己的对子比他大,或者出了对2之后,只剩下一手牌,则可以出 if(dui!=-1 && state.isMax(TYPE_DUI, dui) && (dui!=C_2 || state.getLeftStep() <= 2)) { return new CardGroup(new int[] {dui,dui},TYPE_DUI,dui,cards); } } //敌人只有一张牌,从最大的开始压 if (parnerPos != 2 && enemyMinCardNum == 1) { int max_index = points_no_boms.length - 1; return new CardGroup(new int[] { points_no_boms[max_index] }, TYPE_DAN, points_no_boms[max_index], cards); } //敌人有两张牌,自己手里全是单牌,从第二大的开始压 if (parnerPos != 2 && enemyMinCardNum == 2 && cards.length > 2 && cards.length == state.getCutCard().getDanNum()) { int max_index = points_no_boms.length - 2; return new CardGroup(new int[] { points_no_boms[max_index] }, TYPE_DAN, points_no_boms[max_index], cards); } //所有牌都是最大的时候,从最大的开始往下压 if(cards.length - state.getMaxCount()<=1) { // 最大的开始压 return new CardGroup(new int[] { points_no_boms[points_no_boms.length-1] }, TYPE_DAN, points_no_boms[points_no_boms.length-1], cards); }else // 最后出最小的单牌 return new CardGroup(new int[] { points_no_boms[0] }, TYPE_DAN, points_no_boms[0], cards); } /** * AI压牌,出更大的牌 * */ CardGroup _sendBiggerCard(DdzTableState state) { try { switch (state.lastCard.type) { case TYPE_DAN: return _sendBiggerDan(state); case TYPE_DUI: return _sendBiggerDui(state); case TYPE_SAN: return _sendBiggerSan(state); case TYPE_SAN_1: return _sendBiggerSan1(state); case TYPE_SAN_2: return _sendBiggerSan2(state); case TYPE_BOMB: return _sendBiggerBomb(state); case TYPE_SI_2: //手里有王炸,则直接出炸弹 if(state.hasMyBombKing()) { int[] noBombType = DdzCard.getCardType(state.pointsNoBomb); if(noBombType!=null && noBombType[0] == DdzCard.TYPE_DUI) {//对子 return useBomb(state); } } return _sendBiggerSi2(state); case TYPE_SUN_DAN: return _sendBiggerSunDan(state); case TYPE_SUN_DUI: return _sendBiggerSunDui(state); case TYPE_SUN_SAN: return _sendBiggerSunSan(state); case TYPE_FLY: return _sendBiggerFly(state); } } catch (Exception e) { LogUtil.error(e); } return null; } /** * 对要压出去的牌进行检查,不符合规则的直接不出 * * @param points * @param cg * @param leftNum * @param sendCardPlayer * @param keyPoint * @param lastCard * @return */ static CardGroup _checkAndSendBigger(int[] points,CardGroup cg,int leftNum,int sendCardPlayer,int keyPoint,CardGroup lastCard,int parnerPos,int parnerCardNum) { // 提示,不进行其他判断 if(parnerPos == 2) return cg; //三带、四带,且为2时 if(cg.isDai() && cg.keyPoint == DdzCard.C_2) { int[] tmpPoints = new int[points.length]; System.arraycopy(points, 0, tmpPoints, 0, tmpPoints.length); //打出后只有一手牌,直接压 int[] tmp = DdzCard.deleteArray(cg.points,tmpPoints); if(DdzCard.getCardType(tmp)!=null) { return cg; } //打出后还剩下4张或者以上单牌,不出 if(DdzCard.getAllDanCards(points, false, false).length>=4) { return null; } } //不压队友的J以上的牌型 if(sendCardPlayer==1 && lastCard.keyPoint>=keyPoint) { int[] tmp = DdzCard.deleteArray(cg.points,points); if(DdzCard.getCardType(tmp)!=null) { return cg; }else if(tmp.length < parnerCardNum) { //基础牌值是否是强牌值 boolean isStrong = getBaseCardValues(tmp, true, true) >= 10 ? (tmp.length<=3 ? true : false) : false; if(isStrong) return cg; else return null; }else { return null; } } return cg; } /** * 出单牌 * * @return */ CardGroup _sendBiggerDan(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerCardNum = state.parnerCardNum; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; //队友打牌,且队友是下家,队友只有一张牌的时候,不压 if(sendCardPlayer == 1 && parnerCardNum==1 && parnerPos == 1) { return null; } //敌人只有一张,队友打牌,且打的牌是最大的了(不包括自己的牌),不压 if(enemyMinCardNum == 1 && sendCardPlayer == 1 ) { if(state.isMax(TYPE_DAN, lastCard.keyPoint)) { return null; } } //DdzLog.info(-1, "cards.length - state.getMaxCount():%d",cards.length - state.getMaxCount()); //我手里的牌都是桌面上最大牌了(剩余一张小牌无所谓),且敌人没有炸弹了,压 if(cards.length - state.getMaxCount() <=1 && !state.hasEnemyBomb()) { //TODO 这里要避免拆了王炸 int[] dans = getAllDanCards2(points, lastCard.keyPoint); //DdzLog.info(-1, "dan length:%d",dans.length); if(dans.length==0) return null; int dan = dans[0]; //压的牌是大、小王,且有王炸,则直接压王炸 if(dan >= C_X && state.hasMyBombKing()) { CardGroup cg = useBomb(state); if(cg!=null) { return cg; } } //从手里最大的开始压 return new CardGroup(new int[] { dan }, TYPE_DAN, dan, cards); } //队友打牌,且队友是下家,敌人剩下1张牌的时候,不压 if(sendCardPlayer == 1 && parnerPos == 1 && enemyMinCardNum == 1) { return null; } // 敌方打出单牌,且敌方最小单牌数量等于1时 if ((sendCardPlayer == 0 && enemyMinCardNum <= 1) || enemyMinCardNum == 1) { //TODO BUG,敌人牌只有一张,王炸在自己手里,且自己牌还有不少,不会拆王炸 // 从大王开始压 int[] dans = getAllDanCards2(points, lastCard.keyPoint); int dan = state.getSuitableCard(dans); if (dan>lastCard.keyPoint) { CardGroup cg = new CardGroup(new int[] { dan }, TYPE_DAN, dan, cards); return cg; } //有王炸,但都不是强牌型或者最后一手独立牌型,则压大王 if(state.hasMyBombKing() && !state.isAloneCards() && !state.isStrong()) { CardGroup cg = new CardGroup(new int[] {C_D},TYPE_DAN,C_D,cards); return cg; } } else if ( points.length >= 1) { //TODO 这里要判断王炸是否存在 // // 从小到大获得最合适的牌 int dan = state.getCutCard().getSuitableCard(lastCard.keyPoint, 1); //拆王炸前先判断是否有AA、22、AAA、222之类的可以拆 if(dan == -1 || dan >= C_X && state.hasMyBombKing()) { int tmp = -1; if(parnerPos == 2) { tmp = _checkRepeat(points, 1, false, lastCard.keyPoint); }else { //通过拆牌获得适合的压牌 tmp = state.getCutCard().getSuitableCut(lastCard.keyPoint,1,state.sentCardsForMe); } if(tmp!=-1) { dan = tmp; } } // 敌人出小牌,且非连续2次自己出小牌 // 牌值大于等于2,需要评估桌面情况 if(!state.isSameEnemySender() && dan >= DdzCard.C_2 && lastCard.keyPoint < DdzCard.C_K) { //拆顺子中多余的牌、222、22获得单牌 int tmp = state.getCutCard().findDan(lastCard.keyPoint); //敌人牌还太多,则使用最小拆牌获得的牌 if(enemyMinCardNum > 8 || cards.length<=2) { if(tmp == -1 || (tmp >= DdzCard.C_2 && !state.isMax(TYPE_DAN, tmp))) { return null; } dan = tmp; } //DdzLog.info(-1, "last dan:%d",dan); } //经过一轮操作后,还是要拆王炸 if(dan >= C_X && state.hasMyBombKing() && enemyMinCardNum > 5) { //非强牌或者非独立牌 if(!state.isStrong() && !state.isAloneCards()) { //判断概率是否拆王炸 if(DdzCtrlConfig.isBombKingPass()) { return null; }else if(DdzCtrlConfig.isBombKingUse()) { CardGroup cg = useBomb(state); if(cg!=null) { return cg; } } } } if (dan != -1) { CardGroup cg = new CardGroup(new int[] { dan }, TYPE_DAN, dan, cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,enemyMinCardNum > 1 ? C_Q : C_K, lastCard,parnerPos,state.parnerCardNum); } } return null; } /** * 出对子 * * @return */ CardGroup _sendBiggerDui(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerCardNum = state.parnerCardNum; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; int[] duis = getAllDuiCards(points, true); int dui = state.getSuitableCard(duis); //我手里的牌都是桌面上最大牌了(剩余一张小牌或者一个小对无所谓),压 if (dui > lastCard.keyPoint) { //我是农民,地主只有一张牌,队友不是一张牌或者非队友出牌,我手里全是对子,无论怎样都要压对子 if(parnerPos!=0 && enemyMinCardNum==1 && ((sendCardPlayer==1 && parnerCardNum!=1) || sendCardPlayer==0) && cards.length - duis.length*2 <= 1) { CardGroup cg = new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); return cg; } } //敌人出牌,我手里只有3张牌或以下,敌人打对子,检查是否有最大的可压之 if(sendCardPlayer == 0 && (cards.length<=3 || (cards.length==4 && state.getLeftStep()==2)) ) { if(duis.length==0) return null; if (dui > lastCard.keyPoint) { CardGroup cg = new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); return cg; } } // 队友出牌 if (sendCardPlayer == 1 && // 敌人剩下的牌小于2张,队友在下家,不压队友 ((enemyMinCardNum <= 2 && parnerPos == 1) || //队友牌数量小于2张,不压队友 parnerCardNum<=2)) { return null; } if (enemyMinCardNum <= 3) { // 敌方手牌数量少于3,队友在上家,优先使用最大牌压 if (dui > lastCard.keyPoint) { CardGroup cg = new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); return cg; } } else if (points.length >= 2) { // 否则按正常套路出牌 // 从最小的对子开始检查,直到找到比目标牌更大的对子 dui = state.getCutCard().getSuitableCard(lastCard.keyPoint,2); if(dui == -1) { if(parnerPos == 2) { dui = _checkRepeat(points, 2, false, lastCard.keyPoint); }else { dui = state.getCutCard().getSuitableCut(lastCard.keyPoint, 2, state.sentCardsForMe); } } //敌方出很小的对子,我出很大的对子,检查是否有多余的连对可拆开来压 if(dui >= C_A && lastCard.keyPoint < C_10) { int tmp = state.getCutCard().findDui(lastCard.keyPoint); //敌人牌还太多 if(enemyMinCardNum>8) { if(tmp == -1 || (dui >= C_A && !state.isMax(TYPE_DUI, tmp))) { return null; } dui = tmp; } } if (dui != -1) { CardGroup cg = new CardGroup(new int[] { dui, dui }, TYPE_DUI, dui, cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } return null; } /** * 出三张 * * @return */ CardGroup _sendBiggerSan(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; // 敌人就剩下的牌小于3张,不压队友 if (enemyMinCardNum < 3 && sendCardPlayer == 1 && parnerPos != 2) { return null; } //按正常套路压牌 if (points.length >= 3) { int san = state.getCutCard().getSuitableCard(lastCard.keyPoint,3); if(san == -1 && (parnerPos == 2 || enemyMinCardNum <= 2 && sendCardPlayer == 0)) { san = _checkRepeat(points, 3, false, lastCard.keyPoint); } if (san != -1) { CardGroup cg = new CardGroup(new int[] { san, san, san }, TYPE_SAN, san, cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } return null; } /** * 出三带一 * * @return */ CardGroup _sendBiggerSan1(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; // 敌人就剩下的牌小于4张,不压队友 if (enemyMinCardNum < 4 && sendCardPlayer == 1 && parnerPos!=2) { return null; } //队友出牌大于J,且自己压完之后,不能一口气打完,则不压 if (points.length >= 4) { int[] san_1 = state.getCutCard().getSan1(lastCard.keyPoint,true,points.length <= 5 ? C_D + 1 : C_2, C_X); if(san_1 == null && (parnerPos == 2 || enemyMinCardNum <= 2 && sendCardPlayer == 0)) { san_1 = _checkSan_1(points, false, lastCard.keyPoint); } if (san_1 != null) { CardGroup cg = new CardGroup(san_1, TYPE_SAN_1, san_1[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } return null; } /** * 出三带一对 * * @return */ CardGroup _sendBiggerSan2(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; // 敌人就剩下的牌小于5张,不压队友 if (enemyMinCardNum < 5 && sendCardPlayer == 1 && parnerPos != 2) { return null; } //队友出牌大于J,且自己压完之后,不能一口气打完,则不压 if (points.length >= 5) { int[] san_2 = state.getCutCard().getSan2(lastCard.keyPoint, false, false, C_X); // System.out.println("first find:"); // printArray(san_2); if(san_2 == null && (parnerPos == 2 || enemyMinCardNum <= 2 && sendCardPlayer == 0)) { san_2 = _checkSan_2(points, false, lastCard.keyPoint); } // System.out.println("tow:"); // printArray(san_2); if (san_2 != null) { CardGroup cg = new CardGroup(san_2, TYPE_SAN_2, san_2[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } return null; } /** * 出炸弹 * * @return */ CardGroup _sendBiggerBomb(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; if(sendCardPlayer != 0 && parnerPos != 2) { return null; } if (points.length >= 4 && !state.hasBankerBombKing()) { int si = _checkRepeat(points, 4, false, lastCard.keyPoint); if (si != -1) { CardGroup cg = new CardGroup(new int[] { si, si, si, si }, TYPE_BOMB, si, cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } //有王炸,且对方牌很少的时候,压王炸 if(state.hasMyBombKing() && (state.enemyMinCardNum <= 4)) { return useBomb(state); } return null; } /** * 出四带2 * * @return */ CardGroup _sendBiggerSi2(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; if (lastCard.cards.length == 6 && points.length >= 6) { // 敌人就剩下的牌小于6张,不压队友 if (enemyMinCardNum < 6 && sendCardPlayer == 1 && parnerPos != 2) { return null; } //int[] si_2 = _checkSi_2(points, false, 2, lastCard.keyPoint); int[] si_2 = state.getCutCard().getSi2(lastCard.keyPoint, 1,parnerPos == 2 ? C_D + 1 : C_2); if(si_2==null && (parnerPos == 2 || enemyMinCardNum <= 2 && sendCardPlayer == 0)) { si_2 = _checkSi_2(points,false,2,lastCard.keyPoint); } if (si_2 != null) { CardGroup cg = new CardGroup(si_2, TYPE_SI_2, si_2[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } if (lastCard.cards.length == 8 && points.length >= 8) { // 敌人就剩下的牌小于8张,不压队友 if (enemyMinCardNum < 8 && sendCardPlayer == 1 && parnerPos != 2) { return null; } int[] si_2 = state.getCutCard().getSi2(lastCard.keyPoint, 2, parnerPos == 2 ? C_D + 1 : C_2); if(si_2==null && (parnerPos == 2 || enemyMinCardNum <= 2 && sendCardPlayer == 0)) { si_2 = _checkSi_2(points, false, 4, lastCard.keyPoint); } if (si_2 != null) { CardGroup cg = new CardGroup(si_2, TYPE_SI_2, si_2[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_J,lastCard,parnerPos,state.parnerCardNum); } } return null; } /** * 出单顺 * * @return */ CardGroup _sendBiggerSunDan(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; // 敌人就剩下的牌小于要压的牌数量,不压队友 if (enemyMinCardNum < points.length && sendCardPlayer == 1 && parnerPos != 2) { return null; } int[] points_tmp = points; while (points_tmp.length >= lastCard.points.length) { int[] sun = _checkSun(points_tmp, 1, false, true); if (sun == null) { break; } int num = lastCard.points.length; if (sun[0] > lastCard.keyPoint && sun.length >= num) { int[] tmp = new int[num]; for (int i = 0; i < num; i++) { tmp[i] = sun[i]; } CardGroup cg = new CardGroup(tmp, TYPE_SUN_DAN, sun[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_7,lastCard,parnerPos,state.parnerCardNum); } else { // 移除最小的牌,继续寻找其他顺子 points_tmp = deleteArray(new int[] { sun[0] }, points_tmp); } } return null; } /** * 出顺对 * * @return */ CardGroup _sendBiggerSunDui(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; // 敌人就剩下的牌小于要压的牌数量,不压队友 if (enemyMinCardNum < points.length && sendCardPlayer == 1 && parnerPos != 2) { return null; } int[] points_tmp = points; while (points_tmp.length >= lastCard.points.length) { int[] sun = _checkSun(points_tmp, 2, false, true); if (sun == null) { break; } int num = lastCard.points.length; if (sun[0] > lastCard.keyPoint && sun.length * 2 >= num) { int[] tmp = new int[num]; for (int i = 0, k = 0; i < num / 2; i++, k += 2) { tmp[k] = sun[i]; tmp[k + 1] = sun[i]; } CardGroup cg = new CardGroup(tmp, TYPE_SUN_DUI, sun[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_8,lastCard,parnerPos,state.parnerCardNum); } else { // 移除最小的对子,继续寻找其他顺子 points_tmp = deleteArray(new int[] { sun[0], sun[0] }, points_tmp); } } return null; } /** * 出三顺 * * @return */ CardGroup _sendBiggerSunSan(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; int enemyMinCardNum = state.enemyMinCardNum; // 敌人就剩下的牌小于要压的牌数量,不压队友 if (enemyMinCardNum < points.length && sendCardPlayer == 1 && parnerPos != 2) { return null; } int[] points_tmp = points; while (points_tmp.length >= lastCard.points.length) { int[] sun = _checkSun(points_tmp, 3, false, true); if (sun == null) { break; } int num = lastCard.points.length; if (sun[0] > lastCard.keyPoint && sun.length * 3 >= num) { int[] tmp = new int[num]; for (int i = 0, k = 0; i < num / 3; i++, k += 3) { tmp[k] = sun[i]; tmp[k + 1] = sun[i]; tmp[k + 2] = sun[i]; } CardGroup cg = new CardGroup(tmp, TYPE_SUN_SAN, sun[0], cards); return _checkAndSendBigger(points,cg,1,sendCardPlayer,C_10,lastCard,parnerPos,state.parnerCardNum); } else { // 移除最小的三条,继续寻找其他顺子 points_tmp = deleteArray(new int[] { sun[0], sun[0], sun[0] }, points_tmp); } } return null; } /** * 出飞机 * * @return */ CardGroup _sendBiggerFly(DdzTableState state) { int sendCardPlayer = state.sendCardPlayer; int[] cards = state.cards; int[] points = state.points; int enemyMinCardNum = state.enemyMinCardNum; CardGroup lastCard = state.lastCard; int parnerPos = state.parnerPos; // 敌人就剩下的牌小于要压的牌数量,不压队友 if (sendCardPlayer == 1 && parnerPos != 2) { return null; } int[] sun = _checkSun(lastCard.points, 3, false, false); if (sun == null) { return null; } int sunLen = sun.length; int num = lastCard.points.length - sunLen*3; if(num == sunLen) { num = 1; }else { num = 2; } int[] fly = state.getCutCard().getFly(lastCard.keyPoint,sunLen,num,true); if(fly==null && (parnerPos == 2 || enemyMinCardNum <= 2)) { fly = _checkFly(points,false); } if(fly!=null) { CardGroup cg = new CardGroup(fly, TYPE_FLY, fly[0], cards); if(parnerPos!=2) { if(cg.keyPoint > lastCard.keyPoint && fly.length == lastCard.cards.length) { return cg; } }else return cg; } return null; } }
以上是关于自动打牌的主要内容,如果未能解决你的问题,请参考以下文章
如何设置 vscode 的代码片段,以便在自动完成后自动触发 vscode 的智能感知?
Java 续上上表 和某位知名老总打牌,赢下价值两百万的Java核心知识,今天发出来,交交善缘。