java的21点牌类游戏-自带洗牌算法与机器AI---【课程设计】

关于毕业设计这个没有总目录,请自行在去毕业设计的这个版块查看
基于jsp的企业员工信息管理系统的设计与实现–【毕业论文】 这里列了一些,其它的请自行查找
在这里插入图片描述
JAVA的有代码可能叫【课程设计】
SSM或JAVAWEB(JSP)的【唐诗300首】
springBoot 的叫【JSB项目实战】
PHP的项目叫【白嫖项目】
其它的有可能叫【课程设计】或【毕业设计】

本系列校训

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

毕设的技术铺垫

语言选择收录专辑链接卷的程度
C张雪峰推荐选择了计算机专业之后-在大学期间卷起来-【大学生活篇】★★★✫✰
JAVA黑马B站视频JAVA部分的知识范围、学习步骤详解★★★★★
JAVAWEB黑马B站视频JAVAWEB部分的知识范围、学习步骤详解★★★★★
SpringBootSpringBoot知识范围-学习步骤【JSB系列之000】★★★★★
微信小程序详细解析黑马微信小程序视频–【思维导图知识范围】★★★✰✰
python详细解析python视频选择–【思维导图知识范围】★★✫✰✰
phpPHP要怎么学–【思维导图知识范围】★★★✫✰

环境及工具:

本系列环境

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

项目说明

这个游戏工作量比较小,也比较粗糙。当做学习还是相当的不错的。当毕业设计就有点拿不出手了。但是还是相当的值得学习

总体功能

21点吹牛。
21点又名黑杰克(Blackjack),起源于法国,已流传到世界各地,有着悠久的历史。在世界各地的赌场中都可以看到二十一点,随着互联网的发展,二十一点开始走向网络时代。该游戏由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。

该游戏由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。当使用1副牌时,以下每种牌各一张(没有大小王):
在这里插入图片描述

21点一般用到1-8副牌。
大家手中扑克点数的计算是:2至9牌,按其原点数计算;K、Q、J和10牌都算作10点(一般记作T,即ten之意);A 牌(ace)既可算作1点也可算作11点,由玩家自己决定(当玩家停牌时,点数一律视为最大而尽量不爆,如A+9为20,A+4+8为13,A+3+A视为15)。
以下规则(软17)和流程视赌场不同而略有区别,请务必了解清楚!
开局时,庄家(dealer)给每个玩家(又称闲家)牌面向上发两张牌(明牌),再给庄家自己发两张牌,一张明牌,一张暗牌(牌面朝下)。
当所有的初始牌分发完毕后,如果玩家拿到的是A和T(无论顺序),就拥有黑杰克(Black Jack);若庄家的明牌为T,且暗牌为A,应直接翻开并拥有Black Jack;如果庄家的明牌为A,则玩家可以考虑买不买保险(Insurance),保险金额是赌注的一半且不退。此时,如果庄家的暗牌为10点牌(构成Black Jack),那么翻开此牌,购买保险的玩家得到1倍赌注;如果庄家没有Black Jack则保持暗牌,玩家继续游戏。若玩家为Black Jack且庄家为其他,玩家赢得1.5倍(或2倍,1赔2时)赌注;若庄家为Black Jack且玩家为其他,庄家赢得赌注;若庄家和玩家均为Black Jack,平局,玩家拿回自己的赌注。
接下来是正常的拿牌流程:首名非黑杰克玩家选择拿牌(Hit)、停牌(Stand)、加倍(Double)、分牌(Split,两牌相同时)或投降(Surrender,庄家赢得一半赌注);若选择拿牌,则后续只能选择拿牌或停牌。在发牌的过程中,如果玩家的牌点数的和超过21,玩家就输了——叫爆掉(Bust),庄家赢得赌注(无论庄家之后的点数是多少)。假如玩家没爆掉,又决定不再要牌了(停牌,或因加倍、投降而终止),则轮到下一名非黑杰克玩家选择。
当所有玩家停止拿牌后,庄家翻开暗牌,并持续拿牌直至点数不小于17(若有A,按最大而尽量不爆计算)。假如庄家爆掉了,那他就输了,玩家赢得1倍赌注;否则那么比点数大小,大为赢。点数相同为平局,玩家拿回自己的赌注。
可以说,21点在规则这一块真的是太简单了。不过,这个项目提供了扑克牌的资源与洗牌的算法,就只凭这两点,也值得收藏了

资源文件

命名也是很规整
在这里插入图片描述
纸牌用的其本就是WINDOWS里的蜘蛛纸牌的图案。
当然可以把牌背换成自己喜欢的。
在这里插入图片描述

代码部分

文件编码问题。不太熟悉JAVA的同学请不要随意怀疑本程序运行出错,或不能运行,盲目修改文件
在这里插入图片描述
项目文件目录如下:
在这里插入图片描述

找到关键核心代码的方法:
应用软件的核心代码是指这个程序最关键部分的代码。例如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();			
		}
		
	}

}

网络部分
在这里插入图片描述

启动主程序


import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.*;

public class Frmchess extends JFrame {
	ChessBoard panel2 = new ChessBoard();
	JButton button1 = new JButton("认输");
	JButton button2 = new JButton("开始");
	JTextField jTextField1 = new JTextField();// 输入IP
	JTextField jTextField2 = new JTextField();// 输入对方端口
	public static final short REDPLAYER = 1;
	public static final short BLACKPLAYER = 0;

	/**
	 * @param args
	 */
	public Frmchess() {
		JPanel panel = new JPanel(new BorderLayout());
		JPanel panel3 = new JPanel(new BorderLayout());

		String urlString = "C://帅.png";
		JLabel label = new JLabel(new ImageIcon(urlString));
		panel.add(label, BorderLayout.CENTER);
		panel2.setLayout(new BorderLayout());
		panel3.setLayout(new FlowLayout());

		JLabel jLabel1 = new JLabel("输入IP");
		JLabel jLabel2 = new JLabel("输入对方端口");
		panel3.add(jLabel1);
		panel3.add(jLabel2);
		jTextField1.setText("127.0.0.1");
		jTextField2.setText("3004");
		panel3.add(jLabel1);
		panel3.add(jTextField1);
		panel3.add(jLabel2);
		panel3.add(jTextField2);
		panel3.add(button1);
		panel3.add(button2);

		this.getContentPane().setLayout(new BorderLayout());
		this.getContentPane().add(panel, BorderLayout.NORTH);
		this.getContentPane().add(panel2, BorderLayout.CENTER);
		this.getContentPane().add(panel3, BorderLayout.SOUTH);
		this.setSize(380, 600);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setTitle("网络中国象棋游戏");
		this.setVisible(true);
		button1.setEnabled(false);
		button2.setEnabled(true);
		setVisible(true);

		// 窗口关闭事件
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				try {
					panel2.send("quit|");// 向对方发送离开信息
					System.exit(0);
				} catch (Exception ex) {
				}
			}
		});

		/**
		 * 鼠标事件监听
		 */
		button1.addMouseListener(new MouseAdapter() {// 认输按钮
					@Override
					public void mouseClicked(MouseEvent e) {
						try {
							panel2.send("lose|");// 向对方发送认输信息
						} catch (Exception ex) {
						}
					}
				});
		button2.addMouseListener(new MouseAdapter() {// 重新开始按钮
					@Override
					public void mouseClicked(MouseEvent e) {
						// panel2.NewGame(REDPLAYER);
						String ip = jTextField1.getText();
						int remoteport = Integer
								.parseInt(jTextField2.getText());
						// int
						// receiveport=Integer.parseInt(jTextField2.getText());
						int receiveport;
						if (remoteport == 3003)
							receiveport = 3004;
						else
							receiveport = 3003;
						panel2.startJoin(ip, remoteport, receiveport); // 开始联机
						button1.setEnabled(true);
						button2.setEnabled(true);
					}
				});
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Frmchess f = new Frmchess();

	}
}


AI 部分(有点标题 党)
这里电脑认为看不到玩家的牌,所以,只要于少17则会一直要牌。
当然,你可以修改此数值,或者把之前的局数胜负存下来。然后,跟据之前的变动来学习这个数值,那就真是AI了。
但是就算是没有真AI,也是人机两个在互玩。而且,电脑也确实存在着不少的胜率。

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;
		}
	}

运行的界面

当然了,这里为了调试的方便,所以我把电脑的牌给显示出来了。否则的话,是玩家胜还是电脑胜就不好知道对错了。事实上,这个代码起初有不少BUG,包括胜负的显示

在这里插入图片描述
你要了一张,电脑也要了一张。这就基本上只能认输了
在这里插入图片描述
玩家要了一张之后,电脑会判断自己的牌点,所以就不要了。(初级AI)
在这里插入图片描述
在这里插入图片描述
又要了一张,爆了。

总结

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

以前的学习的人,没有那么正规,但是潜下心写代码。现在的人呢?除了各种网络的BBLL,真心写代码的还能找不到工作?每个人都是springBoot ,甚至springcloud 起步,但是实际的分析能力真的是…也正如2023年的IT现状一样,会springBoot全套,会VUE,工资只有2000左右。
有的时候,真的要思考一下,现在的人取巧 到底是不是巧。

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

配套资源

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

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

项目花园范德彪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值