【课程设计】【JAVA】java的斗地主牌类游戏-自带洗牌算法与机器AI---我见过的最好的JAVA封装与游戏算法结合的例子

关于毕业设计这个总目录
一定要看,因为JAVA工具,tomcat,MAVEN , idea 下载都在这篇文件当中
JAVA项目环境必知必会–【大作业及毕设项目】
部分截图如下:(持续增加中)
在这里插入图片描述

本系列校训

互相伤害互相卷,玩命学习要你管,天生我才必有用,我命由我不由天!

环境及工具:

本系列环境

环境win11
工具idea 2017/idea 2018
jdk1.8
数据库
maven
项目导入方式打开目录
数据库前端工具

项目说明

这个游戏工作量适中,类的封装很优秀。算法的部分也提炼的很好。当做学习还是相当的不错的。当毕业设计就有点拿不出手了。但是还是相当的值得学习

总体功能

斗地主这个全国流行的玩法就不用介绍了。
说一下牌型。使用的是枚举类型。

public enum CardType {
	c1,//单牌。
	c2,//对子。
	c3,//3不带。
	c4,//炸弹。
	c31,//3带1。
	c32,//3带2。
	c411,//4带2个单,或者一对
	c422,//4带2对
	c123,//连子。
	c1122,//连队。
	c111222,//飞机。
	c11122234,//飞机带单排.
	c1112223344,//飞机带对子.
	c0//不能出牌
}

资源文件

这个是另一篇文章里资源文件。
命名也是很规整的《java的21点牌类游戏》
在这里插入图片描述
纸牌用的其本就是WINDOWS里的蜘蛛纸牌的图案。
这套项目把大王小王的图案换了个,其它的没动。(毕竟WINDOWS自带的纸牌游戏深入人心)
在这里插入图片描述

当然可以把牌背换成自己喜欢的。
在这里插入图片描述

项目目录

在这里插入图片描述

代码部分

文件编码问题。不太熟悉JAVA的同学请不要随意怀疑本程序运行出错,或不能运行,盲目修改文件
Card 部分封装了牌的显示,贴图等。
在这里插入图片描述
使用的是JLabel 的父类。写法很规范。

package example;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class Card extends JLabel implements MouseListener{

	Main main;//Main类的引用
	String name;//图片url名字
	boolean up;//是否正反面
	boolean canClick=false;//是否可被点击
	boolean clicked=false;//是否点击过
	public Card(Main m,String name,boolean up){
		this.main=m;
		this.name=name;
		this.up=up;
	    if(this.up)
	    	this.turnFront();
	    else {
			this.turnRear();
		}
		this.setSize(71, 96);
		this.setVisible(true);
		this.addMouseListener(this);
	}
	//正面
	public void turnFront() {
		this.setIcon(new ImageIcon("images/" + name + ".gif"));
		this.up = true;
	}
	//反面
	public void turnRear() {
		this.setIcon(new ImageIcon("images/rear.gif"));
		this.up = false;
	}
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
	}
	public void mouseEntered(MouseEvent arg0) {}
	public void mouseExited(MouseEvent arg0) {}
	public void mousePressed(MouseEvent e) {
		if(canClick)
		{
			Point from=this.getLocation();
			int step; //移动的距离
			if(clicked)
				step=-20;
			else {
				step=20;
			}
			clicked=!clicked; //反向
			//当被选中的时候,向前移动一步/后退一步
			Common.move(this,from,new Point(from.x,from.y-step));
		}
	}
	public void mouseReleased(MouseEvent arg0) {
		
	}

}

核心当然是各种牌型的判断:
在这里插入图片描述

package example;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Common {

	// 判断牌型
	public static CardType jugdeType(List<Card> list) {
		// 因为之前排序过所以比较好判断
		int len = list.size();
		// 单牌,对子,3不带,4个一样炸弹
		if (len <= 4) { // 如果第一个和最后个相同,说明全部相同
			if (list.size() > 0
					&& Common.getValue(list.get(0)) == Common.getValue(list
							.get(len - 1))) {
				switch (len) {
				case 1:
					return CardType.c1;
				case 2:
					return CardType.c2;
				case 3:
					return CardType.c3;
				case 4:
					return CardType.c4;
				}
			}
			// 双王,化为对子返回
			if (len == 2 && Common.getColor(list.get(1)) == 5)
				return CardType.c2;
			// 当第一个和最后个不同时,3带1
			if (len == 4
					&& ((Common.getValue(list.get(0)) == Common.getValue(list
							.get(len - 2))) || Common.getValue(list.get(1)) == Common
							.getValue(list.get(len - 1))))
				return CardType.c31;
			else {
				return CardType.c0;
			}
		}
		// 当5张以上时,连字,3带2,飞机,2顺,4带2等等
		if (len >= 5) {// 现在按相同数字最大出现次数
			Card_index card_index = new Card_index();
			for (int i = 0; i < 4; i++)
				card_index.a[i] = new ArrayList<Integer>();
			// 求出各种数字出现频率
			Common.getMax(card_index, list); // a[0,1,2,3]分别表示重复1,2,3,4次的牌
			// 3带2 -----必含重复3次的牌
			if (card_index.a[2].size() == 1 && card_index.a[1].size() == 1
					&& len == 5)
				return CardType.c32;
			// 4带2(单,双)
			if (card_index.a[3].size() == 1 && len == 6)
				return CardType.c411;
			if (card_index.a[3].size() == 1 && card_index.a[1].size() == 2
					&& len == 8)
				return CardType.c422;
			// 单连,保证不存在王
			if ((Common.getColor(list.get(0)) != 5)
					&& (card_index.a[0].size() == len)
					&& (Common.getValue(list.get(0))
							- Common.getValue(list.get(len - 1)) == len - 1))
				return CardType.c123;
			// 连队
			if (card_index.a[1].size() == len / 2
					&& len % 2 == 0
					&& len / 2 >= 3
					&& (Common.getValue(list.get(0))
							- Common.getValue(list.get(len - 1)) == (len / 2 - 1)))
				return CardType.c1122;
			// 飞机
			if (card_index.a[2].size() == len / 3
					&& (len % 3 == 0)
					&& (Common.getValue(list.get(0))
							- Common.getValue(list.get(len - 1)) == (len / 3 - 1)))
				return CardType.c111222;
			// 飞机带n单,n/2对
			if (card_index.a[2].size() == len / 4
					&& ((Integer) (card_index.a[2].get(len / 4 - 1))
							- (Integer) (card_index.a[2].get(0)) == len / 4 - 1))
				return CardType.c11122234;

			// 飞机带n双
			if (card_index.a[2].size() == len / 5
					&& card_index.a[2].size() == len / 5
					&& ((Integer) (card_index.a[2].get(len / 5 - 1))
							- (Integer) (card_index.a[2].get(0)) == len / 5 - 1))
				return CardType.c1112223344;

		}
		return CardType.c0;
	}

	// 移动效果的函数,用于发牌
	public static void move(Card card, Point from, Point to) {
		if (to.x != from.x) {
			double k = (1.0) * (to.y - from.y) / (to.x - from.x);
			double b = to.y - to.x * k;
			int flag = 0;// 判断向左还是向右移动步幅
			if (from.x < to.x)
				flag = 20;
			else {
				flag = -20;
			}
			for (int i = from.x; Math.abs(i - to.x) > 20; i += flag) {
				double y = k * i + b;// 这里主要用的数学中的线性函数

				card.setLocation(i, (int) y);
				try {
					Thread.sleep(5); // 延迟,可自己设置
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		// 位置校准
		card.setLocation(to);
	}

	// 对list排序
	public static void order(List<Card> list) {
		Collections.sort(list, new Comparator<Card>() {
			@Override
			public int compare(Card o1, Card o2) {
				// TODO Auto-generated method stub
				int a1 = Integer.parseInt(o1.name.substring(0, 1));// 花色
				int a2 = Integer.parseInt(o2.name.substring(0, 1));
				int b1 = Integer.parseInt(o1.name.substring(2, o1.name.length()));// 数值
				int b2 = Integer.parseInt(o2.name.substring(2, o2.name.length()));
				int flag = 0;
				// 如果是王的话
				if (a1 == 5)
					b1 += 100;
				if (a1 == 5 && b1 == 1)
					b1 += 50;
				if (a2 == 5)
					b2 += 100;
				if (a2 == 5 && b2 == 1)
					b2 += 50;
				// 如果是A或者2
				if (b1 == 1)
					b1 += 20;
				if (b2 == 1)
					b2 += 20;
				if (b1 == 2)
					b1 += 30;
				if (b2 == 2)
					b2 += 30;
				flag = b2 - b1;
				if (flag == 0)
					return a2 - a1;
				else {
					return flag;
				}
			}
		});
	}

	// 重新定位 flag代表电脑1 ,2 或者是我
	public static void rePosition(Main m, List<Card> list, int flag) {
		Point p = new Point();
		if (flag == 0) {
			p.x = 50;
			p.y = (450 / 2) - (list.size() + 1) * 15 / 2;
		}
		if (flag == 1) {// 我的排序 _y=450 width=830
			p.x = (800 / 2) - (list.size() + 1) * 21 / 2;
			p.y = 450;
		}
		if (flag == 2) {
			p.x = 700;
			p.y = (450 / 2) - (list.size() + 1) * 15 / 2;
		}
		int len = list.size();
		for (int i = 0; i < len; i++) {
			Card card = list.get(i);
			Common.move(card, card.getLocation(), p);
			m.container.setComponentZOrder(card, 0);
			if (flag == 1)
				p.x += 21;
			else
				p.y += 15;

		}
	}

	// 地主牌权值,看是否抢地主
	public static int getScore(List<Card> list) {
		int count = 0;
		for (int i = 0, len = list.size(); i < len; i++) {
			Card card = list.get(i);
			if (card.name.substring(0, 1).equals("5")) {
				// System.out.println(card.name.substring(0, 1));
				count += 5;
			}
			if (card.name.substring(2, card.name.length()).equals("2")) {
				// System.out.println(2);
				count += 2;
			}
		}
		return count;

	}

	// 返回花色
	public static int getColor(Card card) {
		return Integer.parseInt(card.name.substring(0, 1));
	}

	// 返回值
	public static int getValue(Card card) {
		int i = Integer.parseInt(card.name.substring(2, card.name.length()));
		if (card.name.substring(2, card.name.length()).equals("2"))
			i += 13;
		if (card.name.substring(2, card.name.length()).equals("1"))
			i += 13;
		if (Common.getColor(card) == 5)
			i += 2;// 是王
		return i;
	}

	// 得到最大相同数
	public static void getMax(Card_index card_index, List<Card> list) {
		int count[] = new int[14];// 1-13各算一种,王算第14种
		for (int i = 0; i < 14; i++)
			count[i] = 0;
		for (int i = 0, len = list.size(); i < len; i++) {
			if (Common.getColor(list.get(i)) == 5)
				count[13]++;
			else
				count[Common.getValue(list.get(i)) - 1]++;
		}
		for (int i = 0; i < 14; i++) {
			switch (count[i]) {
			case 1:
				card_index.a[0].add(i + 1);
				break;
			case 2:
				card_index.a[1].add(i + 1);
				break;
			case 3:
				card_index.a[2].add(i + 1);
				break;
			case 4:
				card_index.a[3].add(i + 1);
				break;
			}
		}
	}

	// 拆牌
	public static Model getModel(List<Card> list,int[] orders) {
		// 先复制一个list
		List list2 = new ArrayList<Card>(list);
		Model model = new Model();
		for(int i=0;i<orders.length;i++)
			showOrders(orders[i], list2, model);
		return model;
	}

	// 拆连子
	public static void get123(List<Card> list, Model model) {
		List<Card> del = new ArrayList<Card>();// 要删除的Cards
		if (list.size() > 0
				&& (Common.getValue(list.get(0)) < 7 || Common.getValue(list
						.get(list.size() - 1)) > 10))
			return;
		if (list.size() < 5)
			return;
		// 先要把所有不重复的牌归为一类,防止3带,对子影响
		List<Card> list2 = new ArrayList<Card>();
		List<Card> temp = new ArrayList<Card>();
		List<Integer> integers = new ArrayList<Integer>();
		for (Card card : list2) {
			if (integers.indexOf(Common.getValue(card)) < 0) {
				integers.add(Common.getValue(card));
				temp.add(card);
			}
		}
		Common.order(temp);
		for (int i = 0, len = temp.size(); i < len; i++) {
			int k = i;
			for (int j = i; j < len; j++) {
				if (Common.getValue(temp.get(i)) - Common.getValue(temp.get(j)) == j
						- i) {
					k = j;
				}
			}
			if (k - i >= 4) {
				String s = "";
				for (int j = i; j < k; j++) {
					s += temp.get(j).name + ",";
					del.add(temp.get(j));
				}
				s += temp.get(k).name;
				del.add(temp.get(k));
				model.a123.add(s);
				i = k;
			}
		}
		list.removeAll(del);
	}

	// 拆双顺
	public static void getTwoTwo(List<Card> list, Model model) {
		List<String> del = new ArrayList<String>();// 要删除的Cards
		// 从model里面的对子找
		List<String> l = model.a2;
		if (l.size() < 3)
			return;
		Integer s[] = new Integer[l.size()];
		for (int i = 0, len = l.size(); i < len; i++) {
			String[] name = l.get(i).split(",");
			s[i] = Integer.parseInt(name[0].substring(2, name[0].length()));
		}
		// s0,1,2,3,4 13,9,8,7,6
		for (int i = 0, len = l.size(); i < len; i++) {
			int k = i;
			for (int j = i; j < len; j++) {
				if (s[i] - s[j] == j - i)
					k = j;
			}
			if (k - i >= 2)// k=4 i=1
			{// 说明从i到k是连队
				String ss = "";
				for (int j = i; j < k; j++) {
					ss += l.get(j) + ",";
					del.add(l.get(j));
				}
				ss += l.get(k);
				model.a112233.add(ss);
				del.add(l.get(k));
				i = k;
			}
		}
		l.removeAll(del);
	}

	// 拆飞机
	public static void getPlane(List<Card> list, Model model) {
		List<String> del = new ArrayList<String>();// 要删除的Cards
		// 从model里面的3带找
		List<String> l = model.a3;
		if (l.size() < 2)
			return;
		Integer s[] = new Integer[l.size()];
		for (int i = 0, len = l.size(); i < len; i++) {
			String[] name = l.get(i).split(",");
			s[i] = Integer.parseInt(name[0].substring(2, name[0].length()));
		}
		for (int i = 0, len = l.size(); i < len; i++) {
			int k = i;
			for (int j = i; j < len; j++) {
				if (s[i] - s[j] == j - i)
					k = j;
			}
			if (k != i) {// 说明从i到k是飞机
				String ss = "";
				for (int j = i; j < k; j++) {
					ss += l.get(j) + ",";
					del.add(l.get(j));
				}
				ss += l.get(k);
				model.a111222.add(ss);
				del.add(l.get(k));
				i = k;
			}
		}
		l.removeAll(del);
	}

	// 拆炸弹
	public static void getBoomb(List<Card> list, Model model) {
		List<Card> del = new ArrayList<Card>();// 要删除的Cards
		if(list.size()<1)
			return;
		// 王炸
		if (list.size() >= 2 && Common.getColor(list.get(0)) == 5
				&& Common.getColor(list.get(1)) == 5) {
			model.a4.add(list.get(0).name + "," + list.get(1).name); // 按名字加入
			del.add(list.get(0));
			del.add(list.get(1));
		}
		// 如果王不构成炸弹咋先拆单
		if (Common.getColor(list.get(0)) == 5
				&& Common.getColor(list.get(1)) != 5) {
			del.add(list.get(0));
			model.a1.add(list.get(0).name);
		}
		list.removeAll(del);
		// 一般的炸弹
		for (int i = 0, len = list.size(); i < len; i++) {
			if (i + 3 < len
					&& Common.getValue(list.get(i)) == Common.getValue(list
							.get(i + 3))) {
				String s = list.get(i).name + ",";
				s += list.get(i + 1).name + ",";
				s += list.get(i + 2).name + ",";
				s += list.get(i + 3).name;
				model.a4.add(s);
				for (int j = i; j <= i + 3; j++)
					del.add(list.get(j));
				i = i + 3;
			}
		}
		list.removeAll(del);
	}

	// 拆3带
	public static void getThree(List<Card> list, Model model) {
		List<Card> del = new ArrayList<Card>();// 要删除的Cards
		// 连续3张相同
		for (int i = 0, len = list.size(); i < len; i++) {
			if (i + 2 < len
					&& Common.getValue(list.get(i)) == Common.getValue(list
							.get(i + 2))) {
				String s = list.get(i).name + ",";
				s += list.get(i + 1).name + ",";
				s += list.get(i + 2).name;
				model.a3.add(s);
				for (int j = i; j <= i + 2; j++)
					del.add(list.get(j));
				i = i + 2;
			}
		}
		list.removeAll(del);
	}

	// 拆对子
	public static void getTwo(List<Card> list, Model model) {
		List<Card> del = new ArrayList<Card>();// 要删除的Cards
		// 连续2张相同
		for (int i = 0, len = list.size(); i < len; i++) {
			if (i + 1 < len
					&& Common.getValue(list.get(i)) == Common.getValue(list
							.get(i + 1))) {
				String s = list.get(i).name + ",";
				s += list.get(i + 1).name;
				model.a2.add(s);
				for (int j = i; j <= i + 1; j++)
					del.add(list.get(j));
				i = i + 1;
			}
		}
		list.removeAll(del);
	}

	// 拆单牌
	public static void getSingle(List<Card> list, Model model) {
		List<Card> del = new ArrayList<Card>();// 要删除的Cards
		// 1
		for (int i = 0, len = list.size(); i < len; i++) {
			model.a1.add(list.get(i).name);
			del.add(list.get(i));
		}
		list.removeAll(del);
	}

	// 隐藏之前出过的牌
	public static void hideCards(List<Card> list) {
		for (int i = 0, len = list.size(); i < len; i++) {
			list.get(i).setVisible(false);
		}
	}

	// 检查牌的是否能出
	public static int checkCards(List<Card> c, List<Card>[] current,Main m) {
		// 找出当前最大的牌是哪个电脑出的,c是点选的牌
		List<Card> currentlist;
		if(m.time[0].getText().equals("不要"))
			currentlist=current[2];
		else
			currentlist=current[0];
		CardType cType = Common.jugdeType(c);
		CardType cType2=Common.jugdeType(currentlist);
		// 如果张数不同直接过滤
		if (cType != CardType.c4 && c.size() != currentlist.size())
			return 0;
		// 比较我的出牌类型
		if (cType != CardType.c4&&Common.jugdeType(c) != Common.jugdeType(currentlist)) {

			return 0;
		}
		// 比较出的牌是否要大
		// 我是炸弹
		if (cType == CardType.c4) {
			if(c.size()==2)
				return 1;
			if(cType2!=CardType.c4)
			{
				return 1;
			}
		}

		// 单牌,对子,3带,4炸弹
		if (cType == CardType.c1 || cType == CardType.c2
				|| cType == CardType.c3 || cType == CardType.c4) {
			if (Common.getValue(c.get(0)) <= Common
					.getValue(currentlist.get(0))) {
				return 0;
			} else {
				return 1;
			}
		}
		// 顺子,连队,飞机裸
		if (cType == CardType.c123 || cType == CardType.c1122
				|| cType == CardType.c111222) {
			if (Common.getValue(c.get(0)) <= Common
					.getValue(currentlist.get(0)))
				return 0;
			else
				return 1;
		}
		// 按重复多少排序
		// 3带1,3带2 ,飞机带单,双,4带1,2,只需比较第一个就行,独一无二的
		if (cType == CardType.c31 || cType == CardType.c32
				|| cType == CardType.c411 || cType == CardType.c422
				|| cType == CardType.c11122234 || cType == CardType.c1112223344) {
			List<Card> a1 = Common.getOrder2(c); // 我出的牌
			List<Card> a2 = Common.getOrder2(currentlist);// 当前最大牌
			if (Common.getValue(a1.get(0)) < Common.getValue(a2.get(0)))
				return 0;
		}
		return 1;
	}

	// 按照重复次数排序
	public static List getOrder2(List<Card> list) {
		List<Card> list2 = new ArrayList<Card>(list);
		List<Card> list3 = new ArrayList<Card>();
		List<Integer> list4 = new ArrayList<Integer>();
		int len = list2.size();
		int a[] = new int[20];
		for (int i = 0; i < 20; i++)
			a[i] = 0;
		for (int i = 0; i < len; i++) {
			a[Common.getValue(list2.get(i))]++;
		}
		int max = 0;
		for (int i = 0; i < 20; i++) {
			max = 0;
			for (int j = 19; j >= 0; j--) {
				if (a[j] > a[max])
					max = j;
			}

			for (int k = 0; k < len; k++) {
				if (Common.getValue(list2.get(k)) == max) {
					list3.add(list2.get(k));
				}
			}
			list2.remove(list3);
			a[max] = 0;
		}
		return list3;
	}
	//拆牌循序
	public static void showOrders(int i, List<Card> list, Model model) {
		switch (i) {
		case 1:
			Common.getSingle(list, model);
			break;
		case 2:
			Common.getTwo(list, model);
			Common.getTwoTwo(list, model);
			break;
		case 3:
			Common.getThree(list, model);
			Common.getPlane(list, model);
			break;
		case 4:
			Common.getBoomb(list, model);
			break;
		case 5:
			Common.get123(list, model);
			break;
		}
	}
}

class Card_index {
	List a[] = new ArrayList[4];// 单张
}

找到关键核心代码的方法:
应用软件的核心代码是指这个程序最关键部分的代码。例如WinRAR,它的核心代码就是压缩算法部分,而诸如用户界面、操作系统移植等部分就无足轻重了。
商城类的核心代码是指业务层的代码,比如你商城的核心代码就是:商品、购物车、创建订单、支付这些代码就是核心代码。

作为程序员,我们经常需要看懂别人的代码。特别是在开源社区中,我们需要理解许多优秀的开源项目的代码。而在Gitee这样的代码托管平台上,我们如何快速有效地看懂别人的代码呢?本文将为大家介绍一些方法。

1.阅读README和项目介绍

在Gitee上,许多开源项目都会有自己的README文件或项目介绍。这些文件一般会介绍项目的背景、功能、使用方法等内容,可以帮助我们快速了解这个开源项目的基本情况。如果我们能够从这些文件中找到与自己相关的内容,就可以快速入手这个开源项目的代码。

2.了解项目结构和代码组织

在阅读代码之前,我们需要先了解这个开源项目的代码结构和代码组织方式。通常,开源项目会将不同的功能模块封装到不同的代码文件中,并按照一定的目录结构组织起来。如果我们能够了解这个开源项目的代码组织方式,就能更加快速地找到所需的代码。

3.利用IDE和工具

IDE和一些代码阅读工具可以帮助我们更快速、更高效地阅读代码。例如,Java开发者可以使用Eclipse或IntelliJ IDEA这样的IDE,可以快速打开代码文件、查看类、方法和变量等信息。另外,一些代码阅读工具,如Source Insight、CodeCompare等,可以帮助我们更方便地查看代码的结构和关系,以及快速跳转到相关代码。

4.关注代码注释和文档

良好的代码注释和文档可以帮助我们更快速地理解代码。因此,在阅读别人的代码时,我们可以将注意力放在代码注释和文档上。有些开源项目会提供详细的文档,有些则注重代码注释。如果我们能够针对代码注释和文档有一个系统的阅读和理解,就能更快速地掌握别人的代码。

5.跑通测试和运行项目

如果我们想更深入地了解别人的代码,可以试着跑通相关的测试,或者直接运行这个开源项目。通过跑测试和运行项目,我们可以更加直观地了解代码的实现细节和具体的业务逻辑。

总结:

以上就是在Gitee上快速理解他人代码的一些方法,希望对大家有所帮助。当然,阅读代码是一件需要耐心和细心的事情,需要我们多花一点时间和心思。只有沉下心来,慢慢阅读每一行代码,才能真正理解它们的含义和作用。

牌类的洗牌

很多初学者认为,那就是不停的随机呗。但是,你有没有想过,随机重复的牌呢?
跳过去? 那要这么随机下去,后面的随机数出的得多么的难?得多少次才能随机出还缺的数字?
在这里插入图片描述
就是不停的两张两张的交换。
这样子是不是就跟手动的洗牌的动画有点像?

下面的洗一次,应该就是循环了牌的一半的次数(当然了,没有随机的洗的效果好)
在这里插入图片描述
这样的洗牌,其实只相当于一次随机的交换牌,效果看上去很花,但是事实上就是老千常用的手法。因为洗N次都可能洗不到最上或最下。按道理,这样洗得洗50次才能有点随机的效果
在这里插入图片描述
还是看代码:(完全用老千的手法,只是系统不出老千罢了)
把每一张牌与随机的一张牌交换。

// 方法xipai()用于将所得的随机数组的值赋值给牌的下标
	public static void xipai() {
		int[] b = new int[54];
		b = random(54);// 调用random方法产生一个长度为54的不重复的随机数组
		cards = poker.getCard();
		Card temp = null;
		for (int i = 0; i < b.length; i++) { // 开始遍历数组实现重新排列
			int k = b[i];
			temp = cards[k];
			cards[i] = cards[k];
			cards[k] = temp;
		}
		// 输出洗牌后的扑克
		poker.Show();

	}

切牌。完全随机的切(完全无老千)

// 方法qiepai()实现扑克的切牌操作
	public static void qiepai(int length) {
		int number = (int) (Math.random() * length);// 产生一个随机数
		System.out.println("随机数为:" + number);// 显示随机数是多少
		Card[] temp = new Card[length];
		int start = number;// 设置切牌后的起点位置
		for (int i = 0; i < length - number; i++) {
			temp[i] = cards[start++];// 将切点后面的牌暂时放入temp数组中
		}
		for (int j = 0; j < number; j++) {
			temp[length - number + j] = cards[j];// 将切点前面的牌加入temp数组中
		}
		for (int k = 0; k < length; k++) {
			cards[k] = temp[k];
		}
		// 输出切牌后的扑克
		poker.Show();
	}

牌的资源处理

import java.awt.BorderLayout;
import java.net.URL;
import javax.swing.*;

public class ShowImage extends JFrame{
	/**
	 * @param args
	 */
	public ShowImage() {
		JPanel panel=new JPanel(new BorderLayout());
		JPanel panel2=new JPanel(new BorderLayout());
		JPanel panel3=new JPanel(new BorderLayout());
		
		String urlString="C://rear.gif";
		JLabel label=new JLabel(new ImageIcon(urlString));
		
		URL url=getClass().getResource("/images/2-1.gif");
		JLabel label2=new JLabel(new ImageIcon(url));
		
		URL url2=getClass().getResource("/images/2-2.gif");
		JLabel label3=new JLabel(new ImageIcon(url2));
	
		panel.add(label,BorderLayout.CENTER);
		panel2.add(label2,BorderLayout.CENTER);
	    panel3.add(label3,BorderLayout.CENTER);
		
		this.getContentPane().setLayout(new BorderLayout());
		this.getContentPane().add(panel,BorderLayout.CENTER);
		this.getContentPane().add(panel2,BorderLayout.SOUTH);
		this.getContentPane().add(panel3,BorderLayout.NORTH);
		
		this.setSize(500, 500);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setTitle("显示扑克牌");
		this.setVisible(true);
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	  ShowImage showImage=new ShowImage();
	}

}

import java.awt.Image;
import java.awt.Toolkit;

public class Poker {
	static Card[] cards = new Card[54];
	static String[] colors = {"黑桃", "红桃", "梅花" , "方块"};
	static String values[] = { "A","2", "3", "4", "5", "6", "7", "8", "9", "10",
			"J", "Q", "K"  };
	private Image pic[] = null; // 扑克牌图片数组
	public void getPic() {
		pic = new Image[54];
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 13; j++) {
//				String urlString="C://rear.gif";
//				pic[i * 13 + j]=Toolkit.getDefaultToolkit().getImage(urlString);
				pic[i * 13 + j] = Toolkit.getDefaultToolkit().getImage(
						"images\\" + (i + 1) + "-" + (j + 1) + ".gif");
				
				pic[52] = Toolkit.getDefaultToolkit()
						.getImage("images\\s1.gif"); // 小王
				pic[53] = Toolkit.getDefaultToolkit()
						.getImage("images\\s2.gif"); // 大王
			}
		}
	}
	// 构造方法Poker()用于初始化这副扑克
	public Poker() {
		getPic();
		for (int i = 0; i < colors.length; i++) {
			for (int j = 0; j < values.length; j++) {
				cards[i * 13 + j] = new Card(colors[i], values[j],pic[i*13+j]);
			}
		}
		cards[52] = new Card("小王",pic[52]);
		cards[53] = new Card("大王",pic[53]);
	}

	// 方法getCard()用于获取一张牌的花色和点数
	public Card[] getCard() {
		return Poker.cards;
	}
	// 方法getCard()用于获取一张牌的花色和点数
	public Card  getCard(int n) {
		return Poker.cards[n-1];
	}
	// 方法Show()用于显示一副新的扑克
	public void Show() {
		for (int i = 0; i < 54; i++) {
			cards[i].print();
		}
		System.out.println();
	}
	public  void xipai() {//洗牌
		int i,j; 
		Card tc;		
	    for (int k = 1; k <= 500; k++)
	    {        
	        i = (int) (Math.random() * 54);
	        j = (int) (Math.random() * 54);
	        tc = cards[i];
	        cards[i] = cards[j];
	        cards[j] = tc;
	    }		
	}
}

游戏面板


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ArrayList;

import javax.swing.*;

public class PokerPanel extends JPanel {
	Poker p = new Poker();
	int n = 1;
	ArrayList Mycards = new ArrayList();     // 电脑得到的牌   
	ArrayList Computercards = new ArrayList();//玩家得到的牌
	int Myscore = 0;      // 电脑得分
	int Computerscore = 0;// 玩家得分

	public boolean ComputerContinue = true;
	public boolean Computerlose = false; // 电脑输了标志
	public boolean Mylose = false; // 玩家输了标志

	/**
	 * @param args
	 */
	public PokerPanel() {
		p.xipai();
		p.Show();		
		setBackground(Color.RED);
		this.setVisible(true);
		//repaint();
	}

	public void faCard() {
		Mycards.add(p.getCard(n));
		calcMyScore();
		n++;
		repaint();
		if (Myscore > 21) {
			Mylose = true;
			/* 显示提示信息对话框 */
			JOptionPane.showMessageDialog(null, "你输了,超过21点", "提示",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	public void faCardToComputer() {
		calcComputerScore();
		if (Computerscore > 21) {
			JOptionPane.showMessageDialog(null, "超过21点,电脑输了", "提示",
					JOptionPane.ERROR_MESSAGE);
			ComputerContinue = false;
			Computerlose = true;// 电脑输了
		} else	if (Computerscore < 17) {
			Computercards.add(p.getCard(n));
			n++;
			repaint();
		} else {
			/* 显示提示信息对话框 */
			JOptionPane.showMessageDialog(null, "电脑不再要牌了", "提示",
					JOptionPane.ERROR_MESSAGE);
			ComputerContinue = false;
		}
	}

	public void calcComputerScore() {
		Computerscore = 0;
		for (int i = 0; i < Computercards.size(); i++) {
			Card c = (Card) Computercards.get(i);
			Computerscore += c.count;
		}
	}

	public void calcMyScore() {
		Myscore = 0;
		for (int i = 0; i < Mycards.size(); i++) {
			Card c = (Card) Mycards.get(i);
			Myscore += c.count;
		}
	}

	public void shuying() {
		calcComputerScore();
		calcMyScore();
		if (Computerlose == false)
			JOptionPane.showMessageDialog(null, "电脑输了", "提示",
					JOptionPane.ERROR_MESSAGE);
		else if (Mylose == false)
			JOptionPane.showMessageDialog(null, "玩家输了", "提示",
					JOptionPane.ERROR_MESSAGE);
		else if (Myscore > Computerscore)
			JOptionPane.showMessageDialog(null, "玩家赢了", "提示",
					JOptionPane.ERROR_MESSAGE);
		else
			JOptionPane.showMessageDialog(null, "电脑赢了", "提示",
					JOptionPane.ERROR_MESSAGE);
	}

	/**
	 * 游戏绘图
	 */
	public void paint(Graphics g) {
		g.clearRect(0, 0, this.getWidth(), this.getHeight());
		g.drawString("玩家牌", 400, 250);
		// 玩家牌在下方
		for (int i = 0; i < Mycards.size(); i++) {
			Card c = (Card) Mycards.get(i);
			c.setPosition(50 * i, 200);
			c.print();
			c.paint(g,this);
		}
		System.out.println();
		calcMyScore();
		g.drawString("玩家牌得分"+Myscore, 400, 300);

		g.drawString("电脑牌", 400, 100);
		// 电脑牌在上方
		for (int i = 0; i < Computercards.size(); i++) {
			Card c = (Card) Computercards.get(i);
			c.setPosition(50 * i, 50);
			c.print();
			c.paint(g,this);
		}
		System.out.println();
		calcComputerScore();
		g.drawString("电脑牌得分"+Computerscore, 400, 150);
	}

	public void newGame() {
		// TODO Auto-generated method stub
		Mycards.clear();
		Computercards.clear();
		Myscore = 0;
		Computerscore = 0;
		ComputerContinue = true;
		Computerlose = false; // 电脑输了标志
		Mylose = false; // 玩家输了标志
		//给两家各发两张张牌
		for(int i=1;i<=2;i++){
			faCard();
			faCardToComputer();
			repaint();			
		}
		
	}

}

启动主程序


package example;

import java.awt.Color;
import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class Main extends JFrame implements ActionListener,Runnable{

	public Container container = null;// 定义容器
	JMenuItem start, exit, about;// 定义菜单按钮
	JButton landlord[]=new JButton[2];//抢地主按钮
	JButton publishCard[]=new JButton[2];//出牌按钮
	int dizhuFlag;//地主标志
	int turn;
	JLabel dizhu; //地主图标
	List<Card> currentList[] =new ArrayList[3]; //  当前的出牌
	List<Card> playerList[] = new ArrayList[3]; // 定义3个玩家表
	List<Card> lordList;//地主牌
	Card card[] = new Card[56]; // 定义54张牌
	JTextField time[]=new JTextField[3]; //计时器
	Time t; //定时器(线程)
	boolean nextPlayer=false; //转换角色
	public Main(){
		
		Init();// 初始化
		SetMenu();// 创建菜单 按钮(抢地主,发牌,计时器)
		this.setVisible(true);
		CardInit();//发牌
		getLord(); //发完牌开始抢地主
		time[1].setVisible(true);
		//线程安全性,把非主线程的UI控制放到里面
		t=new Time(this,10);//从10开始倒计时
		t.start();
		
	}
	// 抢地主
	public void getLord(){
		//System.out.println(CardType.c0.toString());
		for(int i=0;i<2;i++)
			landlord[i].setVisible(true);
	}
	//初始化牌
	// 发牌洗牌
	public void CardInit() {
		
		int count = 1;
		//初始化牌
		for (int i = 1; i <= 5; i++) {
			for (int j = 1; j <= 13; j++) {
				if ((i == 5) && (j > 2))
					break;
				else {
					card[count] = new Card(this, i + "-" + j, false);
					card[count].setLocation(350, 50);
					container.add(card[count]);
					count++;
				}
			}
		}
		//打乱顺序
		for(int i=0;i<100;i++){
			Random random=new Random();
			int a=random.nextInt(54)+1;
			int b=random.nextInt(54)+1;
			Card k=card[a];
			card[a]=card[b];
			card[b]=k;
		}
		//开始发牌
		for(int i=0;i<3;i++)
			playerList[i]=new ArrayList<Card>(); //玩家牌
		lordList=new ArrayList<Card>();//地主牌三张
		int t=0;
		for(int i=1;i<=54;i++)
		{
			if(i>=52)//地主牌
			{
				Common.move(card[i], card[i].getLocation(),new Point(300+(i-52)*80,10));
				lordList.add(card[i]);
				continue;
			}
			switch ((t++)%3) {
			case 0:
				//左边玩家
				Common.move(card[i], card[i].getLocation(),new Point(50,60+i*5));
				playerList[0].add(card[i]);
				break;
			case 1:
				//我
				Common.move(card[i], card[i].getLocation(),new Point(180+i*7,450));
				playerList[1].add(card[i]);
				card[i].turnFront(); //显示正面
				break;
			case 2:
				//右边玩家
				Common.move(card[i], card[i].getLocation(),new Point(700,60+i*5));
				playerList[2].add(card[i]);
				break;
			}
			//card[i].turnFront(); //显示正面
			container.setComponentZOrder(card[i], 0);
		}
		//发完牌排序,从大到小
		for(int i=0;i<3;i++)
		{
			Common.order(playerList[i]);
			Common.rePosition(this,playerList[i],i);//重新定位
		}
		dizhu=new JLabel(new ImageIcon("images/dizhu.gif"));
		dizhu.setVisible(false);
		dizhu.setSize(40, 40);
		container.add(dizhu);
	}

	// 初始化窗体
	public void Init() {

		this.setTitle("斗地主");
		this.setSize(830, 620);
		setResizable(false);
		setLocationRelativeTo(getOwner()); // 屏幕居中
		container = this.getContentPane();
		container.setLayout(null);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		container.setBackground(new Color(0, 112, 26)); // 背景为绿色

	}

	// 创建菜单 功能按钮
	public void SetMenu() {
		JMenuBar jMenuBar = new JMenuBar();
		JMenu game = new JMenu("游戏");
		JMenu help = new JMenu("帮助");

		start = new JMenuItem("新游戏");
		exit = new JMenuItem("退出");
		about = new JMenuItem("关于");

		start.addActionListener(this);
		exit.addActionListener(this);
		about.addActionListener(this);

		game.add(start);
		game.add(exit);
		help.add(about);

		jMenuBar.add(game);
		jMenuBar.add(help);
		this.setJMenuBar(jMenuBar);
		
		landlord[0]=new JButton("抢地主");
		landlord[1]=new JButton("不     抢");
		publishCard[0]= new JButton("出牌");
		publishCard[1]= new JButton("不要");
		for(int i=0;i<2;i++)
		{
			publishCard[i].setBounds(320+i*100, 400, 60, 20);
			landlord[i].setBounds(320+i*100, 400,75,20);
			container.add(landlord[i]);
			landlord[i].addActionListener(this);
			landlord[i].setVisible(false);
			container.add(publishCard[i]);
			publishCard[i].setVisible(false);
			publishCard[i].addActionListener(this);
		}
		for(int i=0;i<3;i++){
			time[i]=new JTextField("倒计时:");
			time[i].setVisible(false);
			container.add(time[i]);
		}
		time[0].setBounds(140, 230, 60, 20);
		time[1].setBounds(374, 360, 60, 20);
		time[2].setBounds(620, 230, 60, 20);
		
		for(int i=0;i<3;i++)
		{
			currentList[i]=new ArrayList<Card>();
		}
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if (e.getSource() == exit) {
			this.dispose();
		}
		if (e.getSource() == about) {
			JOptionPane.showMessageDialog(this, "斗地主");
		}
		if (e.getSource() == start) {
			// this.restart();
		}
		if(e.getSource()==landlord[0])
		{
			time[1].setText("抢地主");
			t.isRun=false; //时钟终结
		}
		if(e.getSource()==landlord[1])
		{
			time[1].setText("不抢");
			t.isRun=false; //时钟终结
		}
		//如果是不要
		if(e.getSource()==publishCard[1])
		{
			this.nextPlayer=true;
			currentList[1].clear();
			time[1].setText("不要") ;
		}
		//如果是出牌按钮
		if(e.getSource()==publishCard[0])
		{
			List<Card> c=new ArrayList<Card>();
			//点选出牌
			for(int i=0;i<playerList[1].size();i++)
			{
				Card card=playerList[1].get(i);
				if(card.clicked)
				{
					c.add(card);
				}
			}
			int flag=0;
			
			//如果我主动出牌
			if(time[0].getText().equals("不要")&&time[2].getText().equals("不要"))
			{
				if(Common.jugdeType(c)!=CardType.c0)
					flag=1;//表示可以出牌
			}//如果我跟牌
			else{
				flag=Common.checkCards(c,currentList,this);
			}
			//判断是否符合出牌
			if(flag==1)
			{
				currentList[1]=c;
				playerList[1].removeAll(currentList[1]);//移除走的牌
				//定位出牌
				Point point=new Point();
				point.x=(770/2)-(currentList[1].size()+1)*15/2;;
				point.y=300;
				for(int i=0,len=currentList[1].size();i<len;i++)
				{
					Card card=currentList[1].get(i);
					Common.move(card, card.getLocation(), point);
					point.x+=15;
				}
				//抽完牌后重新整理牌
				Common.rePosition(this, playerList[1], 1);
				time[1].setVisible(false);
				this.nextPlayer=true;
			}

		}
	}

	public static void main(String args[]) {
		
			new Thread(new Main()).start();
		
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}

}




AI 部分(有点标题 党)不过,这个游戏里确实电脑是有策略的。
而且,电脑也确实存在着不少的胜率。

// 地主牌权值,看是否抢地主
	public static int getScore(List<Card> list) {
		int count = 0;
		for (int i = 0, len = list.size(); i < len; i++) {
			Card card = list.get(i);
			if (card.name.substring(0, 1).equals("5")) {
				// System.out.println(card.name.substring(0, 1));
				count += 5;
			}
			if (card.name.substring(2, card.name.length()).equals("2")) {
				// System.out.println(2);
				count += 2;
			}
		}
		return count;

	}

// 拆牌
	public static Model getModel(List<Card> list,int[] orders) {
		// 先复制一个list
		List list2 = new ArrayList<Card>(list);
		Model model = new Model();
		for(int i=0;i<orders.length;i++)
			showOrders(orders[i], list2, model);
		return model;
	}

运行的界面

在这里插入图片描述
基本上就是只要能打得过,就一定会“打” 这个策略好象有点简单了。
在这里插入图片描述

总结

就一句,真的很实用,真的太实用了了。

无论是JAVA的封装,还是牌型

论文参考
基于java的坦克大战游戏的设计与实现–毕业论文–【毕业论文】
https://blog.csdn.net/dearmite/article/details/131962993

配套资源

java的21点牌类游戏-自带洗牌与机器AI-太牛了–【课程设计】

https://download.csdn.net/download/dearmite/88219715

课程设计JAVAjava的斗地主牌类游戏
https://download.csdn.net/download/dearmite/91945829

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

项目张雪峰之巅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值