ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java Swing:Nim游戏实现

2021-03-26 12:29:09  阅读:255  来源: 互联网

标签:Java Nim int void private Swing new JLabel public


由于作业需要,编写了Nim游戏实现。有些地方不太严谨。
废话不多说直接上代码:

MyFrame.Java

import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import javax.swing.border.SoftBevelBorder;

public class MyFrame extends JFrame implements ActionListener, MouseListener {
	private static final long serialVersionUID = 1L; // 序列化,保持对象的唯一性

	private JLabel manmachine; // 人机对战
	private JLabel course; // 新手攻略
	private JLabel about; // 关于
	private JLabel ppt;
	private Container container; // 内容层

	private int ratio; // 难度系数
	private int judge_total; // 记录总数

	// 人机游戏所需要的组件
	private JPanel main; // 主面板
	private JLabel stack_label; // 堆数标签
	private JComboBox<String> stack; // 堆输入框
	private JLabel max_label; // 每次拿的上限
	private JLabel number_label; // 每堆的数量标签
	private JComboBox<String> number; // 每堆的数量
	private JComboBox<String> max; // 上限输入框
	private JLabel total; // 总棋子数
	private int total_number; // 总棋子数
	private JButton start; // 开始按钮
	private static Font font = new Font("Dialog", 0, 20); // 字体
	private Color color = new Color(227, 212, 162); // 颜色
	private int sstack; // 获取堆数
	private int smax; // 获取上限
	private int snumber; // 获取每堆的数量
	private MyLabel[][] myLabel; // 棋子标签
	private JButton carry; // 拿走按钮
	private JLabel[] row; // 行标签
	int carry_row; // 记录拿走的行数
	private int select; // 记录每次选择的个数
	private int[] remainder; // 剩余棋子

	public MyFrame() {// 构造函数
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			System.err.println(e);
		}
		this.setSize(1000, 700); // 设置窗体大小
		this.setLocationRelativeTo(null); // 设置窗体位置
		this.setVisible(true); // 设置窗体可见
		this.setTitle("Nim Game"); // 设置窗体标题
		this.setResizable(false); // 设置窗体不可改变大小
		this.setLayout(null); // 设置布局管理器为null
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗体即退出程序
		this.getContentPane().setBackground(color); // 设置背景颜色

		container = this.getContentPane(); // 获得JFrame的内容层
		init(); // 调用init函数,初始化界面
	}

	public void init() { // 首页的界面
		container.removeAll();
		container.repaint();

		manmachine = new JLabel("人机对战");
		manmachine.addMouseListener(this);
		manmachine.setCursor(new Cursor(Cursor.HAND_CURSOR));
		manmachine.setFont(font);
		manmachine.setBounds(450, 150, 100, 50);
		this.add(manmachine);

		course = new JLabel("新手攻略");
		course.addMouseListener(this);
		course.setCursor(new Cursor(Cursor.HAND_CURSOR));
		course.setFont(font);
		course.setBounds(450, 250, 100, 50);
		this.add(course);

		ppt = new JLabel("观看PPT");
		ppt.addMouseListener(this);
		ppt.setCursor(new Cursor(Cursor.HAND_CURSOR));
		ppt.setFont(font);
		ppt.setBounds(450, 350, 100, 50);
		ppt.addMouseListener(this);
		this.add(ppt);

		about = new JLabel("关于");
		about.addMouseListener(this);
		about.setCursor(new Cursor(Cursor.HAND_CURSOR));
		about.setFont(font);
		about.setBounds(470, 450, 100, 50);
		this.add(about);
		this.validate(); // 刷新内容层
	}

	public void Game() { // 人机游戏函数,创建UI界面
		container.removeAll();
		container.repaint();
		container.setLayout(null);

		final JLabel exit = new JLabel("返回首页");
		exit.setFont(font);
		exit.setBounds(0, 0, 87, 30);
		this.add(exit);
		exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
		exit.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				MyFrame.this.init();
			}

			public void mouseEntered(MouseEvent e) {
				exit.setBorder(null);
				exit.setBorder(new SoftBevelBorder(0, Color.white, Color.white));
			}

			public void mouseExited(MouseEvent e) {
				exit.setBorder(null);
				exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
			}
		});

		stack_label = new JLabel("堆数:");
		stack_label.setFont(font);
		stack_label.setBounds(100, 0, 60, 30);
		this.add(stack_label);

		stack = new JComboBox<String>(new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
		stack.setFont(font);
		stack.setFocusable(false);
		stack.setBackground(color);
		stack.setBounds(150, 3, 50, 25);
		stack.addActionListener(this);
		this.add(stack);

		number_label = new JLabel("每堆数量:");
		number_label.setFont(font);
		number_label.setBounds(250, 0, 150, 30);
		this.add(number_label);

		number = new JComboBox<String>(
				new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" });
		number.setFont(font);
		number.setFocusable(false);
		number.setBackground(color);
		number.setBounds(340, 3, 50, 26);
		this.add(number);

		max_label = new JLabel("每次拿取数量的上限:");
		max_label.setFont(font);
		max_label.setBounds(450, 0, 200, 30);
		this.add(max_label);

		max = new JComboBox<String>(new String[] { "1", "2", "3", "4", "5", "6" });
		max.setFont(font);
		max.setFocusable(false);
		max.setBackground(color);
		max.setBounds(640, 3, 50, 26);
		this.add(max);

		start = new JButton("开始");
		start.addActionListener(this);
		start.setFocusable(false);
		start.setBackground(color);
		start.setBorder(new LineBorder(color, 0));
		start.setFont(font);
		start.setBounds(720, 3, 70, 28);
		this.add(start);

		total = new JLabel("剩余棋子:0");
		total.setFont(font);
		total.setBounds(50, 60, 200, 50);
		this.add(total);

		carry = new JButton("拿走");
		carry.addActionListener(this);
		carry.setFocusable(false);
		carry.setBackground(color);
		carry.setBorder(new LineBorder(color, 0));
		carry.setFont(font);
		carry.setBounds(880, 70, 70, 28);
		this.add(carry);

		main = new JPanel(null);
		main.setBackground(color);
		JScrollPane mainjsp = new JScrollPane(main);
		mainjsp.setBounds(50, 100, 900, 500);
		mainjsp.setBorder(new LineBorder(Color.black, 0));
		mainjsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		this.add(mainjsp);
		this.validate(); // 刷新UI
	}

	@Override
	public void actionPerformed(ActionEvent e) { // 动作监听函数
		if (e.getSource() == stack) { // 监听堆
			int index = stack.getSelectedIndex();
			if (index == 0) {
				max_label.setVisible(true);
				max.setVisible(true);
			} else {
				max_label.setVisible(false);
				max.setVisible(false);
			}
		} else if (e.getSource() == start) {// 如果点击了开始按钮
			Object[] options = { "容易", "一般", "困难" }; // 选择的难度系数
			int response = JOptionPane.showOptionDialog(MyFrame.this, "请选择难度?", "提醒", JOptionPane.YES_NO_CANCEL_OPTION,
					JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
			if (response == 0 || response == 1 || response == 2) { // 如果做了选择
				ratio = response; // 难度系数
				start();
			}
		} else if (e.getSource() == carry) { // 如果点击了拿走按钮
			int select_row = -1;
			if (myLabel == null) {
				JOptionPane.showMessageDialog(MyFrame.this, "请开始游戏", "提示", JOptionPane.CLOSED_OPTION);
				return;
			}
			for (int i = 0; i < myLabel.length; i++) {
				for (int j = 0; j < myLabel[i].length; j++) {
					if (myLabel[i][j].status == 1) {
						if (select_row == -1)
							select_row = i; // 定位到第i行
						if (select_row != i) { // 如果跨行
							JOptionPane.showMessageDialog(MyFrame.this, "选择的棋子不能不在同一行", "提示",
									JOptionPane.CLOSED_OPTION);
							return;
						}
					}
				}
			}
			if (select_row == -1)
				return;
			for (int i = 0; i < myLabel[select_row].length; i++) { // 得到选择的那行
				int status = myLabel[select_row][i].status;
				if (status == 1) {
					ImageIcon iamgeIcon = new ImageIcon("image/black.gif");
					myLabel[select_row][i].setIcon(iamgeIcon);
					myLabel[select_row][i].status = 2;
				}
			}
			total_number -= select;
			total.setText("剩余棋子:" + total_number);
			remainder[select_row] -= select;
			row[select_row].setText("第" + (select_row + 1) + "行剩余:" + remainder[select_row]);
			select = 0;

			if (total_number == 0) {
				JOptionPane.showMessageDialog(MyFrame.this, "您赢了", "提示", JOptionPane.CLOSED_OPTION);
				return;
			}

			new Thread(new Runnable() {
				public void run() {
					try {
						Thread.sleep(1000);
						MyFrame.this.Judge();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
	}

	public void Judge() { // 判断难度系数
		double rand = Math.random(); // 产生随机数
		if (ratio == 0) { // 如果难度系数为容易的时候
			if (rand < 0.2) { // 如果产生的随机数小于0.2,则采用最佳策略
				Computer();
				return;
			}
		} else if (ratio == 1) {// 如果难度系数为普通
			if (rand < 0.4) { // 如果产生的随机数小于0.2,则采用最佳策略
				Computer();
				return;
			}
		} else if (ratio == 2) {// 如果难度系数为困难
			if (rand < 0.8) {// 如果产生的随机数小于0.8,则采用最佳策略
				Computer();
				return;
			}
		}
		Bad(); // 如果没有采用最佳策略,则采用随机策略
	}

	public void Bad() { // 没有胜手的时候,就随机的走
		int ln = (int) (Math.random() * 100) % sstack;
		int circle = 0;
		while (remainder[ln] == 0 && circle < 1000) {
			ln = (int) (Math.random() * 100) % sstack;
			circle++;
		}
		if (remainder[ln] == 0) {
			JOptionPane.showMessageDialog(MyFrame.this, "您赢了", "提示", JOptionPane.CLOSED_OPTION);
			return;
		}
		int cn = (int) (Math.random() * 100) % remainder[ln] + 1;
		if (remainder.length == 1)
			cn = (int) (Math.random() * 100) % smax + 1;
		for (int i = 0, j = 0; i < snumber; i++) {
			if (j >= cn)
				break;
			if (myLabel[ln][i].status == 0) {
				myLabel[ln][i].status = 2;
				ImageIcon imageIcon = new ImageIcon("image/black.gif");
				myLabel[ln][i].setIcon(imageIcon);
				j++;
			}
		}
		remainder[ln] -= cn; // 减少数量
		total_number -= cn; // 减少数量
		total.setText("剩余棋子:" + total_number);
		row[ln].setText("第" + (ln + 1) + "行剩余:" + remainder[ln]);
		if (total_number == 0) {
			JOptionPane.showMessageDialog(MyFrame.this, "真是遗憾,电脑赢了", "提示", JOptionPane.CLOSED_OPTION);
		}
		return;
	}

	public void Computer() { // 计算机行动
		int result = 0;
		for (int i = 0; i < remainder.length; i++) {
			result ^= remainder[i]; // 得到剩余棋子异或的值
		}
		int high = 0; // 最高位
		int temp = result;
		int ln = 0; // 最佳策略的堆号
		int cn = 0; // 最佳策略对应的数量
		while (temp != 0) { // 找到result二进制最高位的位数high
			temp /= 2;
			high++;
		}
		if (result == 0) { // 如果没有胜手,则随机产生一个数字
			Bad();
			return;
		}

		// 让剩下的异或值为0,得到最佳策略
		for (int i = 0; i < remainder.length; i++) {
			String com = Integer.toBinaryString(remainder[i]);
			char[] chars = com.toCharArray();
			if (chars.length >= high) {
				if (chars[chars.length - high] == '1') {// 如果high位为1
					ln = i; // 堆号
					cn = remainder[ln] - (remainder[ln] ^ result); // 数量
					break;
				}
			}
		}

		if (sstack == 1) {// 如果堆数为1
			ln = 0;
			cn = remainder[ln] % (smax + 1);
			if (cn == 0)
				cn = (int) (Math.random() * 100) % smax + 1;
		}
		// 改变标签的内容
		remainder[ln] -= cn; // 减少数量
		total_number -= cn; // 减少数量
		total.setText("剩余棋子:" + total_number);
		row[ln].setText("第" + (ln + 1) + "行剩余:" + remainder[ln]);
		// 改变第ln行的状态
		for (int j = 0; j < myLabel[ln].length; j++) {
			if (cn > 0) {
				if (myLabel[ln][j].status == 0) { // 如果该棋子未被拿掉
					ImageIcon imageIcon = new ImageIcon("image/black.gif");
					myLabel[ln][j].setIcon(imageIcon);
					myLabel[ln][j].status = 2;
					cn--;
				}
			}
		}
		if (total_number == 0) {
			JOptionPane.showMessageDialog(MyFrame.this, "真是遗憾,电脑赢了", "提示", JOptionPane.CLOSED_OPTION);
		}
	}

	public void startGame() { // 开始游戏
		select = 0;
		remainder = new int[sstack];
		for (int i = 0; i < remainder.length; i++) {
			remainder[i] = snumber; // 剩余棋子
		}
		total_number = snumber * sstack;
		judge_total = total_number;
		total.setText("剩余棋子:" + total_number);

		if (sstack != 1)
			smax = snumber;

		row = new JLabel[sstack];
		myLabel = new MyLabel[sstack][snumber];

		int x = 50, y = 30;

		for (int i = 0; i < sstack; i++) {
			row[i] = new JLabel("第" + (i + 1) + "行剩余:" + remainder[i]);
			row[i].setFont(font);
			row[i].setBounds(x, y, 150, 30);
			main.add(row[i]);

			x = 200;
			for (int j = 0; j < snumber; j++) {
				myLabel[i][j] = new MyLabel();
				myLabel[i][j].setBounds(x, y, 30, 30);
				x += 40;
				main.add(myLabel[i][j]);

				final int tempi = i, tempj = j;
				myLabel[i][j].addMouseListener(new MouseAdapter() {
					public void mousePressed(MouseEvent e) {
						int status = myLabel[tempi][tempj].status;
						if (status == 0) {
							if (select < smax) {
								ImageIcon imageIcon = new ImageIcon("image/yellow.gif");
								myLabel[tempi][tempj].setIcon(imageIcon);
								myLabel[tempi][tempj].status = 1;
								select++;
							}
						} else if (status == 1) {
							ImageIcon imageIcon = new ImageIcon("image/white.gif");
							myLabel[tempi][tempj].setIcon(imageIcon);
							myLabel[tempi][tempj].status = 0;
							select--;
						}
					}
				});
			}
			x = 50;
			y += 50;
		}
	}

	public void start() { // 开始游戏的函数
		sstack = Integer.valueOf(stack.getSelectedItem().toString());
		smax = Integer.valueOf(max.getSelectedItem().toString());
		snumber = Integer.valueOf(number.getSelectedItem().toString());
		new Thread(new Runnable() {
			public void run() {
				// 创建新的线程,用于改变UI
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						main.removeAll();
						main.updateUI();
						main.repaint();
						startGame();
					}

				});
			}
		}).start(); // 开启游戏
	}

	public void Course() {
		container.removeAll(); // 去除内容
		container.repaint();
		container.setLayout(null); // 设置为null布局

		JLabel title = new JLabel("●游戏规则");
		title.setFont(font);
		title.setBounds(200, 100, 100, 20);
		this.add(title);

		JLabel content = new JLabel(
				"<html><body>你与电脑玩游戏,你每次能拿若干个棋子(至少一个),<br><br>要求所拿棋子不能跨行。谁拿走最后一颗棋子即获胜。</body></html>");
		content.setFont(new Font("Dialog", 0, 14));
		content.setBounds(200, 120, 1000, 100);
		this.add(content);

		JLabel tips = new JLabel("●温馨提示");
		tips.setFont(font);
		tips.setBounds(200, 250, 100, 20);
		this.add(tips);

		JLabel tip = new JLabel("<html><body>只要剩余棋子的个数异或值不为0,则存在胜手;若<br><br>异或值为0,则不存在胜手。</body></html>");
		tip.setFont(new Font("Dialog", 0, 14));
		tip.setBounds(200, 270, 1000, 100);
		this.add(tip);

		JLabel tip1 = new JLabel(
				"<html><body><font color='red'>旁边剩余棋子分别是3、4、5。3 ^ 4 ^ 5 = 2,不为0,<br><br>说明存在胜手。而胜手即为让剩余的异或值为0</font></body></html>");
		tip1.setFont(new Font("Dialog", 0, 14));
		tip1.setBounds(200, 400, 1000, 100);
		this.add(tip1);

		final JLabel startGame = new JLabel("开始游戏");
		startGame.setFont(font);
		startGame.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				MyFrame.this.Game();
			}

			public void mouseEntered(MouseEvent e) {
				startGame.setBorder(null);
				startGame.setBorder(new SoftBevelBorder(0, Color.white, Color.white));
			}

			public void mouseExited(MouseEvent e) {
				startGame.setBorder(null);
				startGame.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
			}
		});
		startGame.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
		startGame.setBounds(200, 520, 87, 30);
		this.add(startGame);

		final JLabel exit = new JLabel("返回首页");
		exit.setFont(font);
		exit.setBounds(400, 520, 87, 30);
		this.add(exit);
		exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
		exit.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				MyFrame.this.init();
			}

			public void mouseEntered(MouseEvent e) {
				exit.setBorder(null);
				exit.setBorder(new SoftBevelBorder(0, Color.white, Color.white));
			}

			public void mouseExited(MouseEvent e) {
				exit.setBorder(null);
				exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
			}
		});

		MyLabel[][] my = new MyLabel[3][];
		int j = 3;
		for (int i = 0; i < my.length; i++) {
			my[i] = new MyLabel[j++];
		}
		int x = 650, y = 150;
		for (int i = 0; i < my.length; i++) {
			for (j = 0; j < my[i].length; j++) {
				my[i][j] = new MyLabel();
				my[i][j].setBounds(x, y, 30, 30);
				this.add(my[i][j]);
				this.validate();
				x += 40;
			}
			x = 650;
			y += 80;
		}
		this.validate();
	}

	@Override
	public void mouseEntered(MouseEvent e) {
	}

这里写代码片

	@Override
	public void mouseExited(MouseEvent e) {
	}

	@Override
	public void mousePressed(MouseEvent e) {
		if (e.getSource() == manmachine) {
			MyFrame.this.Game();
		} else if (e.getSource() == about) {
			JOptionPane.showMessageDialog(MyFrame.this, "\t\t\t\t版本:V1.0\n\t\t\t\t请期待下一次更新\n\t\t\t\t© Right By Aiden\n",
					"提示", JOptionPane.CLOSED_OPTION);
		} else if (e.getSource() == course) {
			Course();
		} else if (e.getSource() == ppt) {
			try {
				Desktop desktop = Desktop.getDesktop();
				File file = new File("D:\\Aiden\\学习\\大三上\\算法\\汇报PPT\\Nim游戏.pptx");
				desktop.open(file);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	@Override
	public void mouseClicked(MouseEvent e) {
	}
}

Main.java

import java.io.IOException;

public class Main {
	private static void createAndShowGUI() throws IOException {
		new MyFrame(); // 新建MyFrame窗体
	}

	public static void main(String[] args) {
		// UI线程安全
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					createAndShowGUI();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
	}
}

MyLabel.java

import java.awt.Cursor;
import java.awt.Dimension;

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

// 自定义标签,用于加载图片
public class MyLabel extends JLabel {
	public int status; // 标记状态
	private static final long serialVersionUID = 1L; // 序列化,保持对象的唯一性

	public MyLabel() {// 构造函数
		status = 0;
		ImageIcon imageIcon = new ImageIcon("image/white.gif");
		this.setIcon(imageIcon);
		this.setCursor((new Cursor(Cursor.HAND_CURSOR)));
		this.setPreferredSize(new Dimension(30, 30));
		// this.setBorder(new LineBorder(new Color(227, 212, 162), 0));
	}

	public void setImage(int i) {
		if (i == 0) {
			status = 0;
			ImageIcon imageIcon = new ImageIcon("image/white.gif");
			this.setIcon(imageIcon);
		} else if (i == 1) {
			status = 1;
			ImageIcon imageIcon = new ImageIcon("image/yellow.gif");
			this.setIcon(imageIcon);
		} else if (i == 2) {
			status = 2;
			ImageIcon imageIcon = new ImageIcon("image/black.gif");
			this.setIcon(imageIcon);
		}
	}
}

源码下载地址如下:下载地址

标签:Java,Nim,int,void,private,Swing,new,JLabel,public
来源: https://blog.csdn.net/new_Aiden/article/details/50437641

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有