五子棋课程设计基础
我们小组三人(小白)的成果,参考b站MLDN的五子棋教程
代码如下:
package wuziqi;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
//00点31 57 间隔40
public class FiveChessFrame extends JFrame implements MouseListener, Runnable {
BufferedImage bgImage = null;
int x = 0;
int y = 0;
int[][] allChess = new int[15][15];
boolean isBlack = true;
//表示当前游戏是否继续
boolean canPlay = true;
//保存显示的提示信息
String message="黑方先行";
//保存最多拥有的时间
int maxTime = 0;
//做倒计时的线程类
Thread t = new Thread (this);
//保存黑方与白方的剩余时间
int blackTime = 0;
int whiteTime = 0;
//保存上方剩余时间的显示信息
String blackMessage = "无限制";
String whiteMessage = "无限制";
public FiveChessFrame(){
this.setTitle("五子棋");
this.setSize(900,700);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(this);
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
this.setLocation((width-900)/2, (height-700)/2);
try {
bgImage = ImageIO.read(new File("D:/Pic/background.jpg"));
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
this.setVisible(true);
t.start();
t.suspend();
//刷新屏幕
}
public void paint(Graphics g) {
//双缓冲技术防止屏幕闪烁
//BufferedImage bi = new BufferedImage(900, 700, BufferedImage.TYPE_INT_ARGB);
//Graphics g2 = bi.createGraphics();
g.drawImage(bgImage, 0, 30, this);
g.setFont(new Font("宋体",Font.BOLD,20));
g.drawString("游戏信息:"+message, 50, 50);
g.setFont(new Font("宋体",Font.BOLD,16));
g.drawString("黑方时间:"+blackMessage, 50, 680);
g.drawString("白方时间:"+whiteMessage, 450, 680);
g.setFont(new Font("宋体",Font.BOLD,16));
g.drawString("开始游戏", 722, 88);
g.drawString("游戏设置", 722, 167);
g.drawString("认输", 738, 249);
//棋盘
for(int i=0;i<15;i++) {
g.drawLine(31, 57+40*i, 591, 57+40*i);
g.drawLine(31+40*i, 57, 31+40*i, 617);
}
//棋子
for(int i=0;i<15;i++)
for(int j=0;j<15;j++) {
if(allChess[i][j]==1) {
int tempX=i*40+31;
int tempY=j*40+57;
g.fillOval(tempX-15, tempY-15, 30, 30);
}
if(allChess[i][j]==2) {
int tempX=i*40+31;
int tempY=j*40+57;
g.setColor(Color.WHITE);
g.fillOval(tempX-15, tempY-15, 30, 30);
g.setColor(Color.BLACK);
g.drawOval(tempX-15, tempY-15, 30, 30);
}
}
//g.drawImage(bi, 0, 0, this);
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO 自动生成的方法存根
}
@Override
public void mousePressed(MouseEvent e) {
// TODO 自动生成的方法存根
if(canPlay==true) {
x = e.getX();
y = e.getY();
if(x>=31 && x<=591 && y>=57 && y<=617) {
if((x-31)%40>20) {
x=(x-31)/40+1;
}
else {
x=(x-31)/40;
}
if((y-57)%40>20) {
y=(y-57)/40+1;
}
else {
y=(y-57)/40;
}
if(allChess[x][y]==0) {
if(isBlack==true) {
allChess[x][y]=1;
isBlack=false;
message = "轮到白方";
}
else {
allChess[x][y]=2;
isBlack=true;
message="轮到黑方";
}
//判断输赢,看周围相连是否有五个
boolean winFlag = this.checkWin();
if(winFlag==true) {
JOptionPane.showMessageDialog(this, "Game Over,"+(allChess[x][y]==1?"黑方":"白方")+"获胜!");
canPlay=false;
}
}
//判断输赢,看周围相连是否有五个
this.repaint();
}
}
System.out.println(e.getX()+"--"+e.getY());
if(e.getX() >=678 && e.getX() <=838 && e.getY() >=50 && e.getY() <=115){
int result = JOptionPane.showConfirmDialog(this, "是否重新开始游戏?");
if(result == 0) {
allChess = new int [19][19];
isBlack = true;
canPlay = true;
blackTime = maxTime;
whiteTime = maxTime;
if(maxTime > 0) {
blackMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
whiteMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
}else {
blackMessage = "无限制";
whiteMessage = "无限制";
}
t.resume();
this.repaint();
}
}
if(e.getX() >=678 && e.getX() <=838 && e.getY() >=134 && e.getY() <=194){
String input = JOptionPane.showInputDialog("请输入最大游戏时间(分钟),如果输入0则表示没有时间限制:");
try {
maxTime = Integer.parseInt(input) * 60;
if(maxTime < 0) {
JOptionPane.showMessageDialog(this, "请输入正确信息,不允许时负数!");
}
if(maxTime == 0) {
int result = JOptionPane.showConfirmDialog(this, "设置完成,是否重新开始游戏?");
if(result == 0) {
allChess = new int [19][19];
isBlack = true;
canPlay = true;
blackTime = maxTime;
whiteTime = maxTime;
blackMessage = "无限制";
whiteMessage = "无限制";
this.repaint();
}
}
if(maxTime > 0) {
int result = JOptionPane.showConfirmDialog(this, "设置完成,是否重新开始游戏?");
if(result == 0) {
allChess = new int [19][19];
isBlack = true;
canPlay = true;
blackTime = maxTime;
whiteTime = maxTime;
blackMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
whiteMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
t.resume();
this.repaint();
}
}
}catch(NumberFormatException el) {
JOptionPane.showMessageDialog(this, "请输入正确信息!");
}
}
if(e.getX() >=678 && e.getX() <=838 && e.getY() >=215 && e.getY() <=274){
int result = JOptionPane.showConfirmDialog(this,"是否确认 认输?" );
if(result == 0) {
if(isBlack) {
JOptionPane.showMessageDialog(this, "黑方已经认输,游戏结束!");
canPlay = false;
}
else{
JOptionPane.showMessageDialog(this, "白方已经认输,游戏结束!");
canPlay = false;
}
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO 自动生成的方法存根
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO 自动生成的方法存根
}
@Override
public void mouseExited(MouseEvent e) {
// TODO 自动生成的方法存根
}
public boolean checkWin() {
boolean flag=false;
// 保存共有相同颜色多少棋子相连
int count = 1;
int color = allChess[x][y];
count = this.checkCount(1, 0, color);
if (count>=5) {
flag=true;
} else {
count=this.checkCount(0, 1, color);
if(count>=5) {
flag=true;
} else {
count=this.checkCount(1, -1, color);
if(count>=5) {
flag=true;
} else {
count=this.checkCount(1, 1, color);
if(count>=5) {
flag=true;
}
}
}
}
return flag;
}
private int checkCount(int xChange, int yChange, int color) {
int count = 1;
int tempX = xChange;
int tempY = yChange;
while (x + xChange >= 0 && x + xChange <= 14 && y + yChange >= 0
&& y + yChange <= 14
&& color == allChess[x + xChange][y + yChange]) {
count++;
if (xChange != 0)
xChange++;
if (yChange != 0) {
if (yChange > 0)
yChange++;
else {
yChange--;
}
}
}
xChange = tempX;
yChange = tempY;
while (x - xChange >= 0 && x - xChange <= 14 && y - yChange >= 0
&& y - yChange <= 14
&& color == allChess[x - xChange][y - yChange]) {
count++;
if (xChange != 0)
xChange++;
if (yChange != 0) {
if (yChange > 0)
yChange++;
else {
yChange--;
}
}
}
return count;
}
@Override
public void run() {
// TODO 自动生成的方法存根
//判断是否有时间限制
if(maxTime > 0) {
while(true) {
if(isBlack) {
blackTime-- ;
if(blackTime == 0) {
JOptionPane.showMessageDialog(this, "黑方超时,游戏结束");
canPlay = false;
t.stop();
}
}else {
whiteTime-- ;
if(whiteTime == 0) {
JOptionPane.showMessageDialog(this, "白方超时,游戏结束");
canPlay = false;
t.stop();
}
}
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
blackMessage = blackTime/3600+":"+(blackTime/60-blackTime/3600*60)+":"+(blackTime-blackTime/60*60);
whiteMessage = whiteTime/3600+":"+(whiteTime/60-whiteTime/3600*60)+":"+(whiteTime-whiteTime/60*60);
this.repaint();
System.out.println(blackTime + "--"+whiteTime);
}
}
}
}
我负责的主要部分为各个按钮的实现与控制以及倒计时的设置。
(1)各个按钮的实现与控制
其中的难点在于每个按钮的使用过程中都是有一些联系的,不然会出现意想不到的bug。例如“认输”按钮后面canPlay = false;会影响接下来的使用,会使认输之后再重新开始后不能落子,所以必须在每一个有重新开始功能的按钮下加入canPlay = true;
allChess = new int【19】【19】作用就是清空棋盘。注:【19】【19】应该为【15】【15】否则会出现bug。
if(e.getX() >=678 && e.getX() <=838 && e.getY() >=50 && e.getY() <=115){
int result = JOptionPane.showConfirmDialog(this, "是否重新开始游戏?");
if(result == 0) {
allChess = new int [19][19];
isBlack = true;
canPlay = true;
blackTime = maxTime;
whiteTime = maxTime;
if(maxTime > 0) {
blackMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
whiteMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
}else {
blackMessage = "无限制";
whiteMessage = "无限制";
}
t.resume();
this.repaint();
}
}
if(e.getX() >=678 && e.getX() <=838 && e.getY() >=134 && e.getY() <=194){
String input = JOptionPane.showInputDialog("请输入最大游戏时间(分钟),如果输入0则表示没有时间限制:");
try {
maxTime = Integer.parseInt(input) * 60;
if(maxTime < 0) {
JOptionPane.showMessageDialog(this, "请输入正确信息,不允许时负数!");
}
if(maxTime == 0) {
int result = JOptionPane.showConfirmDialog(this, "设置完成,是否重新开始游戏?");
if(result == 0) {
allChess = new int [19][19];
isBlack = true;
canPlay = true;
blackTime = maxTime;
whiteTime = maxTime;
blackMessage = "无限制";
whiteMessage = "无限制";
this.repaint();
}
}
if(maxTime > 0) {
int result = JOptionPane.showConfirmDialog(this, "设置完成,是否重新开始游戏?");
if(result == 0) {
allChess = new int [19][19];
isBlack = true;
canPlay = true;
blackTime = maxTime;
whiteTime = maxTime;
blackMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
whiteMessage = maxTime/3600+":"+(maxTime/60-maxTime/3600*60)+":"+(maxTime-maxTime/60*60);
t.resume();
this.repaint();
}
}
}catch(NumberFormatException el) {
JOptionPane.showMessageDialog(this, "请输入正确信息!");
}
}
if(e.getX() >=678 && e.getX() <=838 && e.getY() >=215 && e.getY() <=274){
int result = JOptionPane.showConfirmDialog(this,"是否确认 认输?" );
if(result == 0) {
if(isBlack) {
JOptionPane.showMessageDialog(this, "黑方已经认输,游戏结束!");
canPlay = false;
}
else{
JOptionPane.showMessageDialog(this, "白方已经认输,游戏结束!");
canPlay = false;
}
}
}
(2)倒计时的设置
前面的声明定义就不展示了,设计倒计时的重点之一就是,要让倒计时结束时停止计时,要用到t.stop() (当然这类方法已经过时了但是其他的不会用) 并且要在此之前加入canPlay = false;否则计时结束分出胜负后依然能下棋。
if(maxTime > 0) {
while(true) {
if(isBlack) {
blackTime-- ;
if(blackTime == 0) {
JOptionPane.showMessageDialog(this, "黑方超时,游戏结束");
canPlay = false;
t.stop();
}
}else {
whiteTime-- ;
if(whiteTime == 0) {
JOptionPane.showMessageDialog(this, "白方超时,游戏结束");
canPlay = false;
t.stop();
}
}
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
blackMessage = blackTime/3600+":"+(blackTime/60-blackTime/3600*60)+":"+(blackTime-blackTime/60*60);
whiteMessage = whiteTime/3600+":"+(whiteTime/60-whiteTime/3600*60)+":"+(whiteTime-whiteTime/60*60);
this.repaint();
System.out.println(blackTime + "--"+whiteTime);
}
}
其他的bug暂时没发现,第一次写程序练手多多包涵!
效果如下:
背景图片为江流儿(网图),各位可以自行设计背景图片。这个程序会出现屏闪问题,目前也不会修复,还请各位大佬指点。