java里nim游戏问题_Java Swing:Nim游戏实现

接手项目时对方所提的需求,其实用javaweb来实现的话基本没有难度,但是要用Swing去实现这个功能,还是一件蛮棘手的事情,中间也遇到了好多衍生出来的问题,利用这篇博客做一个记录。 先上一张最后的效果图: 可以根据输入框中文字的改变生成不同的提示,并且

由于作业需要,编写了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 stack; // 堆输入框

private JLabel max_label; // 每次拿的上限

private JLabel number_label; // 每堆的数量标签

private JComboBox number; // 每堆的数量

private JComboBox 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(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(

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(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 =(原创) 测试代码,解决java gui swing多线程界面假死、僵死问题,实现界面动态刷新,动态更新,同步显示数据 主类: package testguimulitiplethread; /** * * @author Administrator */ public class Main {

/**

* @param args the command line= 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(

"

你与电脑玩游戏,你每次能拿若干个棋子(至少一个),
要求所拿棋子不能跨行。谁拿走最后一颗棋子即获胜。");

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("

只要剩余棋子的个数异或值不为0,则存在胜手;若
异或值为0,则不存在胜手。");

tip.setFont(new Font("Dialog", 0, 14));

tip.setBounds(200, 270, 1000, 100);

this.add(tip);

JLabel tip1 = new JLabel(

"

旁边剩余棋子分别是3、4、5。3 ^ 4 ^ 5 = 2,不为0,
说明存在胜手。而胜手即为让剩余的异或值为0
");

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

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值