初始目标:
模拟两人诈金花牌,并进行手牌大小判断 来决定输赢(并不包含诈人的游戏过程)
(资料图片)
目标分析:
确定游戏需求:游戏娱乐确定项目应用前景:简单游戏需求,初级学习需求,商业化能力≈0分析项目内容
项目分析:
发牌手牌等级判断等级比较确认输赢
1.每个人 手牌的 标准javaBean包
包括了:
大等级(豹子,同花顺……),小等级(相同大等级内细分的 小等级)
每张手牌的 花色 , 牌面数字
每个人的ID
package Save_Pai;import java.util.Arrays;public class PersonPoker {public int BigLevel;public String SmallLevel;private int PokerColour[];private int PokerNumber[];public int person;public PersonPoker(){}public PersonPoker(int[] pokerColour, int[] pokerNumber) {super();PokerColour = pokerColour;PokerNumber = pokerNumber;}public int[] getPokerColour() {return PokerColour;}public void setPokerColour(int[] pokerColour) {PokerColour = pokerColour;}public int[] getPokerNumber() {return PokerNumber;}public void setPokerNumber(int[] pokerNumber) {PokerNumber = pokerNumber;}@Overridepublic String toString() {return "PersonPoker [PokerColour=" + Arrays.toString(PokerColour) + ", PokerNumber="+ Arrays.toString(PokerNumber) + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + Arrays.hashCode(PokerColour);result = prime * result + Arrays.hashCode(PokerNumber);return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;PersonPoker other = (PersonPoker) obj;if (!Arrays.equals(PokerColour, other.PokerColour))return false;if (!Arrays.equals(PokerNumber, other.PokerNumber))return false;return true;}}
2.主程序分析
游戏不止两个人进行,可以为多人发牌多人发牌前需要得到本局游戏人数确认发牌是否成功
主程序(domain)
package domain;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;import java.util.Scanner;import Fapai.Fapai;import PokerLevel.PokerLevel;import PrintPoker.PrintPoker;import Save_Pai.PersonPoker;public class domain {private static final int BAOZI = 1;public static void main(String[] args) {Fapai t1;Scanner sc = new Scanner(System.in);String ss;System.out.println("开始游戏请输入 Y , 否则输入 N");int Person = 0;while ((ss = sc.next()).equals("Y")) {t1 = new Fapai();System.out.println("请输入参与游戏人数(因牌数限制,人数小于等于17 , 大于1)");sc = new Scanner(System.in);int invol = sc.nextInt();if (!t1.Fp(invol)) {System.out.println("发牌失败,是否重新发牌");System.out.println("重新发牌输入 Y , 否则输入 N");sc = new Scanner(System.in);continue;}for (int i = 0; i < invol; i++) {System.out.println("第" + (i + 1) + "人 牌型:");PrintPoker P = new PrintPoker(t1.p[i]);}for (int i = 0; i < invol; i++) {t1.p[i].BigLevel = new PokerLevel(t1.p[i]).GetBigLevel();if (t1.p[i].BigLevel != 5) {t1.p[i].SmallLevel = new PokerLevel(t1.p[i]).MakeString(0);} else {t1.p[i].SmallLevel = new PokerLevel(t1.p[i]).MakeString(1);}}ArrayListAL1 = new ArrayList<>();for (int i = 0; i < invol; i++) {AL1.add(t1.p[i]);}Collections.sort(AL1, new Comparator() {@Overridepublic int compare(PersonPoker o1, PersonPoker o2) {if (o1.BigLevel != o2.BigLevel) {if (o1.BigLevel > o2.BigLevel)return 1;elsereturn -1;}return o1.SmallLevel.compareTo(o2.SmallLevel);}});int ans = 0;if (AL1.get(0).BigLevel == BAOZI) {for (int i = 1; i < AL1.size(); i++) {int a[] = AL1.get(i).getPokerColour();if (AL1.get(i).SmallLevel.equals("JLM") && a[0] != a[1] && a[1] != a[2] && a[0] != a[2]) {ans = i;break;}}}System.out.println("第 " + AL1.get(ans).person + " 赢了!");System.out.println("\n重新发牌输入 Y , 否则输入 N");sc = new Scanner(System.in);}}}
3.发牌分析:
确认是否发牌输入游戏人数
发牌方式
方式一:直接随机 牌色 和 牌面值,出现重复牌,重新随机方式二:为所有牌确定等级(包括花色 4 * 13 张),随机等级,出现重复等级重新随机方式三:将所有牌的牌色 和 牌面值 放进两个List ,对List进行随机排序,依次取每个人的牌方式四:在方式二的基础上 也是放进List , 对List 进行随机排序, 依次取每个人的牌
发牌方式复杂度和操作难度分析
方式一:人数少时速度较快,人数多时,出现重复牌的概率增加(最坏情况 一直取到重复出现的牌)方式二:速度较第一种略快(但是也会出现方式一的最坏情况),分配等级困难很高,预处理static过程出错不容易查找方式三:static预处理简单,优化取消了重复牌出现的可能,确定等级过程稍显复杂(需要一些小思考)方式四:预处理困难,随机过程内部时间复杂度不确定(感觉挺高),优点是 确定等级的 直接排序过程 得到了优化
发牌:(选择方式三)
package Fapai;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.HashSet;import java.util.List;import java.util.Random;import java.util.Set;import Save_Pai.PersonPoker;public class Fapai {private static final int PersonNumber = 17;public static PersonPoker p[] = new PersonPoker[PersonNumber];public static ArrayListPkColour = new ArrayList<>();public static ArrayListPkNumber = new ArrayList<>();static {int cnt = 0;for (int i = 0; i < 4; i++) {for (int j = 1; j <= 13; j++) {PkColour.add(i);}cnt++;}for (int i = 1; i <= 13; i++) {for (int j = 1; j <= public="" static="" boolean="" int="" new="" if="" num=""> 17 || num <= 1){return false;}else{int cnt = 0;for (int i = 0; i < num; i++) {int PC[] = new int[3];int PN[] = new int[3];for (int j = 0; j < 3; j++) {PC[j] = PkColour.get(cnt);PN[j] = PkNumber.get(cnt++);}//System.out.println(PC[0] + " " + PC[1] + " " + PC[2]);//System.out.println(PN[0] + " " + PN[1] + " " + PN[2]);p[i] = new PersonPoker(PC , PN);p[i].person = i+1;}return true;}}}
4.输出每个人的手牌:
比较简单的对应转换输出,不做详解
package PrintPoker;import Save_Pai.PersonPoker;public class PrintPoker {public PrintPoker(PersonPoker p) {super();OPT(p);}private void OPT(PersonPoker e) {int[] a;int[] b;a = e.getPokerColour();b = e.getPokerNumber();for (int i = 0; i < 3; i++) {OptColour(a[i]);System.out.print(" ");OptNumber(b[i]);if(i != 2)System.out.print(", ");}System.out.println();}private void OptColour(int x) {if(x == 0){System.out.print("方块");} else if(x == 1){System.out.print("梅花");} else if(x == 2){System.out.print("红桃");} else {System.out.print("黑桃");}}private void OptNumber(int x) {if(x == 1){System.out.print("A");} else if(x <= 10){System.out.print(x);} else if(x == 11){System.out.print("J");} else if(x == 12){System.out.print("Q");} else if(x == 13){System.out.print("K");}}}
5.确定发牌等级(最重要的处理步骤):
首先确定手牌的大等级:
豹子 > 同花顺 > 同花 > 顺子 > 对子 > 单牌
特殊牌:三张不同花色的235不做单独考虑,后面出现豹子获胜的人,再特判即可
确定小等级:
最容易的思路就是把同一等级的所有小等级全部按顺序编号,但这违背方法三的初衷(取消复杂的小等级确定过程)
通过思考 除了对子 的小牌等级 比较大小 方式比较特殊,其他的牌均相同
对子:先比较对牌的大小,对子牌相同,比较单牌大小
其他等级:A (1)> K(13) > Q(12) > J(11) > 10 > 9 > 8 > 7 > 6 > 5 > 4 > 3 > 2
因为直接用这种数字比较,大小的概念是很难 确定的,实现起来繁琐冗杂
可以将13个数字(其中1=A,13=K,12=Q,11=J)
变换为:
11312111098765432
ABCDEFGHIJKLM
这种改写方式可以直接将牌的大小 用字符串的 compareTo方法进行比较
对子:只需要先以上面表格的方式作为小等级的前两个字符,其他的不变即可
package PokerLevel;import Save_Pai.PersonPoker;public class PokerLevel {PersonPoker p;private static final int BaoZi = 1;private static final int TongHuaShun = 2;private static final int TongHua = 3;private static final int ShunZi = 4;private static final int DuiZi = 5;private static final int DanZhang = 6;public PokerLevel(PersonPoker p) {super();this.p = p;}public String MakeString(int cek) {char[] a = new char[3];int cnt = 0;char ch = "A";int Number[] = p.getPokerNumber();int CalNum[] = new int[15];for (int i = 0; i < 3; i++) {CalNum[Number[i]]++;}if (cek == 0) {while (CalNum[1] > 0) {a[cnt++] = ch;CalNum[1]--;}for (int i = 13; i > 1; i--) {++ch;while (CalNum[i] > 0) {a[cnt++] = ch;CalNum[i]--;}if (cnt == 3)break;}return new String(a);} else {if (CalNum[1] == 2) {a[0] = a[1] = ch;CalNum[1] = 0;} else {for (int i = 13; i > 1; i--) {++ch;if (CalNum[i] == 2) {a[0] = a[1] = ch;CalNum[i] = 0;break;}}}ch = "A";if(CalNum[1] == 1)a[2] = ch;for(int i = 13 ; i > 1 ; i--){++ch;if(CalNum[i] == 1){a[2] = ch;break;}}return new String(a);}}public int GetBigLevel() {int Colour[] = p.getPokerColour();int Number[] = p.getPokerNumber();int CalCol[] = new int[5];int CalNum[] = new int[15];for (int i = 0; i < 3; i++) {CalCol[Colour[i]]++;}for (int i = 0; i < 3; i++) {CalNum[Number[i]]++;}// 豹子if (isBaoZi(CalNum)) {return BaoZi;}if (isTongHua(CalCol)) {// 同花顺if (isShunZi(CalNum)) {return TongHuaShun;}// 同花return TongHua;}// 顺子if (isShunZi(CalNum)) {return ShunZi;}// 对子if (isDuiZi(CalNum)) {return DuiZi;}// 单牌return DanZhang;}private boolean isDuiZi(int[] a) {for (int i = 1; i <= 1="" if="" return="" private="" boolean="" for="" int="" i="">= 3; i--) {if (a[i] == 1 && a[i - 1] == 1 && a[i - 2] == 1) {return true;}}return false;}private boolean isTongHua(int a[]) {for (int i = 0; i < 4; i++) {if (a[i] == 3)return true;}return false;}private boolean isBaoZi(int a[]) {for (int i = 13; i >= 1; i--) {if (a[i] == 3) {return true;}}return false;}}
回到主程序:
我们将每个人的手牌JavaBean塞到List里,运用Collections工具类,重写实现内部类,进行排序
直接获取第一个人的ID
特判:如果此时获胜者是 豹子 手牌,则在List内遍历是否有牌面为235,且三张牌不同花色 的人,如果找到,更改ans存的ID
输出获胜者ID