您的位置:首页 > 其它

斗地主手牌最少手数的搜索

2016-05-12 22:20 866 查看
基本思路:

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]

炸弹:[]

三条:[]

对子:[]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: