Java基础篇【斗地主】


前言

嗯~怎么说呢,就是心血来潮想练下基础,但又不知道练什么好。就干脆做个小游戏玩一玩。


一、设计

首页斗地主有这么几个需要的东西:

  1. 玩家
  2. 扑克牌
  3. 发牌的??

每局游戏玩家需要3个,扑克牌每3个人一套,而发牌的就叫庄家了吧,也是每三人一个。

综上所述,程序运行需要的对象有

  1. 庄家:有一套完整的牌和三个玩家
  2. 玩家:有一套自己的牌
  3. 扑克牌:有牌的大小和类型(对子,炸弹啥的)

二、流程

  1. 初始化54张牌
  2. 选定谁是地主
  3. 发牌(每人17张牌)
  4. 剩余3张牌给地主
  5. 地主出牌
  6. 按顺序下一位出牌
  7. 重复5-6至有人手牌全部出完
  8. 宣布胜利者

三、方法定义

  1. 初始化54张牌
  2. 选定谁是地主
  3. 发牌(每人17张牌)
  4. 剩余3张牌给地主
  5. 地主出牌
  6. 按顺序下一位出牌
  7. 重复5-6至有人手牌全部出完
  8. 宣布胜利者
  1. 这个当然是庄家初始化,也就是庄家对象需要初始化54张牌的方法
  2. 谁是地主也是庄家选定的,专家对象需要一个选定地址的方法
  3. 发牌也是庄家干的事,但发给玩家,玩家需要拿到牌,也就是庄家需要一个发牌的方法,玩家需要一个收牌的方法
  4. 没啥好说的
  5. 出牌也就是玩家需要一个出牌的方法
  6. 决定出牌的顺序和记录上一个出牌的玩家也是庄家需要的方法
  7. 循环,交给主程序
  8. 最后的输出也交给主程序

整理成代码:

扑克牌

**
 * @author: ljp
 * @description:* @date: 
 */
public class Brand {

	/**
	 * 扑克牌数字
	 */
	private static final String[] NUMBER = new String[] { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A",
			"2", "joker" };
	/**
	 * 扑克牌花色
	 */
	private static final String[] COLOUR = new String[] { "♥", "♠", "♣", "♦" };

	/**
	 * 卡牌数组
	 */
	public static final String[] DEFAULT_BRAND = new String[54];

	/**
	 * 初始化
	 */
	static {
		
	}

	/** 类型-1错误类型0-单1-对子2-王炸3-三带一4-三带二5-顺子6-连队7-炸弹 */
	private int type = -1;

	/** 牌的大小-组 */
	private int[] brandSize = new int[20];

	/** 数组大小 */
	private int brandLength = 0;

	/** 存储重复出现次数的数组 */
	private int[] brandNum = new int[NUMBER.length];

	/**
	 * 创建牌对象
	 * @param brands 可以有多张牌
	 */
	public Brand(String... brands) {
		
	}

	/**
	 * 排序
	 * 
	 */
	public void sort() {
		
	}

	/**
	 * 计算类型
	 */
	public void updateType() {
		type = -1;
	}


	/**
	 * 获取牌下标
	 */
	public static int getBrandIndex(String brand) {
		return -1;
	}

	/**
	 * 根据下标获取牌
	 */
	public static String getBrandByIndex(int index) {
		return "大王";
	}

	/**
	 * 获取牌的大小
	 */
	public static int getBrandSize(String brand) {
		return 0;
	}

	/**
	 * 比较牌大小
	 * 
	 * @return -true 大于,false 无法判断或小于等于
	 */
	public boolean extent(Brand brand) {
		return true;
	}
}

玩家

/**
 * @author: ljp
 * @description: 玩家
 * @date: 
 */
public class User {

	/**
	 * 初始化
	 * 
	 * @param userName
	 */
	public User(String userName) {
		this.userName = userName;
	}

	/** 用户名 */
	private String userName;
	/** 卡牌数 */
	private int brandNumber = 0;
	/** 是否地主 */
	private boolean isLord = false;
	/** 用户持有卡牌 */
	private String[] userp = new String[20];

	/**
	 * 发牌
	 */
	public void deal(String brand) {
		
	}
	/**
	 * 出牌
	 * 
	 * @param index 用户牌下标
	 * @return
	 */
	public void outBrand(int[] indexs) {
		
	}

	/**
	 * 排序
	 */
	public void sort() {
		
	}

	/**
	 * 输出手牌
	 */
	public String getBrand() {
		
	}
	/**
	 * 输出手牌序号
	 */
	public String getBrandNo() {
		
	}

	public String getUserName() {
		return userName;
	}

	public Integer getBrandNumber() {
		return brandNumber;
	}

	public Boolean isLord() {
		return isLord;
	}

	public void setIsLord(Boolean isLord) {
		this.isLord = isLord;
	}


}

庄家

/**
 * @author: ljp
 * @description: 庄家
 * @date: 
 */
public class Maker {

	/**
	 * 卡牌数组
	 */
	private String[] p = new String[54];

	/**
	 * 用户出的牌
	 */
	private Brand brand;
	/**
	 * 出牌的用户下标
	 */
	private int uIndex = -1;

	/**
	 * 地主下标
	 */
	private int lordIndex = -1;

	/**
	 * 初始化54张牌
	 */
	public Maker() {
		
	}

	/** 玩家 */
	private User[] user = new User[3];

	/**
	 * 伪随机洗牌
	 */
	public void washBrand() {
		
	}

	/**
	 * 发牌
	 */
	public void start() {
		
	}

	/**
	 * 用户出牌
	 * 
	 * @param uIndex 用户下标
	 * @param pIndex 用户牌下标
	 */
	public boolean outBrand(int uIndex, int[] pIndex) {
		
	}

	/**
	 * 输出玩家出的牌
	 */
	public String getOutBrand(Integer lordIndex) {
		
	}

	public User[] getUser() {
		return user;
	}

	public void setUser(User[] user) {
		this.user = user;
	}

	public Integer getLordIndex() {
		return lordIndex;
	}

}

主程序

/**
 * @author: ljp
 * @description:
 * @date: 
 */
public class Main {

	public static void main(String[] args) {
		Maker m = new Maker();
		m.setUser(new User[] { new User("天天"), new User("可可儿"), new User("水煮鱼") });
		m.washBrand();
		// 开始发牌
		m.start();
		// 打印用户的手牌
		for (User user : m.getUser()) {
			System.out.println(user.getBrand());
		}
		// 第一次出牌玩家的下标
		int lordIndex = m.getLordIndex();
		int roundNumber = 1;
		Scanner in = new Scanner(System.in);
		System.out.println("=======================================");
		while (true) {
			System.out.println(m.getOutBrand(lordIndex));
			System.out.println("请出牌,出多张牌用空格隔开");
			// 输出玩家手牌
			System.out.println(m.getUser()[lordIndex].getBrand());
			System.out.println(m.getUser()[lordIndex].getBrandNo());
			try {
				String[] split = in.nextLine().split(" ");
				int[] indexs = new int[split.length];
				for (int i = 0; i < split.length; i++) {
					indexs[i] = Integer.valueOf(split[i]).intValue();
				}
				if(check(indexs)){
					System.out.println("输入有误,请重新输入");
					continue;
				}
				if (!m.outBrand(lordIndex, indexs)) {
					System.out.println("输入有误,请重新输入");
					continue;
				}
				if (m.getUser()[lordIndex].getBrandNumber() == 0) {
					System.out.println("恭喜玩家:" + m.getUser()[lordIndex].getUserName() + "获胜");
					roundNumber++;
					break;
				}
				lordIndex = (lordIndex + 1) % 3;
				roundNumber++;
			} catch (Exception e) {
				in = new Scanner(System.in);
				System.out.println("输入有误,请重新输入");
				continue;
			}
		}
		in.close();
		System.out.println("总回合数为:" + roundNumber);
	}
	/**
	* 是否有重复
	* @param indexs
	* @return
	*/
	private static boolean check(int[] indexs){
		if(indexs.length < 2){
			return false;
		}
		for(int i=0;i<indexs.length;i++){
			for(int j=i+1;j<indexs.length;j++){
				if(indexs[i] == indexs[j]){
					return true;
				}
			}
		}
		return false;
	}
}

思路整理的那么好,这还能翻!!这还能翻??这都能翻o_O
额,好吧。过了两天了我还是没有写完

四、遇到的问题

小bug小bug,一个练基础用的小游戏而已啦,不会搞得太复杂的,只是一直拿不到好的牌害我测试各种情况费了点劲。最大的问题就是牌的大小判断,一开始代码写的是真的low各种if判断看的我自己都发疯。最后还是花了4-5天终于是写完了。

五、完整代码

玩家

/**
 * @author: ljp
 * @description: 玩家
 * @date: 
 */
public class User {

	/**
	 * 初始化
	 * 
	 * @param userName
	 */
	public User(String userName) {
		this.userName = userName;
	}

	/** 用户名 */
	private String userName;
	/** 卡牌数 */
	private int brandNumber = 0;
	/** 是否地主 */
	private boolean isLord = false;
	/** 用户持有卡牌 */
	private String[] userp = new String[20];

	/**
	 * 发牌
	 */
	public void deal(String brand) {
		userp[brandNumber] = brand;
		brandNumber++;
	}

	/**
	 * 获取出牌
	 * 
	 * @param index 用户手牌下标
	 * @return 用户出的牌
	 */
	public String[] getOutBrandIndex(int[] indexs) {
		String[] brands = new String[indexs.length];
		for (int i = 0; i < indexs.length; i++) {
			if (indexs[i] < 0 || indexs[i] >= this.brandNumber) {
				brands[i] = "";
			} else {
				brands[i] = userp[indexs[i]];
			}
		}
		return brands;
	}

	/**
	 * 出牌
	 * 
	 * @param index 用户牌下标
	 * @return
	 */
	public void outBrand(int[] indexs) {
		for (int index : indexs) {
			userp[index] = null;
		}
		sort();
		brandNumber-=indexs.length;
	}

	/**
	 * 排序
	 */
	public void sort() {
		String ch;
		int beginIndex = -1;
		int endIndex = -1;
		for (int i = 0; i < brandNumber - 1; i++) {
			for (int n = i + 1; n < brandNumber; n++) {
				beginIndex = Brand.getBrandIndex(userp[i]);
				endIndex = Brand.getBrandIndex(userp[n]);
				if (beginIndex == -1 || (endIndex != -1 && beginIndex > endIndex)) {
					ch = userp[n];
					userp[n] = userp[i];
					userp[i] = ch;
				}
			}
		}
	}

	/**
	 * 输出手牌
	 */
	public String getBrand() {
		sort();
		StringBuilder result = new StringBuilder();
		result.append(userName);
		if (this.isLord) {
			result.append("(地主)");
		}
		result.append("的手牌:");
		for (int i = 0; i < brandNumber; i++) {
			result.append(userp[i]).append(",");
		}
		return result.substring(0, result.length() - 1);
	}

	/**
	 * 输出手牌序号
	 */
	public String getBrandNo() {
		sort();
		StringBuilder result = new StringBuilder();
		result.append(userName);
		if (this.isLord) {
			result.append("(地主)");
		}
		result.append("的牌号:");
		for (int i = 0; i < brandNumber; i++) {
			for (int n = 0; n < userp[i].length() - String.valueOf(i).length(); n++) {
				result.append("♥");
			}
			result.append(""+i).append(",");
		}
		return result.substring(0, result.length() - 1);
	}

	public String getUserName() {
		return userName;
	}

	public Integer getBrandNumber() {
		return brandNumber;
	}

	public Boolean isLord() {
		return isLord;
	}

	public void setIsLord(Boolean isLord) {
		this.isLord = isLord;
	}

}

庄家

/**
 * @author: ljp
 * @description: 庄家
 * @date: 
 */
public class Maker {

	/**
	 * 卡牌数组
	 */
	private String[] p = new String[54];

	/**
	 * 用户出的牌
	 */
	private Brand brand;
	/**
	 * 出牌的用户下标
	 */
	private int uIndex = -1;

	/**
	 * 地主下标
	 */
	private int lordIndex = -1;

	/**
	 * 初始化
	 */
	public Maker() {
		for (int i = 0; i < p.length; i++) {
			p[i] = Brand.DEFAULT_BRAND[i];
		}
	}

	/** 玩家 */
	private User[] user =new User[3];

	/**
	 * 伪随机洗牌
	 */
	public void washBrand() {
		String ch;
		int off;
		long time = System.currentTimeMillis();
		// n=洗牌次数
		for (int n = -1; n < time % p.length; n++) {
			for (int i = 0; i < p.length; i++) {
				// 新位置
				off = (int) ((time | n & p.hashCode() | p[i].hashCode()) % p.length);
				off = off < 0 ? -off : off;
				ch = p[off];
				p[off] = p[i];
				p[i] = ch;
			}
		}
	}

	/**
	 * 发牌
	 */
	public void start() {
		int lord = (int) ((System.currentTimeMillis() | user.hashCode()) % user.length);
		if (lord < 0) {
			lord = -lord;
		}
		// 发地主
		user[lord].setIsLord(true);
		this.lordIndex = lord;
		for (int i = 0; i < p.length; i++) {
			if (i > p.length - 4) {
				user[lord].deal(p[i]);
			} else {
				user[i % 3].deal(p[i]);
			}
		}
	}

	/**
	 * 用户出牌
	 * 
	 * @param uIndex 用户下标
	 * @param pIndex 用户牌下标
	 */
	public boolean outBrand(int uIndex, int[] pIndex) {
		// 校验越界
		Brand brand = new Brand(user[uIndex].getOutBrandIndex(pIndex));
		if (brand.isOff()) {
			// 有用户出牌大不起时才返回true
			return this.brand != null && this.uIndex != uIndex;
		}
		if (this.brand == null || this.uIndex == uIndex) {
			// 1.第一次出牌或全pass
			user[uIndex].outBrand(pIndex);
			this.brand = brand;
			this.uIndex = uIndex;
			return true;
		}
		// 2.比较大小
		if (brand.extent(this.brand)) {
			user[uIndex].outBrand(pIndex);
			this.brand = brand;
			this.uIndex = uIndex;
			return true;
		}
		return false;
	}

	/**
	 * 输出玩家出的牌
	 */
	public String getOutBrand(Integer lordIndex) {
		if (this.brand == null || this.uIndex == lordIndex) {
			return "";
		}
		StringBuilder out = new StringBuilder();
		User user = this.user[this.uIndex];
		out.append(user.getUserName());
		if (user.isLord()) {
			out.append("(地主)");
		}
		out.append("出的牌:");
		out.append(this.brand.printBrand());
		return out.toString();
	}

	public User[] getUser() {
		return user;
	}

	public void setUser(User[] user) {
		this.user = user;
	}

	public Integer getLordIndex() {
		return lordIndex;
	}

}

扑克牌

/**
 * @author: ljp
 * @description: 牌
 * @date: 2022年12月8日 上午9:27:01
 */
public class Brand {

	/**
	 * 扑克牌数字
	 */
	private static final String[] NUMBER = new String[] { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A",
			"2", "joker" };
	/**
	 * 扑克牌花色
	 */
	private static final String[] COLOUR = new String[] { "♥", "♠", "♣", "♦" };

	/**
	 * 卡牌数组
	 */
	public static final String[] DEFAULT_BRAND = new String[54];

	/**
	 * 初始化
	 */
	static {
		DEFAULT_BRAND[52] = "小王";
		DEFAULT_BRAND[53] = "大王";
		for (int i = 0; i < DEFAULT_BRAND.length - 2; i++) {
			DEFAULT_BRAND[i] = COLOUR[i % 4] + NUMBER[i / 4];
		}
	}

	/** 类型-1错误类型0-单1-对子2-王炸3-三带一4-三带二5-顺子6-连队7-炸弹 */
	private int type = -1;

	/** 牌的大小-组 */
	private int[] brandSize = new int[20];

	/** 数组大小 */
	private int brandLength = 0;

	/** 存储重复出现次数的数组 */
	private int[] brandNum = new int[NUMBER.length];

	public Brand(String... brands) {
		brandLength = brands.length;
		for (int i = 0; i < brands.length; i++) {
			brandSize[i] = getBrandIndex(brands[i]);
			if (brandSize[i] < 0) {
				return;
			}
		}
		// 初始化出现次数
		for (int i = 0; i < brandLength; i++) {
			brandNum[brandSize[i] / 4]++;
		}
		// 计算出类型
		updateType();
		// 排序
		sort();
	}

	/**
	 * 排序
	 * 
	 */
	public void sort() {
		int ch;
		int beginIndex = -1;
		int endIndex = -1;
		for (int i = 0; i < brandLength - 1; i++) {
			for (int n = i + 1; n < brandLength; n++) {
				beginIndex = brandNum[brandSize[i] / 4];
				endIndex = brandNum[brandSize[n] / 4];
				if (beginIndex == -1 || (endIndex != -1 && beginIndex < endIndex)) {
					ch = brandSize[n];
					brandSize[n] = brandSize[i];
					brandSize[i] = ch;
				} else if (beginIndex == endIndex && brandSize[i] > brandSize[n]) {
					ch = brandSize[n];
					brandSize[n] = brandSize[i];
					brandSize[i] = ch;
				}
			}
		}
	}

	/**
	 * 计算类型
	 */
	public void updateType() {
		// 0-单
		if (judgeType(1, 0, 1)) {
			type = 0;
			return;
		}
		// 1-对子
		if (judgeType(2, 0, 2)) {
			if(brandSize[0] > 51 && brandSize[1] > 51) {
				// 2-王炸
				type =2;
			}else {
				type = 1;
			}
			return;
		}
		// 3-三带一
		if (judgeType(4, 0, 3)) {
			type = 3;
			return;
		}
		// 4-三带二
		if (judgeType(5, 0, 3) && judgeType(5, 0, 2)) {
			type = 4;
			return;
		}
		// 5-顺子
		if (judgeType(0, 5, 1) && judgeType(brandLength, brandLength, 1)) {
			type = 5;
			return;
		}
		// 6-连队
		if (brandLength % 2 == 0 && judgeType(0, 4, 2) && judgeType(brandLength, brandLength / 2, 2)) {
			type = 5;
			return;
		}
		// 7炸弹
		if (judgeType(4, 0, 4)) {
			type = 7;
			return;
		}
		type = -1;
	}

	/**
	 * 判断类型
	 * 
	 * @param len       长度 0-为不判断长度
	 * @param seriesNum 连续次数 0-不连续
	 * @param repeatNum 牌重复的次数 0-不判断
	 * @return
	 */
	public boolean judgeType(int len, int seriesNum, int repeatNum) {
		if (len != 0 && brandLength != len) {
			return false;
		}
		// 是否满足重复次数
		boolean isRepeat = false;
		// 是否满足连续次数
		boolean isSeries = false;
		// 连续次数
		int count = 0;
		for (int brand : brandNum) {
			if (repeatNum == 0 || brand == repeatNum) {
				isRepeat = true;
				count++;
				if (count >= seriesNum) {
					isSeries = true;
				}
			} else {
				count = 0;
			}
		}
		return isRepeat && isSeries;
	}

	/**
	 * 获取牌下标
	 */
	public static int getBrandIndex(String brand) {
		for (int i = 0; i < DEFAULT_BRAND.length; i++) {
			if (DEFAULT_BRAND[i].equals(brand)) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * 根据下标获取牌
	 */
	public static String getBrandByIndex(int index) {
		if (index == 52) {
			return "小王";
		}
		if (index == 53) {
			return "大王";
		}
		return COLOUR[index % 4] + NUMBER[index / 4];
	}

	/**
	 * 获取牌的大小
	 */
	public static int getBrandSize(String brand) {
		int index = getBrandIndex(brand);
		if (index > 51) {
			return index;
		}
		return index / 4;
	}

	/**
	 * 比较牌大小
	 * 
	 * @return -true 大于,false 无法判断或小于等于
	 */
	public boolean extent(Brand brand) {
		if (this.type == -1) {
			return false;
		}
		if (brand == null || brand.type == -1 || this.type == 2) {
			return true;
		}
		if (this.type == brand.type && this.brandLength == brand.brandLength) {
			return this.brandSize[0] > brand.brandSize[0];
		}
		if (this.type == 7) {
			return true;
		}
		return false;
	}

	/**
	 * 输出牌组
	 */
	public String printBrand() {
		StringBuilder result = new StringBuilder();
		for (int i = 0; i < brandLength; i++) {
			result.append(getBrandByIndex(brandSize[i]));
		}
		return result.toString();
	}

	public boolean isOff() {
		return this.type == -1;
	}

}

六、游戏体验

在这里插入图片描述

总结

还是有点意思的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值