基本思路:
1) 先确定火箭:判断是否有大小王。
2) 再确定炸弹:判明是否有四头。
3) 再确定三条和三顺:在已经确定的三条中判断是否包含相邻的三条,如果有,则将其组成三顺。注意,应该使三顺的数量尽可能大。
即如果有444555666,则将其合成一个三顺,而不是分成444555一个三顺和666一个三条。
4) 再确定单顺:判断单顺时必须去除四个2以外的所有炸弹。
首先判断是否存在除了三条牌(这里的三条是指所有的三条)以外的连牌。
if(havaNext)则将其提取出来。then,将剩余的牌与每一个三条(不包含三顺)进行试组合,
if能够重新组成单顺和对子,则将原有的三条取消,重新组合成连牌和单顺
5) 再确定双顺:首先,如果两单顺牌完全重合,则将其重新组合成双顺。
其次,在除炸弹、三顺、三条、单顺以外的牌中检测是否包含双顺。如果有,将其提取出来。
6 再确定对子:在炸弹、三顺、三条、连牌、双顺以外的牌中检测是否存在对子,如果存在将其提取出来。
7) 再确定单牌:除了炸弹、三顺、三条、连牌、双顺、对子以外的所有牌张都是单牌。
补充:
很显然,单顺和三条炸弹等的处理最追求最少手数的基础上是非常麻烦的;一种方法是穷举,二种方法是字典法,方法三就是dp问题的形式求解。
上面的4)是一种方法,另一种方法在放弃除去2王炸弹的情况下,我们可以实现的最少手数依次和放弃三条的情况下的手数做比较,最终选择其中手数最少的一种。
打分系统:并将各个牌的情况打分。这个打分系统将后面再说。
中心程序
package com.byk.play; import java.util.ArrayList; import com.byk.ddz.PaixDic; import com.byk.ddz.XuanPai; public class CopareShouPaiShuLiang { static int[] arr1 = XuanPai.set17Pai(); static int[] arr = new int[]{3,4,5,6,7,8,9,10,11,12,13,14,16,20,30}; public static void main(String[] args) { ArrayList<PaixDic> alp1 = new ArrayList<>(); ArrayList<PaixDic> alp = new ArrayList<>(); int b = fangfa2(alp1); int a = fangfa1(alp); if(a>b){ System.out.println("决定选择的方法"+alp); }else if(a<b){ System.out.println("决定选择的方法"+alp1); }else{ System.out.println("两种方法可以酌情考虑"); } } public static int fangfa2(ArrayList<PaixDic> alp1) { ArrayList<Integer> alr2= new ArrayList<>(); for(int i=0;i<arr1.length;i++){ alr2.add(arr1[i]); }//将数组转到集合中 if(pdHuoJian(alr2)){//判断火箭 ArrayList<Integer> alk = new ArrayList<>(); alk.add(20); alk.add(30); removeAll(alr2, alk); PaixDic pxdic= new PaixDic("火箭",alk); alp1.add(pxdic); } ArrayList<PaixDic> alpk = new ArrayList<>(); returnShunZi(alpk, alr2);//顺子处理 alp1.addAll(alpk); returnAfterRemove(alpk,alr2); ArrayList<PaixDic> ack = returnZhaDan(alr2);//炸弹处理 alp1.addAll(ack);//[炸弹,null] returnAfterRemove(ack,alr2); ArrayList<PaixDic> ack1 = return3Tiao(alr2);//三条处理 alp1.addAll(ack1); returnAfterRemove(ack1,alr2); ArrayList<PaixDic> ack2 = returnDuiZi(alr2);//对子处理 alp1.addAll(ack2); returnAfterRemove(ack2,alr2); ArrayList<PaixDic> alpd = returnDanZhi(alr2);//单牌处理 alp1.addAll(alpd); for(PaixDic ap:alp1){ System.out.println(ap); } int num = comuShouShu(alp1); System.out.println("[火箭->顺子->炸弹->三带->对子->单牌]这样的手牌数为:"+num); return num; } public static int fangfa1(ArrayList<PaixDic> alp){ ArrayList<Integer> alr2= new ArrayList<>(); for(int i=0;i<arr1.length;i++){ alr2.add(arr1[i]); }//将数组转到集合中 if(pdHuoJian(alr2)){//判断火箭 ArrayList<Integer> alk = new ArrayList<>(); alk.add(20); alk.add(30); removeAll(alr2, alk); PaixDic pxdic= new PaixDic("火箭",alk); alp.add(pxdic); } ArrayList<PaixDic> ack = returnZhaDan(alr2);//炸弹处理 alp.addAll(ack);//[炸弹,null] returnAfterRemove(ack,alr2); ArrayList<PaixDic> ack1 = return3Tiao(alr2);//三条处理 alp.addAll(ack1); returnAfterRemove(ack1,alr2); ArrayList<PaixDic> alpk = new ArrayList<>();//顺子需要自己建立一个中间字典 returnShunZi(alpk, alr2);//顺子处理 alp.addAll(alpk); returnAfterRemove(alpk,alr2); ArrayList<PaixDic> ack2 = returnDuiZi(alr2);//对子处理 alp.addAll(ack2); returnAfterRemove(ack2,alr2); ArrayList<PaixDic> alpd = returnDanZhi(alr2);//单排处理 alp.addAll(alpd); for(PaixDic ap:alp){ System.out.println(ap); } int num = comuShouShu(alp); System.out.println("[炸弹->三带->火箭->顺子->对子->个]这样的手牌数为:"+num); return num; } //在原集合中删除字典集合中出现过的元素;输入字典集合和原始整数集合。 public static void returnAfterRemove(ArrayList<PaixDic> alpd,ArrayList<Integer> al){ if(alpd.get(0).getAlr().isEmpty()){ return; }else{ for(int i=0;i<alpd.size();i++){ ArrayList<Integer> alr = alpd.get(i).getAlr(); // al.removeAll(alr); removeAll(al, alr); } } } public static boolean pdHuoJian(ArrayList<Integer> alr) { int count=0; for(int i=0;i<alr.size();i++){ if(alr.get(i) == 20 || alr.get(i) == 30){ count++; } } if(count>1){ return true; }else{ return false; } } //判断炸弹并返回炸弹的个数,ps炸弹,三顺,对子都可以抽象为一个方法,略。 public static ArrayList<PaixDic> returnZhaDan(ArrayList<Integer> alr){ ArrayList<PaixDic> alk = new ArrayList<>(); boolean flag=false; for(int i=0;i<13;i++){ int count = 0; for(int j=0;j<alr.size();j++){ if(alr.get(j)==arr[i]){ count++; } } ArrayList<Integer> al2= new ArrayList<>(); if(count==4){ flag = true; for(int k=0;k<4;k++){ al2.add(arr[i]); } PaixDic pxdic = new PaixDic("炸弹",al2); alk.add(pxdic); } } if(!flag){ PaixDic pxdic = new PaixDic("炸弹",new ArrayList<Integer>()); alk.add(pxdic); } return alk; } //判断是否存在三条;无视d):将三条弄到一起出;判断手数的时候再判断三顺。 public static ArrayList<PaixDic> return3Tiao(ArrayList<Integer> alr){ ArrayList<PaixDic> alk = new ArrayList<>(); boolean flag=false; for(int i=0;i<13;i++){ int count = 0; for(int j=0;j<alr.size();j++){ if(alr.get(j)==arr[i]){ count++; } } ArrayList<Integer> al2= new ArrayList<>(); if(count==3){ flag = true; for(int k=0;k<3;k++){ al2.add(arr[i]); } PaixDic pxdic = new PaixDic("三条",al2); alk.add(pxdic); } } if(!flag){ PaixDic pxdic = new PaixDic("三条",new ArrayList<Integer>()); alk.add(pxdic); } return alk; } //逼近最后阶段,判断完单顺和双顺就基本结束了。 public static void returnShunZi(ArrayList<PaixDic> alpk,ArrayList<Integer> alr){ // ArrayList<PaixDic> alpp = new ArrayList<>(); for(int i=0;i<8;i++){ ArrayList<Integer> ar = new ArrayList<>(); for(int j=arr[i];j<arr[i]+5;j++){ ar.add(j); }//for里面装的一个5连集合。 if(alr.containsAll(ar)){ PaixDic pdc = new PaixDic("单顺",ar); alpk.add(pdc); removeAll(alr, ar); // System.out.println(alr); returnShunZi(alpk,alr); } } if(alpk.isEmpty()){ PaixDic pxdic = new PaixDic("顺子",new ArrayList<Integer>()); alpk.add(pxdic); return; } //在进入穷举前需要对alr自动排序;但是递归过程中会逐步遍历 // System.out.println(alr); for(Integer i:alr){ for(PaixDic pdc:alpk){//遍历每一个独立出来的元素;寻找是否存在在一个Dic的Al后添加上来 if(i==(pdc.getAlr().get(pdc.getAlr().size()-1)+1)){ pdc.getAlr().add(i); } } } } //建立一个自己的remove函数,只删除一套元素. public static void removeAll(ArrayList<Integer> alr,ArrayList<Integer> ar){ a:for(int i=0;i<ar.size();i++){ for(int j=0;j<alr.size();j++){ if(ar.get(i)==alr.get(j)){ alr.remove(j); continue a; } } } } //判断对子;并返回有对子的字典。 public static ArrayList<PaixDic> returnDuiZi(ArrayList<Integer> alr){ ArrayList<PaixDic> ald = new ArrayList<>(); boolean flag=false; for(int i=0;i<13;i++){ int count = 0; for(int j=0;j<alr.size();j++){ if(alr.get(j)==arr[i]){ count++; } } ArrayList<Integer> al2= new ArrayList<>(); if(count==2){ flag = true; for(int k=0;k<2;k++){ al2.add(arr[i]); } PaixDic pxdic = new PaixDic("对子",al2); ald.add(pxdic); } } if(!flag){ PaixDic pxdic = new PaixDic("对子",new ArrayList<Integer>()); ald.add(pxdic); } return ald; } //判断对子;并返回有对子的字典。 public static ArrayList<PaixDic> returnDanZhi(ArrayList<Integer> alr){ ArrayList<PaixDic> aldz = new ArrayList<>(); for(int i=0;i<alr.size();i++){ ArrayList<Integer> aldr = new ArrayList<>(); aldr.add(alr.get(i)); aldz.add(new PaixDic("单牌",aldr)); } return aldz; } public static int comuShouShu(ArrayList<PaixDic> alp){ int num=0; for(PaixDic dic:alp){ if(!dic.getAlr().isEmpty()){ num += 1; } if(dic.getPaixing().equals("三条") && !dic.getAlr().isEmpty()){ num-=1; } if(dic.getPaixing().equals("炸弹") && !dic.getAlr().isEmpty()){ num -= 2; } if(dic.getPaixing().equals("火箭") && !dic.getAlr().isEmpty()){ num -= 2; }//因为绝对手牌的原因 } return num; } }工具类和便于手牌类型统计建立的集合类附上。
package com.byk.ddz; import java.util.ArrayList; /* * 在54张牌中随机选出17张用数组记录 */ public class XuanPai { static int[] arr = new int[]{3,4,5,6,7,8,9,10,11,12,13,14,16,20,30}; //核心函数。10行的样子 public static int[] set17Pai(){ ArrayList<Integer> alr= new ArrayList<>(); for(int i=0;i<arr.length-2;i++){ for(int j=0;j<4;j++){ alr.add(arr[i]); } } alr.add(20); alr.add(30); int[] arr2 = new int[17]; int i=0; while(i<17){ int k = (int) (alr.size()*Math.random()); arr2[i] = alr.get(k); alr.remove((Integer)arr2[i]); i++; } return arr2; } } package com.byk.ddz; import java.util.ArrayList; public class PaixDic { String paixing; ArrayList<Integer> alr; public PaixDic(String paixing, ArrayList<Integer> alr) { super(); this.paixing = paixing; this.alr = alr; } public PaixDic() { // TODO Auto-generated constructor stub } public String getPaixing() { return paixing; } public void setPaixing(String paixing) { this.paixing = paixing; } public ArrayList<Integer> getAlr() { return alr; } public void setAlr(ArrayList<Integer> alr) { this.alr = alr; } @Override public String toString() { // TODO Auto-generated method stub return paixing+":"+alr; } }给出一个执行结果:
单顺:[4, 5, 6, 7, 8, 9, 10]
单顺:[8, 9, 10, 11, 12, 13, 14]
炸弹:[]
三条:[]
对子:[]
[火箭->顺子->炸弹->三带->对子->单牌]这样的手牌数为:2
炸弹:[]
三条:[8, 8, 8]
单顺:[9, 10, 11, 12, 13, 14]
对子:[4, 4]
单牌:[5]
单牌:[7]
单牌:[6]
[炸弹->三带->火箭->顺子->对子->个]这样的手牌数为:5
决定选择的方法:
单顺:[4, 5, 6, 7, 8, 9, 10]
单顺:[8, 9, 10, 11, 12, 13, 14]
炸弹:[]
三条:[]
对子:[]