大三Java程序设计课老师让做的大实验,我做了拼图游戏,参考了https://blog.youkuaiyun.com/A1344714150/article/details/84888599这个博主的代码,我的没有实现存储记录和难度选择功能。
运行结果:
主要组成:HelpPanel和GamePanel页面。
源码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
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.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class JigsawPuzzle {
public final static int N = 3;//3*3的拼图
public static void main(String[] args) {
MyFrame frame= new MyFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);//使界面可视
}
static class MyFrame extends JFrame
{
private static final long serialVersionUID = 1L;
private int num=0;//生成随机数
private Image[] pictures;//存储分割后的图片
private int [][] arr;//存储打乱的图片顺序
private int [][] FinalArr;//未打乱正确的图片顺序
int blank_x,blank_y;//记录空白块的下标
int step=0;//记录所走步数
public static HelpPanel panel7;
public static GamePanel panel8;
//构造函数
public MyFrame()
{
num = (int) ( Math.random () * 7 + 1 );//生成随机数,传参,选取图片
setTitle("JigsawPuzzle");
setSize(600,360);
panel7=new HelpPanel(num);
panel8=new GamePanel(num);
add(panel8,"Center");
add(panel7,"East");
}
//右边的帮助页面
public class HelpPanel extends JPanel{
Font font2=new Font("宋体",Font.PLAIN,17);//定义一个字体样式
//定义上,下,左,右,换一张图,退出按钮
JButton UpButton = new JButton("上");
JButton LeftButton = new JButton("左");
JButton DownButton = new JButton("下");
JButton RightButton = new JButton("右");
JButton ChangeButton = new JButton("换一张图");
JButton ExitButton = new JButton("退出");
JPanel panel1=new JPanel(new BorderLayout());
JPanel panel2=new JPanel(new GridLayout(1,3,10,30));
JPanel panel4=new JPanel();
JPanel panel5=new JPanel();
//帮助页面构造函数
public HelpPanel(int nume) {
this.setLayout(new BorderLayout());
PicturePanel panel3=new PicturePanel(nume);
UpButton.setFont(font2);
LeftButton.setFont(font2);
DownButton.setFont(font2);
RightButton.setFont(font2);
ChangeButton.setFont(font2);
ExitButton.setFont(font2);
//帮助页面的布局为Borderlayout,有三个面板panel1,panel2,panel3,分别在为North,South,Center位置
//panel1放“上”,“下”,“左”,“右”按钮;panel2放“换一张图”,“退出”按钮;panel3放正确的帮助图片;
//panel1又分为两个面板panel4,panel5;panel4添加“左”,“下”,“右”按钮,放在panel1的South位置;panel5添加“上”按钮,放在panel1的North位置
panel5.add(UpButton);
panel1.add(panel5,BorderLayout.NORTH);
panel4.add(LeftButton);
panel4.add(DownButton);
panel4.add(RightButton);
panel1.add(panel4, BorderLayout.SOUTH);
panel2.add(ChangeButton);
panel2.add(ExitButton);
this.add(panel1,BorderLayout.NORTH);
this.add(panel3,BorderLayout.CENTER);
this.add(panel2,BorderLayout.SOUTH);
//添加更换图片事件监听器
ChangeButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
num = (int) ( Math.random () * 7 + 1 );//生成随机数
MyFrame.panel7=new HelpPanel(num);
MyFrame.panel8.GetPictures(num);
step=0;
repaint();
MyFrame.panel8.requestFocus();
//点击按钮后焦点到按钮上了,原有键盘监听器的组件失去焦点,requestFocus()使焦点重新回到组件panel8上
}
});
//添加退出事件监听器
ExitButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.exit(0);
}
});
//添加上移事件监听器
UpButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(blank_x!=N-1)
{
MoveUp();
MyFrame.panel8.draw();
}
else
return ;
IsSuccessful();
MyFrame.panel8.requestFocus();
}
});
//添加下移事件监听器
DownButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(blank_x!=0)
{
MoveDown();
MyFrame.panel8.draw();
}
else
return ;
IsSuccessful();
MyFrame.panel8.requestFocus();
}
});
//添加左移事件监听器
LeftButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(blank_y!=N-1)
{
MoveLeft();
MyFrame.panel8.draw();
}
else
return ;
IsSuccessful();
MyFrame.panel8.requestFocus();
}
});
//添加右移事件监听器
RightButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(blank_y!=0)
{
MoveRight();
MyFrame.panel8.draw();
}
else
return ;
IsSuccessful();
MyFrame.panel8.requestFocus();
}
});
}
}
//把图片分成N*N形式从上往下,从左往右赋值为1-9
public void setArr(){
arr=new int [N][N];
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
arr[i][j]=3*i+j+1;//表示把图片分成3*3形式从上往下,从左往右赋值为1-9
}
}
arr[N-1][N-1]=-1;//右下角为空格,值设置为-1;
}
//把图片分成N*N形式从上往下,从左往右赋值为1-9
public void setFinalArr(){
FinalArr=new int [N][N];
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
FinalArr[i][j]=3*i+j+1;//表示把图片分成3*3形式从上往下,从左往右赋值为1-9
}
}
FinalArr[N-1][N-1]=-1;//右下角为空格,值设置为-1;
}
//空白块与下面的方块交换,即有图片的方块上移
private void MoveUp() {
arr[blank_x][blank_y]=arr[blank_x+1][blank_y];
arr[blank_x+1][blank_y]=-1;
blank_x=blank_x+1;
step++;
}
//空白块与上面的方块交换,即有图片的方块下移
private void MoveDown() {
arr[blank_x][blank_y]=arr[blank_x-1][blank_y];
arr[blank_x-1][blank_y]=-1;
blank_x=blank_x-1;
step++;
}
//空白块与右面的方块交换,即有图片的方块左移
private void MoveLeft() {
arr[blank_x][blank_y]=arr[blank_x][blank_y+1];
arr[blank_x][blank_y+1]=-1;
blank_y=blank_y+1;
step++;
}
//空白块与左面的方块交换,即有图片的方块右移
private void MoveRight() {
arr[blank_x][blank_y]=arr[blank_x][blank_y-1];
arr[blank_x][blank_y-1]=-1;
blank_y=blank_y-1;
step++;
}
//帮助页面的正确图片页面
public class PicturePanel extends JPanel{
int W=40;//小方块的大小40*40
//构造函数
public PicturePanel(int nume) {
BufferedImage bufferedImage=null;
int width=0,height=0;
try {
bufferedImage=ImageIO.read(new File("src/picture"+nume+".png"));
System.out.println("选取图片"+nume);
width = bufferedImage.getWidth();
height = bufferedImage.getHeight();
}
catch(IOException e){
e.printStackTrace();
}
pictures=new Image[N*N];
setArr();
int w=width/N,h=height/N;//arr中存储的图片的大小
//裁剪小图
for(int i=0;i<N*N-1;i++) {
int x=i%N*w;
int y=i/N*h;
pictures[i]=bufferedImage.getSubimage(x,y,w,h);
}
}
//显示正确图像pictures[]
public void paint(Graphics g)
{
int tag=0;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
g.drawImage(pictures[tag++], j*W, i*W, W, W,this);//按顺序显示
}
}
}
}
//左边的游戏页面
public class GamePanel extends JPanel implements ActionListener,MouseListener,KeyListener{
int W=100;
public GamePanel(int nume) {
setSize(300,300);
//给控件添加监听器
this.addKeyListener(this);
this.addMouseListener(this);
this.setFocusable(true);
this.setVisible(true);
setFinalArr();//保存正确的图片顺序,方便后面判断是否拼图成功
blank_x=blank_y=N-1;//初始化空白块为右下角
GetPictures(nume);
}
//做10000次移动打乱顺序
private void WrongOrderArr() {
blank_x=blank_y=N-1;//这里必须重新把空白快定位到右下角,否则已经对图片进行操作之后再点击更换图片会出现两个空白块
int i=0;
while(i<10000) {
int j=(int)(Math.random()*100);
if(j<25&&blank_x!=N-1)//空白块不在最后一行时,空白块与下面的方块交换
{
MoveUp();
i++;
}
else if(j<50&&blank_x!=0)//空白快不在第一行时,空白块与上面的方块交换
{
MoveDown();
i++;
}
if(j<75&&blank_y!=N-1)//空白块不在最后一列时,空白块与右面的方块交换
{
MoveLeft();
i++;
}
else if(j<100&&blank_y!=0)//空白块不在第一列时,空白块与左面的方块交换
{
MoveRight();
i++;
}
}
//把空白块移到右下角
while(blank_x<N-1){
MoveUp();
}
while(blank_y<N-1){
MoveLeft();
}
step=0;
}
//画待拼的图
public void GetPictures(int nume) {
WrongOrderArr();
BufferedImage bufferedImage=null;
int width=0,height=0;
try {
bufferedImage=ImageIO.read(new File("src/picture"+nume+".png"));
width = bufferedImage.getWidth();
height = bufferedImage.getHeight();
}
catch(IOException e){
e.printStackTrace();
}
pictures=new Image[N*N];
int w=width/N,h=height/N;//arr中存储的图片的大小
//裁剪小图
for(int i=0;i<N*N-1;i++) {
int x=i%N*w;
int y=i/N*h;
pictures[i]=bufferedImage.getSubimage(x,y,w,h);
}
this.draw();//这里不能直接写repaint(),因为repaint()会调用paint方法,而super.paint(g);这句会清空组件,导致并不会发生重绘
}
public void paint(Graphics g)
{
super.paint(g);
for(int i=0;i<arr.length;i++)
{
for(int j=0;j<arr.length;j++)
{
if(arr[i][j]!=-1)
{
g.drawImage(pictures[arr[i][j]-1], j*W, i*W, W, W,this);//以打乱过的顺序输出图片
}
}
}
}
public void draw() {
repaint();
}
public void keyTyped(KeyEvent e) {
}
//键盘事件,上下左右移动
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_UP&&blank_x!=N-1)
{
MoveUp();
repaint();
}
else if(e.getKeyCode()==KeyEvent.VK_DOWN&&blank_x!=0)
{
MoveDown();
repaint();
}
else if(e.getKeyCode()==KeyEvent.VK_LEFT&&blank_y!=N-1)
{
MoveLeft();
repaint();
}
else if(e.getKeyCode()==KeyEvent.VK_RIGHT&&blank_y!=0)
{
MoveRight();
repaint();
}
else
return;
IsSuccessful();
}
public void keyReleased(KeyEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
//鼠标事件,点击图片进行上下左右移动
public void mousePressed(MouseEvent e) {
int x=e.getX();
int y=e.getY();
//超出图片范围,什么都不做
if(x<0||y<0||x>300||y>300)
return;
//点击的图片对应的数组行列下标
int i=y/W;
int j=x/W;
//空白块在当前点击图片的上面,当前点击图片上移
if(blank_x==i-1&&blank_y==j)
{
MoveUp();
repaint();
}
//空白块在当前点击图片的下面,当前点击图片下移
else if(blank_x==i+1&&blank_y==j)
{
MoveDown();
repaint();
}
//空白块在当前点击图片的左面,当前点击图片左移
else if(blank_x==i&&blank_y==j-1)
{
MoveLeft();
repaint();
}
//空白块在当前点击图片的右面,当前点击图片右移
else if(blank_x==i&&blank_y==j+1)
{
MoveRight();
repaint();
}
else
return;
IsSuccessful();
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void actionPerformed(ActionEvent e) {
}
}
//判断是否拼图完成
//判断拼图是否成功
public void IsSuccessful(){
boolean tag=true;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(arr[i][j]!=FinalArr[i][j])
{
tag=false;
break;
}
}
}
if(tag)
JOptionPane.showMessageDialog(null, "恭喜你拼图成功!!共用"+step+"步");
else
return;
}
}
}
源码zip文件网盘链接:https://pan.baidu.com/s/1UG2tddhOus3IOnGrXxYzAA
提取码:77sz