Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6170
  • 博文数量: 6
  • 博客积分: 1450
  • 博客等级: 上尉
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-24 21:52
文章分类

全部博文(6)

文章存档

2011年(2)

2010年(2)

2009年(2)

我的朋友
最近访客

分类: Java

2010-09-27 21:15:09

扫雷不能不说一款非常经典的游戏,无聊时候可以打发时间,虽然玩了很久,但还不知道它是怎么写的,所以自己就尝试动手做了个。

众所周知,java的swing采用mvc模式,即模型-视图-控制器,所以如果真的了解了这个模式,较c++,用java做个游戏还是比较容易的。下面是我写的扫雷的代码

import java.awt.*;
import java.io.*;
import java.net.URL;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.concurrent.*;
public class MineSweep
{
    public static void main(String[] args)
    {
            JFrame frame = new MineFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
    }
}

class MineFrame extends JFrame
{
    private JPanel buttonPanel;
    private MinePanel mp;
    private int rn,cn;
    public static final int DEFAULT_WIDTH = 650;
    public static final int DEFAULT_HEIGHT = 450;
    public static final int DEFAULT_CN = 9;
    public static final int DEFAULT_RN = 9;
    public JLabel remainMine;
    public JLabel mes;
    private JComboBox cb;
    public MineFrame()
    {
        setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
        setTitle("扫雷");
        mp = new MinePanel(DEFAULT_CN,DEFAULT_RN,this);
        mp.setMinenum(10);
        mp.setRC(9,9);
        buttonPanel = new JPanel();

        add(mp,BorderLayout.CENTER);
        mes = new JLabel("");
        mes.setEnabled(false);
        add(mes,BorderLayout.EAST);
        cb = new JComboBox();
        cb.setEditable(true);
        cb.addItem("初级");
        cb.addItem("中级");
        cb.addItem("高级");
        cb.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
        {
            int index = cb.getSelectedIndex();
            System.out.println(index);
            switch(index)
        {
            case 0:
            mp.setMinenum(10);
            mp.setRC(9,9);
            break;
            case 1:
            mp.setMinenum(40);
            mp.setRC(16,16);
            break;
            case 2:
            mp.setMinenum(99);
            mp.setRC(30,16);
            break;
        }
        }
                }
                );
        JButton showAll = new JButton("显示所有地雷");
        showAll.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
        {
            mp.showMines();
        }
                }
                );
        buttonPanel.add(showAll);

        JButton replay = new JButton("重新开始");
        replay.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
        {
            mp.updateMines();
        }
                }
                );
        buttonPanel.add(replay);
        buttonPanel.add(cb);

         remainMine = new JLabel("剩余雷数:" +mp.getMinenum());
        add(remainMine,BorderLayout.SOUTH);
        add(buttonPanel,BorderLayout.NORTH);

    }

}

class Pair
{
    public Pair(int r,int c)
    {
        this.r = r;
        this.c =c;
    }
    public int r;
    public int c;
}
class MinePanel extends JPanel implements MouseListener
{
    private int cn,rn;
    private int minenum;
    private Mine[][] mines;
    private int hideMine = minenum;
    private int ableMn ;
    private MineFrame f;
    private boolean over ;
    private int w,h;
    private boolean win;
    public static ArrayList<Image> IMAGES = new ArrayList<Image>(12);
    public MinePanel(int rn,int cn,MineFrame f)
    {
            
        IMAGES.add(new ImageIcon(getURL(".\\img\\0.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\1.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\2.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\3.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\4.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\5.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\6.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\7.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\8.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\mine.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\11.gif")).getImage());
        IMAGES.add(new ImageIcon(getURL(".\\img\\12.gif")).getImage());
        this.f = f;
        this.rn = rn;
        this.cn = cn;
        this.ableMn = rn * cn;
        addMouseListener(this);
        updateMines();
    }
    public URL getURL(String file)
    {
        URL url =null;
        try
        {
            url = this.getClass().getResource(file);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return url;
    }

    public void decAbleMn()
    {
        ableMn --;
    }
    public int getAbleMn()
    {
        return ableMn;
    }
    public void decHideMine()
    {
    hideMine --;
    }    

    public void incHideMine()
    {
        hideMine ++;
    }
    public int getHideMine()
    {
        return hideMine;
    }

    public void setMinenum(int n)
    {
        minenum = n;
    }

    public int getMinenum()
    {
        return minenum;
    }
    public void mousePressed(MouseEvent e)
    {    
        if(!over)
        {
            int x = (int)e.getX();
            int y = (int)e.getY();
            int keyCode = e.getButton();
            int c,r;
            r = x/Mine.WIDTH;
            c = y/Mine.HEIGHT;
            switch(keyCode)
            {
                case MouseEvent.BUTTON1:
                    if(mines[r][c].getFlag() == false)
                    {
                        try
                        {
                            mines[r][c].setOpen();
                            decAbleMn();
                            if(mines[r][c].getImage() == 9)
                            {
                                over = true;
                                decHideMine();
                                showMines();
                            }
                            else if(mines[r][c].getImage() == 0)
                            {
                                if(getAbleMn() == rn * cn - minenum)
                                {
                                    win = true;
                                }
                                openNear(r,c);
                            }
                        }
                        catch(Exception ex)
                        {
                            //e.printStackTrace();

                        }
                        repaint();
                    }
                    break;
                case MouseEvent.BUTTON3:
                    if( mines[r][c].isOpen() == false || mines[r][c].getFlag() == true)
                    {
                        if(mines[r][c].getFlag() == true)
                        {
                            incHideMine();
                            mines[r][c].setFlag();
                            repaint();
                        }
                        else if(hideMine > 0)
                        {
                            mines[r][c].setFlag();
                            decHideMine();
                            repaint();
                        }
                    }
                    break;
            }
        }
    }
    public void mouseReleased(MouseEvent e)
    {
    }
    public void mouseClicked(MouseEvent e)
    {
    }
    public void mouseEntered(MouseEvent e)
    {}
    public void mouseExited(MouseEvent e)
    {}

    private ArrayDeque<Pair> queue = new ArrayDeque<Pair>(20);
    public void openNear(int r,int c)
    {
        int i,j;
        i = r;
        j = c;
        for(int n = -1; n <= 1; n ++)
        {
            r = i + n;
            if(r >= 0 && r <mines.length)
                for(int k = -1; k <=1; k ++)
                {
                    c = j + k;
                    if(c >= 0 && c < mines[r].length)
                    {
                        if(mines[r][c].isOpen() == false && mines[r][c].getImage() == 0)
                        {
                            mines[r][c].setOpen();
                            queue.add(new Pair(r,c));
                        }
                        else
                        {
                            if(mines[r][c].getFlag() ==true)
                        {
                            mines[r][c].setFlag();
                            incHideMine();
                        }
                            mines[r][c].setOpen();
                        }
                    }
                }
        }
        for(i = 0 ;i < queue.size(); i ++)
        {
            Pair p = queue.poll();
            openNear(p.r,p.c);
        }
        
    }

    public void setRC(int rn,int cn)
    {
        this.rn = rn;
        this.cn = cn;
        updateMines();
        repaint();
    }

    public void updateMines()
    {
        removeAll();
        win = false;
        over = false;
        f.setSize((10 +rn) * 20,(cn + 10) * 20);
        setSize(rn * Mine.HEIGHT,cn * Mine.WIDTH);
        mines = new Mine[rn][cn];
        for(int i = 0;i < mines.length;i ++)
            for(int j = 0 ;j < mines[i].length; j ++)
            {
                mines[i][j] = new Mine(i,j);
            }
        int mn = getMinenum();
        hideMine = mn;
        for(int i = 0; i <mn;i ++)
        {
            int r,c;
            do
            {
             r = (int)(Math.random() * rn);
             c = (int)(Math.random() * cn);
            }while(mines[r][c].getImage() == 9);
            mines[r][c].setImage(9);
        }
        generateNum();
        repaint();
    }

    public void generateNum()
    {
        int r,c;
        for(int i = 0 ;i < mines.length;i ++)
            for(int j = 0 ;j < mines[i].length; j ++)
                if(mines[i][j].getImage() != 9)
                {
                    int cnum = 0 ;
                    for(int n = -1; n <= 1; n ++)
                    {
                        r = i + n;
                        if(r >= 0 && r < mines.length)
                        for(int k = -1 ;k <=1; k ++)
                        {
                            c = j + k;
                            if(c >= 0 && c < mines[i].length)
                            {
                                if(mines[r][c].getImage() == 9)
                                    cnum ++;
                            }
                        }
                    }
                    mines[i][j].setImage(cnum);
                }
    }




    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        int c = 0;
        Graphics2D g2 = (Graphics2D) g;
        for(int i = 0 ;i < mines.length; i ++)
            for(int j = 0 ;j < mines[i].length; j ++)
            {
                g2.setColor(mines[i][j].getColor());
                g2.draw(mines[i][j].getShape());
                if(mines[i][j].getFlag() == true && mines[i][j].isOpen() == false)
                    g.drawImage(IMAGES.get(10),mines[i][j].getW(),mines[i][j].getH(),Mine.HEIGHT,Mine.WIDTH,this);
                if(mines[i][j].isOpen()&& mines[i][j].getFlag() == false )
                {
                    g.drawImage(IMAGES.get(mines[i][j].getImage()),mines[i][j].getW(),mines[i][j].getH() ,Mine.HEIGHT,Mine.WIDTH,this);
                
                
                    c ++;
                }

            }
        f.remainMine.setText("剩余雷数:" + getHideMine() );
        
    }
    public void showMines()
    {
        removeAll();
        for(int i = 0 ;i <mines.length; i ++)
            for(int j = 0 ; j < mines[i].length; j ++)
            {
                if(mines[i][j].getImage() == 9)
                {
                    if(mines[i][j].getFlag() == false)
                    mines[i][j].setOpen();
                }
                else
                {
                    if(mines[i][j].getFlag() == true)
                    {
                        mines[i][j].setOpen();
                        mines[i][j].setFlag();
                        mines[i][j].setImage(11);
                    }
                }

            }
        hideMine = 0;
        repaint();
    }
}

class Mine
{
    private    Rectangle2D rect = null;
    public static final ImageIcon IMAGE = new ImageIcon("mine.gif");
    public static final int HEIGHT = 20;
    public static final int WIDTH = 20;
    private boolean flag = false;
    private boolean open = false;
    public static final Color DEFAULT_COLOR = Color.BLACK;
    private int image = 0;
    private Color color;
    private boolean isMine = false;
    private int w,h;
    public Mine(int r,int c)
                {

                    this.w = r * HEIGHT;
                    this.h = c * HEIGHT;
                    rect = new Rectangle2D.Double(1.0D *r * HEIGHT,1.0D *c * WIDTH ,1.0D *HEIGHT,1.0D *WIDTH);
                    setColor(DEFAULT_COLOR);
                }



    public void setMine()
    {
        isMine = true;
    }
    public boolean isMine()
    {
        return isMine;
    }

    public void setColor(Color c)
    {
        this.color = c;
    }
    public Color getColor()
    {
        return color;
    }

    public void setOpen()
    {
        open = true;
    }

    public boolean isOpen()
    {
        return open;
    }

    public void setImage(int n)
    {
        image =n;
    }

    public int getImage()
    {
        return image;
    }

    public int getW()
    {
        return w;
    }
    public int getH()
    {
        return h;
    }

    public void setFlag()
    {
        flag = !flag;
    }
    public boolean getFlag()
    {
        return flag;
    }
    public Shape getShape()
    {
        return rect;
    }
}

代码主要包含三个类,MineSweep,MinePanel和Mine类。

MineSweep包含main函数,为程序的入口,此外还负责初始化一个游戏界面的框架。

MinePanel为整个程序的核心,负责响应鼠标事件,游戏逻辑的处理,视图的刷新。其包含的openNear和generateNum方法为逻辑处理的核心。openNear方法主要功能是当被打开的一个方格不包含任何内容时(即它周围不包含雷),则它打开周围不为地雷的方格。这个方法主要用到广度优先搜索算法,用一个队列实现。而generateNum方法目的是初始化地图,即它是生成每个雷周围的数字。

Mine表示每个方格,里面包含每个方格的属性,flag是判断该方格是否被右键标上旗子,open判断该格子是否已经被打开,isMine判断是否是地雷,此外还有其他属性。

整个程序的逻辑流程如下


  最后,附上程序包。解压后直接双击扫雷.jar即可运行。

文件:MineSweep.zip
大小:30KB
下载:下载




阅读(728) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-09-28 15:49:22

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com