深入解析棋牌湖南放炮罚,跑胡子手游后台源码(java版)

最近开发了一款湖南放炮罚的房卡模式带三级分销的手游,现在我就将我开发中的思路给朋友们分享一下。

首先介绍一下棋牌游戏最近的火热度吧。

最近微信群和朋友圈中忽然流行起了一款APP手机棋牌房卡麻将游戏,微信群各种被刷,朋友圈也被各霸了,约战的,晒成绩的,开好房间,约上好友,酣战一场!
这就是“ APP手机棋牌房卡麻将游戏”,一款将传统麻将机搬上智能手机,利用零散闲碎的空余时间与好友来一场说约就约的局的手机游戏。手机房卡麻将”来源于传统桌麻,游戏玩法与桌麻相差不大。玩家无需注册,可以直接微信登陆,方便快捷。登陆后便有一定数量免费房卡可供开房,开房后分享到微信群里,喊上好友输入房间号便可开局了。

说说放炮罚的游戏玩法,这个对理解开发很有作用。

点击链接查看跑胡子规则

下面就具体说说开发这一快吧,这里具体讲讲思路

一,设计数据库

数据库设计这块是根据现有的需求来设计的。比如现在我们是房卡模式,具有回放功能,战绩查询功能,发公告的功能。聊天等这里就可以根据自己的需求去设计。

二,通讯协议的拟定

这里的通讯协议像棋牌手游这种肯定是选用长连接。用soket协议,具体的自己去封装一下,这里不做具体的讲解。

三,创建房间

    /*** 创建房间* @param avatar*/public void CreateRoom(Avatar avatar){ //这里设置房间的创建者是一个全局变量createAvator = avatar;//初始化一个集合用于装在这个房间的玩家VOroomVO.setPlayerList(new ArrayList<AvatarVO>());//这里初始化房间的玩家playerList = new ArrayList<Avatar>();//设置是否是庄家avatar.avatarVO.setMain(true);//这里将房间的信息设置到人员里面去,便于以后的调用avatar.setRoomVO(roomVO);//添加到玩牌的玩家集合中去playerList.add(avatar);roomVO.getPlayerList().add(avatar.avatarVO);}

四,进入房间

   /*** 进入房间,* @param avatar*/public  boolean intoRoom(Avatar avatar){//当玩家的人数等于三的时候就发送消息给该玩家房间人数满了。不能继续加入了if(playerList.size() == 3){try {avatar.getSession().sendMsg(newErrorResponse(ErrorCode.Error_000011));} catch (IOException e) {e.printStackTrace();}return false;}else {//设置后面的加入房间的人都不是庄家因为我们默认是开房的人事庄家avatar.avatarVO.setMain(false);//房间号也放入avatarvo中avatar.avatarVO.setRoomId(roomVO.getRoomId());avatar.setRoomVO(roomVO);//通知房间里面的其他几个玩家noticJoinMess(avatar);playerList.add(avatar);roomVO.getPlayerList().add(avatar.avatarVO);RoomManager.getInstance().addUuidAndRoomId(avatar.avatarVO.getAccount().getUuid(),roomVO.getRoomId());avatar.getSession().sendMsg(new JoinRoomResponse(1, roomVO));try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}return true;}}}

五,检测是否可以开始游戏,退出房间,申请解散房间

这里就自己去想想实现代码了这里占不介绍。

六,游戏准备

当加入房间后我们去判断准备的人是不是三个人都准备了。如果都准备了我们就开始游戏。

七,初始化牌

由于现在我们是湖南的放炮罚。所以我们有八十张牌,

    大的  壹、贰、叁、肆、伍、陆、柒、捌、玖、拾    各四张小的  一、二、三、四、五、六、七、八、九、十    各四张

这里初始化一个全局的数组。size=20的 他的索引就是牌的值,数组对应索引出对应的值就是牌的数量。列如:

//代表的就是 二、二、三、三、三、四、四、四、五、六、七、七、九、九、九、十、叁、叁、叁这些牌
int[] paiArray={0, 2, 3,3, 1, 1, 2, 0, 3, 1, 0, 0,3, 0, 0, 0, 0, 0, 0, 0};

下面就是初始化牌的代码

    /*** 初始化牌*/public void initCard(RoomVO value) {roomVO = value;paiCount = 20;listCard = new ArrayList<Integer>();for (int i = 0; i < paiCount; i++) {for (int k = 0; k < 4; k++) {listCard.add(i);}}for (int i = 0; i < playerList.size(); i++) {playerList.get(i).avatarVO.setPaiArray(new int[2][paiCount]);}// 洗牌shuffleTheCards();// 发牌dealingTheCards();}/*** 随机洗牌*/public void shuffleTheCards() {Collections.shuffle(listCard);Collections.shuffle(listCard);}

当然发牌后就得检查是否有起手胡的情况和是否有提(放炮罚中是提其实就是相当于四川麻将的直杠)的情况了。如果有则给客户端发有胡的消息。或者是杠的消息。客户端操作后调用我们的胡的协议或者杠的协议。

八,出牌

/*** 出牌* * @param avatar* @param cardPoint*/public void putOffCard(Avatar avatar, int cardPoint) {System.err.println("出牌:"+cardPoint);System.err.println("出牌:玩家号"+playerList.indexOf(avatar)+"出牌前旧牌:"+avatar.printPaiString());System.err.println("出牌:玩家号"+playerList.indexOf(avatar)+"出牌前新牌:"+avatar.printNewPaiString());//添加当前的操作for (int i = 0; i < playerList.size(); i++) {playerList.get(i).avatarVO.addOperation(playerList.indexOf(avatar),"chupai",cardPoint);}avatar.avatarVO.setHasMopaiChupai(true);// 修改出牌 摸牌状态// 已经出牌就清除所有的吃,碰,杠,胡的数组clearAvatar();//当前出的牌putOffCardPoint = cardPoint;System.out.println("出牌点数"+putOffCardPoint+"---出牌人索引:"+playerList.indexOf(avatar));//出牌人索引curAvatarIndex = playerList.indexOf(avatar);PlayRecordOperation(curAvatarIndex, cardPoint, 1, -1, null, null);avatar.pullCardFormList(putOffCardPoint);for (int i = 0; i < playerList.size(); i++) {// 不能返回给自己if (i != curAvatarIndex) {playerList.get(i).getSession().sendMsg(new ChuPaiResponse(1, putOffCardPoint,curAvatarIndex));
//               System.out.println("发送打牌消息----"+playerList.get(i).avatarVO.getAccount().getNickname());} else {playerList.get(i).gangIndex.clear();// 每次出牌就先清除缓存里面的可以杠的牌下标}}// 出牌时,房间为可抢杠胡并且有癞子时才检测其他玩家有没胡的情况Avatar ava;StringBuffer sbs = new StringBuffer();boolean checkGang=false;boolean checkPeng=false;boolean checkChi=false;boolean checkHu=false;int chick=0;for (int i = 0; i < playerList.size(); i++) {ava = playerList.get(i);checkGang = ava.checkGang(putOffCardPoint);checkPeng = ava.checkPeng(putOffCardPoint);if(checkGang){chick+=1;}if(checkPeng){chick+=1;}}for (int i = 0; i < playerList.size(); i++) {ava = playerList.get(i);StringBuffer sb = new StringBuffer();ava.chiIndex.clear();ava.biIndex.clear();// 判断吃,碰, 胡 杠的时候需要把以前吃,碰,杠胡的牌踢出再计算checkGang = ava.checkGang(putOffCardPoint);checkPeng = ava.checkPeng(putOffCardPoint);checkHu = ava.checkHu(putOffCardPoint);checkChi =  ava.checkChi(putOffCardPoint);if (checkHu&&(ava.getUuId() != avatar.getUuId())&&!ava.guoHu) {huAvatar.add(ava);// 同时传会杠的牌的点数sb.append("hu:" + putOffCardPoint + ",");}if (checkGang&&(ava.getUuId() != avatar.getUuId())) {gangAvatar.add(ava);System.err.println("打牌有杠 是否是二次杠的值:"+ava.isfirstGang);if(ava.isfirstGang>0){// 同时传会杠的牌的点数sb.append("gang:" + putOffCardPoint + ","+"ergang"+",");}else{// 同时传会杠的牌的点数sb.append("gang:" + putOffCardPoint + ","+""+",");}}if (checkPeng&&!checkGang&&(ava.getUuId() != avatar.getUuId())&&!ava.guoHu) {penAvatar.add(ava);sb.append("peng:" + curAvatarIndex + ":"+ putOffCardPoint + ",");}//放炮罚。。。检查吃只有下一家才能吃if ( roomVO.getRoomType() == 4 &&checkChi&& getNextAvatarIndex() ==i&&!checkGang&&!checkPeng&&!ava.guoHu&&chick==0){chiAvatar.add(ava);sb.append("chi:"+curAvatarIndex+":"+ putOffCardPoint + ",");}else{ava.chiIndex.clear();ava.biIndex.clear();}if (sb.length() > 1) {/** try { Thread.sleep(300); } catch* (InterruptedException e) { e.printStackTrace(); }*/try { Thread.sleep(2000); } catch(InterruptedException e) { e.printStackTrace(); }sbs.append(sb);if(chiAvatar.size()>0&&!sb.toString().contains("gang")&&!sb.toString().contains("peng")&&!sb.toString().contains("hu")&&ava.chiIndex.size()>0){HashMap<String, Object> map = new HashMap<>();System.out.println("打牌:吃的组合:"+ava.chiIndex);map.put("chiIndexList", ava.chiIndex);ava.getSession().sendMsg(new ReturnInfoResponse(1, sb.toString(),map));System.out.println("打牌:有吃的情况下返回给前段的数据-------------"+sb+map);}else {ava.getSession().sendMsg(new ReturnInfoResponse(1, sb.toString()));System.out.println("打牌:有碰胡杠的情况下返回给前段的数据----------"+sb);}// responseMsg = new ReturnInfoResponse(1,// sb.toString());// lastAvtar = ava;ava.chiIndex.clear();ava.biIndex.clear();}}System.err.println("出牌:玩家号"+playerList.indexOf(avatar)+"出牌后旧牌:"+avatar.printPaiString());System.err.println("出牌:玩家号"+playerList.indexOf(avatar)+"出牌后新牌:"+avatar.printNewPaiString());// 如果没有吃,碰,杠,胡的情况,则下家自动摸牌String string = new String(sbs);if(string.contains("hu")||(string.contains("gang")&&!string.contains("ergang"))||string.contains("peng")||string.contains("chi")||string.contains("zjHu")){System.out.println("打牌:有胡或碰或吃的时候不调用自动摸牌");}else {// 出牌信息放入到缓存中,掉线重连的时候,返回房间信息需要
//              avatar.avatarVO.updateChupais(cardPoint);if(string.contains("ergang")){try { Thread.sleep(2000); } catch(InterruptedException e) { e.printStackTrace(); }}else {avatar.avatarVO.addChupais(cardPoint,playerList.indexOf(avatar));}try { Thread.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); }System.out.println("打牌:调用自动摸牌");chuPaiCallBack();}}

代码有点乱说说思路吧:
1,首先出牌了就清除以前的用于装吃碰杠胡的玩家的信息。
2,判断出的这张牌是否有胡,碰,杠,吃的情况如果有就给相应的玩家发送消息。让玩家操作。
3,如果没有就自己调用下家自动摸牌的方法。下家自动摸牌。当然这里必须清除当前操作的玩家的索引和下家玩家的索引。
4,当判断到有胡,碰,杠,吃的情况后向客户端发送消息,等待客户端做操作。他可以选择胡,碰,杠,吃,和放弃的操作。

九,摸牌

    /*** 摸牌***/public void pickCard() {clearAvatar();// 摸牌pickAvatarIndex = getNextAvatarIndex();// pickAvatarIndex = nextIndex;// 本次摸得牌点数,下一张牌的点数,及本次摸的牌点数int tempPoint = getNextCardPoint();System.out.println("摸牌:"+tempPoint+"----上一家出牌"+putOffCardPoint+"--摸牌人索引:"+pickAvatarIndex);//添加当前的操作断线重连用的数据for (int i = 0; i < playerList.size(); i++) {playerList.get(i).avatarVO.addOperation(pickAvatarIndex,"mopai",tempPoint);}if (tempPoint != -1) {// 回放记录PlayRecordOperation(pickAvatarIndex, tempPoint, 2, -1, null, null);currentCardPoint = tempPoint;Avatar avatar = playerList.get(pickAvatarIndex);System.err.println("摸牌:玩家号"+playerList.indexOf(avatar)+"摸牌前旧牌:"+avatar.printPaiString());System.err.println("摸牌:玩家号"+playerList.indexOf(avatar)+"摸牌前新牌:"+avatar.printNewPaiString());avatar.avatarVO.setHasMopaiChupai(true);// 修改出牌 摸牌状态avatar.qiangHu = true;avatar.canHu = true;avatar.iszjPeng = false;// 摸起来也要判断是否可以杠,胡boolean checkPeng = avatar.checkPeng(tempPoint);boolean checkSelfGang = avatar.checkGang(tempPoint);boolean checkHu = avatar.checkHu(tempPoint);if(checkPeng){}else {avatar.putCardInList(tempPoint);}//移除摸到的牌StringBuffer sb = new StringBuffer();if(checkPeng||checkSelfGang||checkHu){if (checkHu&&!avatar.guoHu) {avatar.iszjHu=true;huAvatar.add(avatar);sb.append("zjHu:" + pickAvatarIndex + ":"+ tempPoint + ",");}if (checkSelfGang) {avatar.iszjGang=true;gangAvatar.add(avatar);System.err.println("摸牌有杠 是否是二次杠的值:"+avatar.isfirstGang);if(avatar.isfirstGang>0){//证明已经杠了一次sb.append("zjErGang");for (int i : avatar.gangIndex) {sb.append(":" + i);}sb.append(",");sb.append("zjGang");for (int i : avatar.gangIndex) {sb.append(":" + i);}sb.append(",");}else {sb.append("zjGang");for (int i : avatar.gangIndex) {sb.append(":" + i);}sb.append(",");}//                   avatar.gangIndex.clear();//9-18出牌了才清楚(在杠时断线重连后需要这里面的数据)}if (checkPeng&&!checkSelfGang) {avatar.setIszjPeng(true);penAvatar.add(avatar);sb.append("zjPeng:" + pickAvatarIndex + ":"+ tempPoint + ",");}if (sb.length() > 2) {if(!sb.toString().contains("zjHu")&&sb.toString().contains("zjErGang")){System.out.println("自己摸牌摸到有二次的杠牌发送消息:"+sb.toString());System.out.println("自己摸牌摸到有二次的杠牌调用下家自动摸牌");try { Thread.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); }avatar.getSession().sendMsg(new ReturnInfoResponse(1, sb.toString()));//有二次杠的时候调用下家自动摸牌System.out.println("自己摸牌摸到有二次的杠牌调用下家自动摸牌");try { Thread.sleep(2000); } catch(InterruptedException e) { e.printStackTrace(); }chuPaiCallBack();}else {System.out.println("摸牌:有胡碰杠的情况发送消息:"+sb.toString());avatar.getSession().sendMsg(new ReturnInfoResponse(1, sb.toString()));}}System.err.println("摸牌:玩家号"+playerList.indexOf(avatar)+"摸牌后旧牌:"+avatar.printPaiString());System.err.println("摸牌:玩家号"+playerList.indexOf(avatar)+"摸牌后新牌:"+avatar.printNewPaiString());}else{avatar.getSession().sendMsg(new PickCardResponse(1, tempPoint));System.out.println("摸牌:没有胡碰杠的情况发送消息:"+tempPoint);for (int i = 0; i < playerList.size(); i++) {if (i != pickAvatarIndex) {playerList.get(i).getSession().sendMsg(new OtherPickCardResponse(1,pickAvatarIndex));System.out.println("摸牌:没有胡碰杠的情况循环提示其他用户消息:"+pickAvatarIndex);} else {playerList.get(i).gangIndex.clear();// 每次摸牌就先清除缓存里面的可以杠的牌下标}}}} else {//黄庄int totalCount = roomVO.getRoundNumber();int useCount = RoomManager.getInstance().getRoom(roomVO.getRoomId()).getCount();if (roomVO.getCurrentRound()==1) {// 第一局结束扣房卡deductRoomCard();}// System.out.println("流局");PlayRecordOperation(pickAvatarIndex, -1, 9, -1, null, null);// 流局处理,直接算分HashMap<String, Object> map = new HashMap<>();//获取到底牌ArrayList<Object> diPaiList = new ArrayList<>();for (int i = 0; i < 20; i++) {int nextCardPoint = getNextCardPoint();if(nextCardPoint!=-1){diPaiList.add(nextCardPoint);}}//          if((playerList.get(0).huInterestCont>=playerList.get(0).getRoomVO().getToCount()*100)||(playerList.get(1).huInterestCont>=playerList.get(1).getRoomVO().getToCount()*100)||(playerList.get(2).huInterestCont>=playerList.get(2).getRoomVO().getToCount()*100)){//牌局结束if((playerList.get(0).huInterestCont>=100)||(playerList.get(1).huInterestCont>=100)||(playerList.get(2).huInterestCont>=100)){//牌局结束ArrayList<Object> arrayList = new ArrayList<>();//获取三个玩家的最后得到的胡息数playerList.get(0).huInterest=(playerList.get(0).huInterest-playerList.get(1).huInterest)+(playerList.get(0).huInterest-playerList.get(2).huInterest);playerList.get(1).huInterest=(playerList.get(1).huInterest-playerList.get(0).huInterest)+(playerList.get(1).huInterest-playerList.get(2).huInterest);playerList.get(2).huInterest=(playerList.get(2).huInterest-playerList.get(1).huInterest)+(playerList.get(2).huInterest-playerList.get(1).huInterest);for (int i = 0; i <playerList.size(); i++) {//当前分数加入总胡息数playerList.get(i).huInterestCont+= playerList.get(i).huInterest;HashMap<String, Object> retmap = new HashMap<>();retmap.put("thishuInterest", playerList.get(i).huInterest);retmap.put("roomhuInterest", playerList.get(i).huInterestCont);retmap.put("fowling", 0);retmap.put("thisintegral", playerList.get(i).huInterest);arrayList.add(retmap);}for (int i = 0; i < playerList.size(); i++) {map.put("huIndex", -1);map.put("faPaoIndex", -1);map.put("arrayList", arrayList);map.put("diPai", diPaiList);playerList.get(i).getSession().sendMsg(new HuPaiAllResponse(1,JsonUtilTool.toJson(map)));//发送消息之后清除}// 游戏回放
//              PlayRecordOperation(playerList.indexOf(avatar), cardIndex,
//                      playRecordType, -1, null, null);addStandings();// 4局完成之后解散房间//销毁RoomLogic roomLogic = RoomManager.getInstance().getRoom(roomVO.getRoomId());roomLogic.destoryRoomLogic();roomLogic = null;}else {ArrayList<Object> arrayList = new ArrayList<>();//获取三个玩家的最后得到的胡息数for (int i = 0; i <playerList.size(); i++) {HashMap<String, Object> retmap = new HashMap<>();retmap.put("thishuInterest", playerList.get(i).huInterest);retmap.put("roomhuInterest", playerList.get(i).huInterestCont);retmap.put("fowling", 0);retmap.put("thisintegral", playerList.get(i).huInterest);arrayList.add(retmap);}addStandings();//当别人放炮的时候for (int i = 0; i < playerList.size(); i++) {map.put("huIndex", -1);map.put("faPaoIndex", -1);map.put("arrayList", arrayList);map.put("diPai", diPaiList);playerList.get(i).getSession().sendMsg(new HuPaiResponse(1,JsonUtilTool.toJson(map)));//发送消息之后清除playerList.get(i).huInterest=0;playerList.get(i).HuCardsMultiples=1;playerList.get(i).HuCardsScore=0;//修改庄家为下一家if (playerList.get(i).avatarVO.isMain()) {playerList.get(i).avatarVO.setMain(false);if(i==0){bankerAvatar = playerList.get(1);playerList.get(1).avatarVO.setMain(true);}if(i==1){bankerAvatar = playerList.get(2);playerList.get(2).avatarVO.setMain(true);}if(i==2){bankerAvatar = playerList.get(0);playerList.get(0).avatarVO.setMain(true);}} }// 游戏回放PlayRecordOperation(playerList.indexOf(avatar), cardIndex,}singleOver = true;// 10-11新增}}

同样的总结一下思路吧
1,判断摸到的这个牌,和自己的牌做对比是否可以碰,杠,胡和出牌时一样的判断方法,只不过这里是只判断自己。
2,如果有碰,杠,胡那么向客户端发送消息。由客户端去操作。并向我返回消息。
3,如果没有那么就将自己摸到的牌打出去。
4,如果摸牌的时候,发现底牌没有可以摸的了。那么就是黄庄了。调用结算的方法。结算。

十,判断吃

 /*** 檢測是否可以吃* @param cardIndex* @return*/public boolean checkChi(int cardIndex){boolean flag = false;//system.out.println("判断吃否可以吃牌-----cardIndex:"+cardIndex);/*** 这里检测吃的时候需要踢出掉碰 杠了的牌*****/int []  cardList = avatarVO.getChickChiArray();for (int i = 0; i < cardList.length; i++) {if(cardList[i]==3){knack++;cardList[i]=0;}if(cardList[i]==4){knack++;cardList[i]=0;}}//小1                到                   小10if(cardIndex>=0  && cardIndex <=9){if(cardIndex == 0 && cardList[1] >=1 && cardList[2] >=1 ){flag = true;putChiIndex(0,1,2);}if (cardIndex == 0 &&(cardList[10] >=2)) {flag = true;putChiIndex(0,10,10);} if(cardIndex == 1 && cardList[0] >=1 && cardList[2] >=1){flag = true;putChiIndex(1,0,2);} if (cardIndex == 1 &&cardList[3] >=1 && cardList[2] >=1) {flag = true;putChiIndex(1,3,2);} if (cardIndex == 1 &&cardList[11] >=2) {flag = true;putChiIndex(1,11,11);} if(cardIndex ==9 &&cardList[8] >=1 && cardList[7] >=1){flag = true;putChiIndex(9,8,7);} if(cardIndex ==9 &&cardList[19] >=2){flag = true;putChiIndex(cardIndex,cardList[9],cardList[9]);} if(cardIndex ==8 && cardList[9] >=1 && cardList[7] >=1){flag = true;putChiIndex(8,9,7);} if(cardIndex ==8 && cardList[6] >=1 && cardList[7] >=1){flag = true;putChiIndex(8,6,7);} if(cardIndex ==8 &&cardList[18] >=2) {flag = true;putChiIndex(8,18,18);} if(cardIndex==1&&cardList[6] >=1&&cardList[9] >=1){flag = true;putChiIndex(1,6,9);} if(cardIndex==6&&cardList[1] >=1&&cardList[9] >=1){flag = true;putChiIndex(6,1,9);} if(cardIndex==9&&cardList[1] >=1&&cardList[6] >=1){flag = true;putChiIndex(9,1,6);} if(cardIndex>=2&&cardIndex<=7){//2 到  7if(cardList[cardIndex-1] >=1 && cardList[cardIndex+1] >=1){flag = true;putChiIndex(cardIndex,cardIndex-1,cardIndex+1);} if (cardList[cardIndex-1] >=1 && cardList[cardIndex-2] >=1) {flag = true; putChiIndex(cardIndex,cardIndex-1,cardIndex-2);} if (cardList[cardIndex+1] >=1 && cardList[cardIndex+2] >=1){flag = true; putChiIndex(cardIndex,cardIndex+1,cardIndex+2);} if ((cardList[cardIndex+10] >=2)){flag = true; putChiIndex(cardIndex,cardIndex+10,cardIndex+10);}if ((cardList[cardIndex+10] >=1&&cardList[cardIndex]>=1)){flag = true; putChiIndex(cardIndex,cardIndex,cardIndex+10);}}}else if (cardIndex>=10  && cardIndex <=19) {if(cardIndex == 10 && cardList[11] >=1 && cardList[12] >=1 ){flag = true;putChiIndex(10,11,12);}if (cardIndex == 10 &&(cardList[0] >=2)) {flag = true;putChiIndex(10,0,0);} if(cardIndex == 11 && cardList[10] >=1 && cardList[12] >=1){flag = true;putChiIndex(11,10,12);} if (cardIndex == 11 &&cardList[13] >=1 && cardList[12] >=1) {flag = true;putChiIndex(11,13,12);} if (cardIndex == 11 &&cardList[1] >=2) {flag = true;putChiIndex(11,1,1);} if(cardIndex ==19 &&cardList[18] >=1 && cardList[17] >=1){flag = true;putChiIndex(19,18,17);} if(cardIndex ==19 &&cardList[9] >=2){flag = true;putChiIndex(19,9,9);} if(cardIndex ==18 && cardList[19] >=1 && cardList[17] >=1){flag = true;putChiIndex(18,19,17);} if(cardIndex ==18 && cardList[16] >=1 && cardList[17] >=1){flag = true;putChiIndex(18,16,17);} if(cardIndex ==18 &&cardList[8] >=2) {flag = true;putChiIndex(18,8,8);} if(cardIndex==11&&cardList[16] >=1&&cardList[19] >=1){flag = true;putChiIndex(11,16,19);} if(cardIndex==16&&cardList[11] >=1&&cardList[19] >=1){flag = true;putChiIndex(16,11,19);} if(cardIndex==19&&cardList[11] >=1&&cardList[16] >=1){flag = true;putChiIndex(19,11,16);} if(cardIndex>=12&&cardIndex<=17){//2 到  7if(cardList[cardIndex-1] >=1 && cardList[cardIndex+1] >=1){flag = true;putChiIndex(cardIndex,cardIndex-1,cardIndex+1);} if (cardList[cardIndex-1] >=1 && cardList[cardIndex-2] >=1) {flag = true; putChiIndex(cardIndex,cardIndex-1,cardIndex-2);} if (cardList[cardIndex+1] >=1 && cardList[cardIndex+2] >=1){flag = true; putChiIndex(cardIndex,cardIndex+1,cardIndex+2);} if ((cardList[cardIndex-10] >=2)){flag = true; putChiIndex(cardIndex,cardIndex-10,cardIndex-10);}if ((cardList[cardIndex-10] >=1&&cardList[cardIndex]>=1)){flag = true; putChiIndex(cardIndex,cardIndex,cardIndex-10);}}}else {System.out.println("判断吃的时候索引越界:传入的牌:"+cardIndex);}//检查吃的时候如果有吃。那么看手里的牌是否有这个组合。如果有,那么是否可以比牌。有比才可以吃。if(flag&&cardList[cardIndex]>=1&&chiIndex.size()>0){int kk =0;for (int i = 0; i < chiIndex.size(); i++) {Map<String, Object> chiMap = chiIndex.get(i);Integer chipai = (Integer) chiMap.get("chipai");Integer chipai1 = (Integer) chiMap.get("chipai1");Integer chipai2 = (Integer) chiMap.get("chipai2");boolean bo1=(chipai==chipai1);boolean bo2=(chipai==chipai2);boolean bo3=(chipai1==chipai2);boolean bo=(chipai==chipai1?true:chipai==chipai2?true:chipai1==chipai2?true:false);if(cardList[chipai]>=1&&cardList[chipai1]>=1&&cardList[chipai2]>=1&&!bo){kk++;}if (bo&&bo1&&cardList[chipai]>=1&&cardList[chipai2]>=1) {kk++;}if (bo&&bo2&&cardList[chipai]>=1&&cardList[chipai1]>=1) {kk++;}if (bo&&bo3&&cardList[chipai]>=1&&cardList[chipai2]>=1) {kk++;} }if(kk<2){flag=false; }}return flag;}

总结一下吧。上面这个代码写的 不好,但是可以解决吃的问题。
大概的思路就是。用于判断吃的数组,是手牌。是排除了碰杠的情况下的数据。然后用写死的方式去判断一些特殊的组合。通用的组合处理通用的吃得数据。

十一,检查碰

  /*** 檢測是否可以碰 大于等于2张可以碰* @param cardIndex* @return*/public boolean checkPeng(int cardIndex){boolean flag = false;if(avatarVO.getPaiArray()[0][cardIndex] == 2 ){if(resultRelation.get(1) == null ){flag = true;}else{String strs [] = resultRelation.get(1).split(",");for (int i = 0; i < strs.length; i++) {if(strs[i].equals(cardIndex+"")){flag  =  false;i = strs.length;}else{flag  =  true;}}}}return flag;}

总结一下。碰的话这里就简单很多了。就是判断我的手牌里面的牌的张数是否大于2大于则可以碰

十二,检查是否可以跑,或者提(就是四川麻将杠的意思)

    /*** 檢測是否可以杠别人出的牌/此牌对应的下标不为1(碰过了的牌)* @param cardIndex* @return*/public boolean checkGang(int cardIndex){boolean flag = false;gangIndex.clear();//每次出牌就先清除缓存里面的可以杠的牌下标if(avatarVO.getPaiArray()[0][cardIndex] == 3){gangIndex.add(cardIndex);flag = true;}return flag;}

检查是否有杠就是检查是否手牌的某一张牌牌的数量为3这里想一下就很容易理解了。但是有个情况是你自己碰 了的牌。再次摸到一张这时也是需要检查的。

十三,检查胡

这里在放炮罚中的胡牌算法。我这是我自己写的一个逻辑。还是有一定的缺陷。但是一般情况写还是可以检测到的。代码如下:

    /*** 检查是否胡牌* @param tempPoint* @return*/public boolean checkHu(int tempPoint) {if(this.huInterest>=15){//当胡息数大于15的时候再判断System.out.println("当前胡息数__"+this.huInterest);putCardInListAsChi(tempPoint);int[] atmp1=new int[20];System.arraycopy(avatarVO.getChickChiArray(), 0, atmp1, 0, 20);if(HuCardsAlgorithm(atmp1,avatarVO.getPaiArray()[0])){return true;}pullCardFormListAsChi(tempPoint);}return false;}public void printHuXi(String type,int i) {System.err.println(type+"后:"+"当前玩家"+i+"胡息数__:"+this.huInterest);}   public boolean HuCardsAlgorithm(int[] paiArray, int[] js) {
//        int[] paiArray={0, 2, 3,3, 1, 1, 2, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};this.thisknack=0;for (int i = 0; i < paiArray.length; i++) {if(paiArray[i]==4){//当牌里面有跑的时候paiArray[i]=0;this.thisknack++;}if(paiArray[i]==3){//当牌里面有碰paiArray[i]=0;this.thisknack++;}}for (int i = 0; i < paiArray.length; i++) {//当时大小搭的时候也要去除if(i<=9){if (paiArray[i] == 1 &&(paiArray[i+10]==2)) {paiArray[i]=0;paiArray[i+10]=0;this.thisknack++;}}else {if (paiArray[i] == 1 &&(paiArray[i-10]==2)) {paiArray[i]=0;paiArray[i-10]=0;this.thisknack++;}}}//当是2,7,10的时候也要去除for (int k = 0; k < 2; k++) {if (paiArray[1] >= 1 &&paiArray[6] >= 1&&paiArray[9] >= 1) {paiArray[1]--;paiArray[6]--;paiArray[9]--;this.thisknack++;}if (paiArray[11] >= 1 &&paiArray[16] >= 1&&paiArray[19] >= 1) {paiArray[11]--;paiArray[16]--;paiArray[19]--;this.thisknack++;}}for (int i = 0; i < paiArray.length; i++) {if(this.isfirstGang>0){//如果有提牌或者跑牌那么就判断是否有一对。一对也是一方门子int  ii=0;if(paiArray[i]==2&&ii!=1){//当牌里面有碰这里判断只能去掉一对paiArray[i]=0;this.thisknack++;ii=1;}}}int atmp1[] = new int[10];int atmp2[] = new int[10];System.arraycopy(paiArray, 0, atmp1, 0, 10);System.arraycopy(paiArray, 10, atmp2, 0, 10);boolean fitThreePairs1 = fitThreePairs(atmp1);boolean fitThreePairs2 = fitThreePairs(atmp2);System.out.println("胡牌检测时thisknack="+thisknack+"并且knack="+this.knack);if(fitThreePairs1&&fitThreePairs2){System.out.println("恭喜!!胡牌");int kk=0;kk+=js[1];  kk+=js[6];  kk+=js[9];  kk+=js[11]; kk+=js[16]; kk+=js[19]; if(kk==1){//只有一张红字的牌HuCardsMultiples=HuCardsMultiples*2;}if(kk>=10&&kk<=12){HuCardsMultiples=HuCardsMultiples*2;}if(kk>=13){HuCardsScore=100;}if(kk==0){//乌胡HuCardsScore=100;}if(js[1]==3||js[6]==3||js[9]==3||js[11]==3||js[16]==3||js[19]==3){//三张一样的红字HuCardsMultiples=HuCardsMultiples*2;}if(huInterest==30){HuCardsScore=100;}if(huInterest==20){HuCardsMultiples=HuCardsMultiples*2;}if(iszjHu){HuCardsMultiples=HuCardsMultiples*2;}
//          }return true;}else{System.out.println("继续努力"+"门子:"+(thisknack));return false;}}public boolean fitThreePairs(int[] cardsNoPair){int size = cardsNoPair.length;for (int i = 0; i < size - 2; i++){if (cardsNoPair[i] == 0){continue;}if (cardsNoPair[i] == 3 || cardsNoPair[i] == 4){cardsNoPair[i] -= 3;}if (cardsNoPair[i] == 2){cardsNoPair[i] -= 2;cardsNoPair[i + 1] -= 2;cardsNoPair[i + 2] -= 2;if(cardsNoPair[i]>=0&&cardsNoPair[i + 1]>=0&&cardsNoPair[i + 2]>=0){this.thisknack+=2;}}if (cardsNoPair[i] == 1){cardsNoPair[i]--;cardsNoPair[i + 1]--;cardsNoPair[i + 2]--;if(cardsNoPair[i]>=0&&cardsNoPair[i + 1]>=0&&cardsNoPair[i + 2]>=0){this.thisknack+=1;}}}// 剩下的牌如果存在必须为3个相同的组合if (cardsNoPair[size - 2] == 3){cardsNoPair[size - 2] -= 3;}if (cardsNoPair[size - 1] == 3){cardsNoPair[size - 1] -= 3;}// 胡牌条件是恰好全0for (int i = 0; i < size; i++){if (cardsNoPair[i] != 0){return false;}}return true;}

说一下思路吧
1,首先去除手牌里面的跑的牌,杠的牌,大小搭的牌。
2,判断是否有杠,如果有杠那么可以去除一对牌。因为在放炮罚中有杠一对牌是可以当成一个门子的。
3,将手牌分成两个数组。一个数组装小的一到十一个数组装大的一到十
4,分别判断小的,和大的在去除了一句话后。是否数组里面全都是0。
5,如果全是0那么就是证明是胡了。胡的算法在网上搜索到时要组成七方门子。
好了就说到这里吧。记录一下我为这个麻将游戏而失去的青春岁月。

深入解析棋牌湖南放炮罚,跑胡子手游源码(java版)相关推荐

  1. Spark3.0发布了,代码拉过来,打个包,跑起来!| 附源码编译

    作者 | 敏叔V587 责编 | 徐威龙 封图| CSDN 下载于视觉中国 Spark3.0已经发布有一阵子了,官方发布了预览版,带来了一大波更新,对于我们程序员来说,首先当然是代码拉过来,打个包,跑 ...

  2. 今天的西红柿就跑了的P8U8源码

    今天的西红柿就跑了的P8U8源码,我听了高兴得跳了起来,轰的一声飞船起飞了,我不想当云,西红柿不顾自己的安危又跑回去救玉米粒,西红柿圆圆的,啪我掉在地上,我是来接你去月球上去的P8U8源码,可是,我慢 ...

  3. Spark 3.0 发布了,代码拉过来,打个包,跑起来!| 附源码编译

    作者 | 敏叔V587 责编 | 徐威龙 封图| CSDN 下载于视觉中国 Spark3.0已经发布有一阵子了,官方发布了预览版,带来了一大波更新,对于我们程序员来说,首先当然是代码拉过来,打个包,跑 ...

  4. Spring源码深度解析(郝佳)-学习-Spring消息-整合RabbitMQ及源码解析

      我们经常在Spring项目中或者Spring Boot项目中使用RabbitMQ,一般使用的时候,己经由前人将配置配置好了,我们只需要写一个注解或者调用一个消息发送或者接收消息的监听器即可,但是底 ...

  5. 麻将服务端架设linux,湖南房卡麻将客户端/服务器端完整源码及编译教程

    客户端源码是基于cocos2d-x 3.10版本开发的.代码完整可编译.本人在WINDOWS平台下成功编译了android包并正常运行.源码里面也有服务器的源码(C++),经过再次鉴定应该是配套的,服 ...

  6. 中小型手机棋牌网络游戏服务端架构设计(带源码)

    承接自己<中小型棋牌类网络游戏服务端架构>博文,用Golang实现基础架构逻辑后,准备再次谈谈我的想法. 已实现的逻辑与前文描述有几点不同: Gateway更名为Proxy,DBProxy ...

  7. docker命令行解析以及如何向服务器端发送请求(docker源码学习一)

    最近在看doccker的源码,最新的master分支(估计是1.12.4,因为最新的release是1.12.3)命令行解析全部都使用了第3方的包https://github.com/spf13/co ...

  8. 如何使用mp4v2解析mp4文件,抽取音视频数据帧【源码】【mp4】【NVR】

    前言: mp4文件目前已经成为了流媒体音视频行业的通用标准文件格式,它是基于mov格式基础上演变来的,特别适合多平台播放,录制一次,多个平台都可使用.但是,由于mp4格式相对比较复杂,直到mp4v2这 ...

  9. 人体解析任务 和 Look into Person数据集 (附源码分享)

    人体解析任务 人体解析(human parsing),属于语义分割任务的子任务,旨在对人类图像进行像素级的是细粒度分割(例如,划分出身体部位和服装).根据不同的场景,又可以分为单人人体解析(singl ...

最新文章

  1. 卡尔曼滤波对gps轨迹数据清洗_卡尔曼滤波:从入门到精通
  2. Linux下安装jdk(xxx.rpm,非xxx.tar.gz,请注意!)过程
  3. linux 常见服务端口
  4. IDEA出现错误:找不到或无法加载主类 io.renren.RenrenApplication
  5. VTK:Shaders之BozoShaderDemo
  6. c++ string分割字符串split_python 字符串和文本处理
  7. python计算在月球的体重_NumPy-快速处理数据--矩阵运算
  8. 备份redis服务并ftp上传(shell)
  9. 小程序已成BAT争锋新战场
  10. 【语音识别】语音端点检测及Python实现
  11. 旷视天元开源图片对比工具 MegSpot,助力图像算法研发
  12. java 动态性之反射机制 详解 案例,一起来聊聊Synchronized底层实现原理
  13. Java模拟猜数字小游戏,有次数限制,并且输出猜测次数。
  14. 爱可信携手Marvell展示爱可信Linux平台
  15. File和MultipartFile互转
  16. 基于灰色模型的端口短信预测和垃圾短信治理研究
  17. Matlab绘制特殊图形------散点图
  18. 【超融合】818超融合发展经历了哪几个阶段!
  19. 华北电大学计算机考研资料汇总
  20. pytorch模型推理提速

热门文章

  1. IT业9大最糟糕CEO决策(转载)
  2. 启动IDEA都会打开Licenses激活弹窗
  3. linux c 获取进程p id,详解Linux获取线程的PID(TID、LWP)的几种方式
  4. Unity Shader入门精要 第2章 读书笔记
  5. 如何清除计算机搜索框内的搜索历史记录,如何清除搜索框中的网站访问历史记录...
  6. 嵌入式编程与软件编程思想不同浅见
  7. 利用QQ群推广网站的经验分享
  8. k8s健康检查(七)--技术流ken
  9. 经典文学之三:鲁迅·故乡
  10. 基于ssm企业后勤订餐管理系统的设计与实现-计算机毕业设计源码+LW文档