一、引言
棋牌游戏中的斗牛,是一种流行的牌类游戏,主要流行于中国。游戏中通常由2到6名玩家参与,使用一副去掉大小王的52张扑克牌。游戏的目标是通过组合手中的牌来赢得更多的分数,或者通过策略和技巧来阻止对手赢得分数。斗牛也被称为“牛牛”,在不同的地区可能会有不同的玩法和规则。
二、基本规则
1. **牌型组合**:玩家需要将得到的五张牌进行三二组合,即其中一组为任意的三张牌,需组成的点数为10的倍数(花牌K、Q、J点数记为10,其余牌的点数为牌的数字大小)如果没有就记为0也就是没牛,最后比较剩下的两张相加的点数的个位数,如4+9记为牛一,8+7记为牛五,4+6记为牛牛(即两张牌点数相加等于10的倍数)等。
2. **牌型大小**:牌型的大小顺序通常是比点数大小,如没牛<牛1<牛2<牛3<牛4<牛5<牛6<牛7<牛8<牛9<牛牛。有的玩法中,特定的牌型(如炸弹牛,五小牛,五金牛)会大于普通的牛牛。如果玩家点数相同就比较手上五张牌中最大的那张牌的大小,如K>Q>J等,如果牌的数值大小相同就比较花色大小(黑桃大于红桃大于梅花大于方块)。
3. **游戏过程**:游戏开始时,庄家洗牌并发牌给所有玩家五张牌,包括自己。玩家根据自己的牌决定是否叫牌或放弃。叫牌的玩家需要下注,然后所有叫牌的玩家亮牌,比较牌型大小。牌型最大的玩家获得胜利,庄家需要根据游戏规则向获胜玩家支付相应的筹码。如果庄家的牌型最大,则其他玩家向庄家支付筹码。游戏结束后,庄家可以决定是否继续担任庄家,或者轮换其他玩家担任庄家。
三、JAVA代码实现
首先设置一个二维数组存储牌型信息
int[][] poker = new int[14][4];
二维系数表示牌型数值大小,一维系数表示牌型花色
发牌
设计一个随机数从牌库中随机抽取
public int number() {
Random random = new Random();
int index = 0;//记录牌数
while (index < 52) {
int a, b;
a = random.nextInt(1, 14);//随机数
b = random.nextInt(0, 4);
if (poker[a][b] == 0) {//判断这张牌是否已经出现了,每张牌只能出现一次
poker[a][b] = 1;//设置状态为1
return a * 10 + b;//返回值设置为三位数,用来存储牌的信息,前两位表示牌的数字大小,个位数表示牌的花色,利于后续牌的大小比较
}
index++;
}
System.out.println("牌库见底");//所有牌的状态为1证明52张牌全部发完
return 0;
}
返回值设置为三位数,用来存储牌的信息,前两位表示牌的数字大小,个位数表示牌的花色,利于后续牌的大小直接比较
然后随机抽取五张牌,并输出牌型
public int[] deal() {//随机发牌五张
int[] num = new int[5];
for (int i = 0; i < 5; i++) {//调用父类随机抽取的牌
num[i] = super.number();
}
System.out.println("你的手牌为:");
for (int i = 0; i < 5; i++) {
int color = num[i] % 10;//取余数代表花色
int number = num[i] / 10;//代表牌的数值
if (color == 0) {
if (number == 1) {
System.out.print("方块" + "A\t");
} else if (number == 11) {
System.out.print("方块" + "J\t");
} else if (number == 12) {
System.out.print("方块" + "Q\t");
} else if (number == 13) {
System.out.print("方块" + "K\t");
} else System.out.print("方块" + number + "\t");
} else if (color == 1) {
if (number == 1) {
System.out.print("梅花" + "A\t");
} else if (number == 11) {
System.out.print("梅花" + "J\t");
} else if (number == 12) {
System.out.print("梅花" + "Q\t");
} else if (number == 13) {
System.out.print("梅花" + "K\t");
} else System.out.print("梅花" + number + "\t");
} else if (color == 2) {
if (number == 1) {
System.out.print("红桃" + "A\t");
} else if (number == 11) {
System.out.print("红桃" + "J\t");
} else if (number == 12) {
System.out.print("红桃" + "Q\t");
} else if (number == 13) {
System.out.print("红桃" + "K\t");
} else System.out.print("红桃" + number + "\t");
} else {
if (number == 1) {
System.out.print("黑桃" + "A\t");
} else if (number == 11) {
System.out.print("黑桃" + "J\t");
} else if (number == 12) {
System.out.print("黑桃" + "Q\t");
} else if (number == 13) {
System.out.print("黑桃" + "K\t");
} else System.out.print("黑桃" + number + "\t");
}
}
System.out.println("");
return num;
}
解释:将牌型大小固定第十位数表示数值,比如,K=130,Q=120,J=110直观看出大小,个位数表示花色大小,如,黑桃为3,红桃为2,梅花为1,方块为0,即 133>130,也就是黑桃K大于方块K
将牌型进行组合计算点数
利用循环遍历找出三张牌的组合为10的倍数,并输出剩下两张牌的点数。
boolean found = false;
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 4; j++) {
for (int k = j + 1; k < 5; k++) {
if ((number[i] + number[j] + number[k]) % 10 == 0) {//依次遍历五张牌,选出任意三张牌之和为十的倍数
found = true;
int result = 0;
for (int l = 0; l < 5; l++) {
if (l != i && l != j && l != k) { // 只加上不在三个数中的数字,也就是剩下两张牌和的点数
result += number[l];
}
}
result = result % 10;//只留各位数代表点数
if (result == 0) {//为0代表点数为10意思就是满点
System.out.println("玩家点数为:满点");
return 10;
} else System.out.println("玩家点数为:" + result + "点");
return result;
}
}
}
}
if (!found) {//没有点数的情况
System.out.println("玩家没有点数");
}
将手牌数据初始化(花牌K、Q、J点数记为10,其余牌的点数为牌的数字大小)
int[] number = new int[5];
for (int i = 0; i < 5; i++) {//如果点数大于10按10算
number[i] = num[i] / 10;
if (number[i] > 10) {
number[i] = 10;
}
}
点数比较大小
public int comp(int[] num, int[] max) {//进行最后结果比较
int number = num[0], record = 0;//赋初值
for (int i = 0; i < num.length; i++) {
if (num[i] > number) {//先从点数开始比较
number = num[i];
record = i;//记录位置,表示是哪个玩家的点数
} else if (num[i] == number) {//如果点数相同,就比较花色
if (max[i] > max[record]) {//max表示五张牌中最大的那张牌,花色大小,0为方块<1为梅花<2为红桃<3为黑桃
number = num[i];
record = i;
}
}
}
return record;//玩家几
}
运行结果:
附录源码
Poker类定义棋牌
package Java基础.Poker;
import java.util.Random;
public class Poker {//扑克牌类
private int[][] poker = new int[14][4];//第一个数表示纸牌的数字大小从一开始到13,第二个数表示纸牌的四种花色。
public int[][] getPoker() {
return poker;
}
public void setPoker(int[][] poker) {
this.poker = poker;
}
public Poker() {//赋初值全设为0,如果用到了这张牌就设为1
for (int i = 1; i < 14; i++) {
for (int j = 0; j < 4; j++)
poker[i][3] = 0;
}
}
public int number() {
Random random = new Random();
int index = 0;//记录牌数
while (index < 52) {
int a, b;
a = random.nextInt(1, 14);//随机数
b = random.nextInt(0, 4);
if (poker[a][b] == 0) {//判断这张牌是否已经出现了,每张牌只能出现一次
poker[a][b] = 1;//设置状态为1
return a * 10 + b;//返回值设置为三位数,用来存储牌的信息,前两位表示牌的数字大小,个位数表示牌的花色,利于后续牌的大小比较
}
index++;
}
System.out.println("牌库见底");//所有牌的状态为1证明52张牌全部发完
return 0;
}
}
玩家类Person
package Java基础.Poker;
public class Person {
private String name;
private int money = 30;
public int result;
public Person(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int sell(int money) {//扣钱
if (this.money < money) {
return 0;//设置状态,便于后期判断余额为空的情况
} else
this.money -= money;
return 1;
}
public void buy(int money) {//加钱
this.money += money;
}
public String toString() {
return "姓名:" + name +
"\t余额:" + money;
}
}
斗牛游戏类Bullfight
package Java基础.Poker;
public class Bullfight extends Poker {//斗牛游戏
public Bullfight() {//构造方法
super();
}
public int comp(int[] num, int[] max) {//进行最后结果比较
int number = num[0], record = 0;//赋初值
for (int i = 0; i < num.length; i++) {
if (num[i] > number) {//先从点数开始比较
number = num[i];
record = i;//记录位置,表示是哪个玩家的点数
} else if (num[i] == number) {//如果点数相同,就比较花色
if (max[i] > max[record]) {//max表示五张牌中最大的那张牌,花色大小,0为方块<1为梅花<2为红桃<3为黑桃
number = num[i];
record = i;
}
}
}
return record;//玩家几
}
public int value(int[] num) {//进行点数计算
int[] number = new int[5];
for (int i = 0; i < 5; i++) {//如果点数大于10按10算
number[i] = num[i] / 10;
if (number[i] > 10) {
number[i] = 10;
}
}
boolean found = false;
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 4; j++) {
for (int k = j + 1; k < 5; k++) {
if ((number[i] + number[j] + number[k]) % 10 == 0) {//依次遍历五张牌,选出任意三张牌之和为十的倍数
found = true;
int result = 0;
for (int l = 0; l < 5; l++) {
if (l != i && l != j && l != k) { // 只加上不在三个数中的数字,也就是剩下两张牌和的点数
result += number[l];
}
}
result = result % 10;//只留各位数代表点数
if (result == 0) {//为0代表点数为10意思就是满点
System.out.println("玩家点数为:满点");
return 10;
} else System.out.println("玩家点数为:" + result + "点");
return result;
}
}
}
}
if (!found) {//没有点数的情况
System.out.println("玩家没有点数");
}
return 0;
}
public int[] deal() {//随机发牌五张
int[] num = new int[5];
for (int i = 0; i < 5; i++) {//调用父类随机抽取的牌
num[i] = super.number();
}
System.out.println("你的手牌为:");
for (int i = 0; i < 5; i++) {
int color = num[i] % 10;//取余数代表花色
int number = num[i] / 10;//代表牌的数值
if (color == 0) {
if (number == 1) {
System.out.print("方块" + "A\t");
} else if (number == 11) {
System.out.print("方块" + "J\t");
} else if (number == 12) {
System.out.print("方块" + "Q\t");
} else if (number == 13) {
System.out.print("方块" + "K\t");
} else System.out.print("方块" + number + "\t");
} else if (color == 1) {
if (number == 1) {
System.out.print("梅花" + "A\t");
} else if (number == 11) {
System.out.print("梅花" + "J\t");
} else if (number == 12) {
System.out.print("梅花" + "Q\t");
} else if (number == 13) {
System.out.print("梅花" + "K\t");
} else System.out.print("梅花" + number + "\t");
} else if (color == 2) {
if (number == 1) {
System.out.print("红桃" + "A\t");
} else if (number == 11) {
System.out.print("红桃" + "J\t");
} else if (number == 12) {
System.out.print("红桃" + "Q\t");
} else if (number == 13) {
System.out.print("红桃" + "K\t");
} else System.out.print("红桃" + number + "\t");
} else {
if (number == 1) {
System.out.print("黑桃" + "A\t");
} else if (number == 11) {
System.out.print("黑桃" + "J\t");
} else if (number == 12) {
System.out.print("黑桃" + "Q\t");
} else if (number == 13) {
System.out.print("黑桃" + "K\t");
} else System.out.print("黑桃" + number + "\t");
}
}
System.out.println("");
return num;
}
public int max(int[] num) {//比较五张牌中最大的那张
int number = num[0];
for (int num1 : num) {
if (num1 > number) {
number = num1;
}
}
return number;
}
}
测试运行
package Java基础.Poker;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.InputMismatchException;
import java.util.Scanner;
import static java.lang.System.exit;
public class Game {
public static void main(String[] args) {
try {//输入的异常处理
Scanner scanner = new Scanner(System.in);
System.out.println("欢迎来到PokerGame!");
Person[] play = new Person[4];//对象数组
System.out.println("请输入你姓名");
String name = scanner.next();
play[3] = new Person(name);
play[0] = new Person("李四");
play[1] = new Person("王五");
play[2] = new Person("老六");
System.out.println("欢迎玩家" + play[3].getName() + "加入!");
System.out.println("游戏即将开始");
while (true) {//输入循环判断
System.out.println("是否开始发牌(是,1/否,0)");
int start = scanner.nextInt();//开始游戏
if ((start != 1) && (start != 0)) {//输入判断
System.out.println("输入不匹配,请重新输入");
continue;
}
int index = 1;//记录游戏次数
while (true) {
if (start == 1) {
System.out.println("第" + index + "轮发牌开始:");
for (int i = 0; i < 4; i++) {//打印玩家信息
System.out.println(play[i].toString());
}
Bullfight bullfight = new Bullfight();//放置循环内,以格式化牌型数组的初值
int[] max = new int[4];
for (int i = 0; i < 4; i++) {
System.out.println("给" + play[i].getName() + "玩家发牌");
int[] num = Arrays.copyOf(bullfight.deal(), 5);//拷贝一份
play[i].result = bullfight.value(num);//存储玩家的点数
max[i] = bullfight.max(num);//记录五张牌中的最大的那一张
System.out.println();
}
int[] num = new int[4];
for (int i = 0; i < 4; i++) {
num[i] = play[i].result;
}
int value = bullfight.comp(num, max);//进行大小比对,输出玩家指针号
System.out.print("玩家" + play[value].getName() + "获胜\t\t\t");
Date now = new Date();
// 创建SimpleDateFormat对象,指定日期格式
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
// 使用format方法将Date对象转换为字符串
String formattedDate = formatter.format(now);
// 打印当前时间
System.out.println("时刻:" + formattedDate);
play[value].buy(40);//获胜玩家加40,本来是加30,这里是为了方便计算
for (int i = 0; i < 4; i++) {//所有玩家扣10
if (play[i].sell(10) == 0) {
System.out.println();
System.out.print("游戏结束\t玩家" + play[i].getName() + "余额不足\t");//玩家余额不足的情况反馈
if (((i + 1)) < 4 && (play[i + 1].sell(10) == 0)) {//判断多位玩家同时余额为0时的输出
System.out.print("玩家" + play[i + 1].getName() + "余额不足\t");
}
if (((i + 2)) < 4 && (play[i + 1].sell(10) == 0)) {
System.out.print("玩家" + play[i + 2].getName() + "余额不足\t");
}
if (((i + 3)) < 4 && (play[i + 1].sell(10) == 0)) {
System.out.print("玩家" + play[i + 3].getName() + "余额不足\t");
}
System.out.println();
for (int j = 0; j < 4; j++) {
System.out.println(play[j].toString());//打印最终的玩家信息
}
exit(0);//结束运行
}
}
System.out.println();
index++;
int end;
while (true) {//输入判断
System.out.println("是否继续发牌(是,1/否,0)");
end = scanner.nextInt();
if ((end != 1) && (end != 0)) {
System.out.println("输入不匹配,请重新输入");
continue;
}
break;
}
if (end == 0) {//结束游戏
break;
}
} else break;
}
for (int i = 0; i < 4; i++) {
System.out.println(play[i].toString());
}
break;
}
} catch (InputMismatchException e) {//输入类型不匹配
System.out.println("输入出错了,游戏结束");
}
}
}