First Entry on is-programmer.com
convert int to string in C

MineSweeperGame powered by Java Swing

Kavinyao posted @ Mar 15, 2010 09:11:43 PM in 学习心得 with tags java Swing game MineSweeper , 2965 阅读

During this winter vacation, I got addicted to the MineSweeper, one of the Games shipped with Windows. Since I am learning Java SE at present, I kept wondering if I could build my own MineSweeper Game with Java Swing. I was not sure though the internal logic of this game is really simple. It was not until the senior told us that there is never a goal that high at the annual Awards of Software Innovation Competitive that I made up my mind to build that. I really appreciate the senior who inspired me, and after a day’s work, beta1 was released, though there was only one tester, me.


I enjoyed the process of making it. Turning a thought floating in the air to a practical product is not so easy, certainly. There’s much things I haven’t learned but are essential to the game. So I have to keep baiduing and googling, looking up API all the time and getting rid of each error I met. The process is painful but the result is fruitful. Not only do I have a runnable program, but experiences gained from building something from void. (that’s absolutely exaggeration, because I have a ready-made MineSweeper.)


As mentioned above, the game is just ‘runnable’, it is of low-efficiency so don’t expect too much from it. Here’s the source code you may want to look at. It involves the use of java.swing classes,  MouseListener Interface, inner classes, ArrayList, class inheritance and some simple logic controls. Hope that you will get something useful from it.


A last word I’d like to share with you: there is never a goal that high.
 

 

/*
  *ATTENTION:If this source file is distributed, this annotation should NOT be removed.
  *MineSweeper Beta2, the real MineSweeper Game
  *Author:Kavinyao
  *Date:2010-03-13
  *Instructions:
    *Use Generate Button to start a new game
    *Use Easy Start Button to get an easy start
    *Use mouse to click:
      **Left click: remove a block
      **Middle click: intelligent clear around blocks
      **Right click: mark/unmark mines
*/

//ATTENTION: The game may run not as smoothly as you expected.
//Your click may not get respond properly. And I don't know why this occurs.
//Maybe the swing module parts are not so efficient.
//Or maybe my algorithm is of too low efficiency.
//If you know why don't hesitate to tell me about it.
//So, please take ease when playing the game.
//I haven't added a time counter to take your time and keep records. Maybe next version. :)

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class MineSweeperGame implements MouseListener{
    JPanel mainPanel;
    ArrayList<MineButton> buttonList;
    JFrame theFrame;
    JLabel lblMineNumberCounter;
    JLabel lblGamesPlayed;
    JLabel lblGamesWon;
    JLabel lblWinRate;
    JLabel lblCaption;
    boolean isActive;
    int fieldsToClear;
    
    public static void main(String[] args){
        MineSweeperGame mineSweeper = new MineSweeperGame();
        mineSweeper.biuldGui();
    }
    
    public void biuldGui(){
        //GUI setup
        theFrame = new JFrame("Mine Sweeper Beta2 by Kavinyao");
        theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        BorderLayout layout = new BorderLayout();
        JPanel background = new JPanel(layout);
        background.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        
        buttonList = new ArrayList<MineButton>();
        Box buttonBox = new Box(BoxLayout.Y_AXIS);
        
        JButton generateMap = new JButton("Generate");
        generateMap.addActionListener(new MyGenerateListener());
        buttonBox.add(generateMap);
        
        JButton easyStart = new JButton("Easy Start");
        easyStart.addActionListener(new EasyStartListener());
        buttonBox.add(easyStart);
        
        JLabel lblMineNumberText = new JLabel("Mines Left:");
        //lblMineNumberText.setFont(new Font("Arial",1,20));
        lblMineNumberCounter = new JLabel("99");
        //lblMineNumberCounter.setFont(new Font("Arial",1,20));
        lblCaption = new JLabel("Enjoy Game!");
        buttonBox.add(lblMineNumberText);
        buttonBox.add(lblMineNumberCounter);
        buttonBox.add(lblCaption);
        
        JLabel lblGamesPlayedText = new JLabel("Games Played:");
        lblGamesPlayed = new JLabel("0");
        buttonBox.add(lblGamesPlayedText);
        buttonBox.add(lblGamesPlayed);
        
        JLabel lblGamesWonText = new JLabel("Games Won:");
        lblGamesWon = new JLabel("0");
        buttonBox.add(lblGamesWonText);
        buttonBox.add(lblGamesWon);
        
        JLabel lblWinRateText = new JLabel("Win Rate");
        lblWinRate = new JLabel("0");
        buttonBox.add(lblWinRateText);
        buttonBox.add(lblWinRate);
        
        background.add(BorderLayout.EAST,buttonBox);
        
        theFrame.getContentPane().add(background);
        
        isActive = true;
        
        GridLayout grid = new GridLayout(16,30);//make a mine map using grid layout
        grid.setVgap(0);
        grid.setHgap(0);
        mainPanel = new JPanel(grid);
        background.add(BorderLayout.CENTER,mainPanel);
        
        for(int i=0;i<30*16;i++){
            MineButton mb = new MineButton();//use button as a minefield
            mb.setFont(new Font("Monaco",0,14));
            mb.addMouseListener(this);//use the frame as listener
            buttonList.add(mb);
            mainPanel.add(mb);
        }
        
        //a problem occurs to display the text of a MineButton, so I have to
        //make the frame as large as possible in order to make the text on buttons appear properly
        theFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        theFrame.setVisible(true);
    }
    
    //--------------------------------------inner classes here!--------------------------------------
    private class MineButton extends JButton{
        private int mineNumber;//mineNumber keeps the number of mines around if this field doesn't have a mine
        private boolean isMine;
        private boolean isMarkedMine;//used together with toggleMarkedMine() method
        
        public int getMineNumber(){
            return this.mineNumber;
        }
        
        public void setMineNumber(int mineNumber){
            this.mineNumber = mineNumber;
        }
        
        public boolean checkIsMine(){
            return this.isMine;
        }
        
        public void setIsMine(boolean isMine){
            this.isMine = isMine;
        }
        
        public boolean checkIsMarkedMine(){
            return this.isMarkedMine;
        }
        
        public void setIsMarkedMine(boolean isMarkedMine){
            this.isMarkedMine = isMarkedMine;
        }
        
        public void toggleMarkedMine(){
            //this method is called when right click on field is met
            if(this.getBackground() != Color.WHITE){
                int mineNumber = Integer.parseInt(lblMineNumberCounter.getText());
                if(this.isMarkedMine){
                    this.isMarkedMine = false;
                    this.setBackground(Color.CYAN);
                    mineNumber++;
                }else{
                    this.isMarkedMine = true;
                    this.setBackground(Color.RED);
                    mineNumber--;
                }
                lblMineNumberCounter.setText(Integer.toString(mineNumber));
            }
        }
    }
    
    private class MyGenerateListener implements ActionListener{
        public void actionPerformed(ActionEvent ev){
            generateMap();
        }
    }
    
    private class EasyStartListener implements ActionListener{
        public void actionPerformed(ActionEvent ev){
            if((Integer.parseInt(lblMineNumberCounter.getText())) == 99){
                boolean isFound = false;
                for(int coordinateY = 5;(coordinateY < 16)&&(!isFound);coordinateY++){
                    for(int coordinateX = 10;(coordinateX < 30)&&(!isFound);coordinateX++){
                        MineButton mb = (MineButton)(buttonList.get(30*coordinateY+coordinateX));
                        if(mb.getMineNumber() == 0){
                            isFound = true;
                            revealMine(coordinateX,coordinateY);
                            revealAround(coordinateX,coordinateY);
                        }
                    }
                }
            }
        }
    }
    //--------------------------------------methods here!--------------------------------------
    private void generateMap(){
        int coordinateX;
        int coordinateY;
        int mineNumberLeft = 99;
        
        //initialize state of all minefields
        isActive = true;
        fieldsToClear = 381;
        for(coordinateY = 0;coordinateY < 16;coordinateY++){
            for(coordinateX = 0;coordinateX < 30;coordinateX++){
                MineButton mb = (MineButton)(buttonList.get(30*coordinateY+coordinateX));
                mb.setText(" ");
                mb.setMineNumber(-1);
                mb.setIsMine(false);
                mb.setIsMarkedMine(false);
                mb.setBackground(Color.CYAN);
            }
        }
        
        lblMineNumberCounter.setText("99");
        lblCaption.setText("Enjoy Game!");

        while(mineNumberLeft > 0){
            //generate random mines
            coordinateX = (int)(Math.random()*30);
            coordinateY = (int)(Math.random()*16);
        
            MineButton mb = (MineButton)buttonList.get(30*coordinateY+coordinateX);
        
            if(mb.checkIsMine()){
                continue;
            }else{
                mb.setIsMine(true);
                mineNumberLeft--;
            }
        }
        
        //set mineNumber to fields without mines
        for(coordinateY = 0;coordinateY < 16;coordinateY++){
            for(coordinateX = 0;coordinateX < 30;coordinateX++){
                MineButton mb = (MineButton)(buttonList.get(30*coordinateY+coordinateX));
                if(!(mb.checkIsMine())){
                    int aroundMineNumber = 0;
                    aroundMineNumber += checkMine(coordinateX-1,coordinateY-1,0);
                    aroundMineNumber += checkMine(coordinateX-1,coordinateY,0);
                    aroundMineNumber += checkMine(coordinateX-1,coordinateY+1,0);
                    aroundMineNumber += checkMine(coordinateX,coordinateY-1,0);
                    aroundMineNumber += checkMine(coordinateX,coordinateY+1,0);
                    aroundMineNumber += checkMine(coordinateX+1,coordinateY-1,0);
                    aroundMineNumber += checkMine(coordinateX+1,coordinateY,0);
                    aroundMineNumber += checkMine(coordinateX+1,coordinateY+1,0);
                    
                    mb.setMineNumber(aroundMineNumber);
                }
            }
        }
    }
    
    private int checkMine(int coordinateX,int coordinateY,int flag){
        //flag == 0, check whether a field really contains a mine
        //flag == 1, check whether a field has been markedas a mine
        if((coordinateX >= 0)&&(coordinateY >= 0)&&(coordinateX < 30)&&(coordinateY < 16)){
            MineButton mb = (MineButton)(buttonList.get(30*coordinateY+coordinateX));
            
            if(((flag == 0)&&(mb.checkIsMine()))||((flag == 1)&&(mb.checkIsMarkedMine()))){
                return 1;
            }
        }
        
        return 0;
    }
    
    private void revealMine(int coordinateX,int coordinateY){
        //reveal a mine field. If the field contains a mine, you lose.
        if((coordinateX >= 0)&&(coordinateY >= 0)&&(coordinateX < 30)&&(coordinateY < 16)){
            MineButton mb = (MineButton)(buttonList.get(30*coordinateY+coordinateX));
            if(mb.checkIsMine()){
                loseGame();
            }else{
                if(mb.getBackground() != Color.WHITE){
                    mb.setText(Integer.toString(mb.getMineNumber()));
                    mb.setBackground(Color.WHITE);
                    fieldsToClear--;
                    
                    //if a field contains no mine, all its fields around are safe to reveal
                    if(mb.getMineNumber() == 0){
                        mb.setText(" ");
                        revealAround(coordinateX,coordinateY);
                    }
                }
            }
        }
    }
    
    private void testAround(int coordinateX,int coordinateY){
        //method accomplishing intelligent clear
        int aroundMineNumber = 0;
        MineButton mb = (MineButton)(buttonList.get(30*coordinateY + coordinateX));
        aroundMineNumber += checkMine(coordinateX-1,coordinateY-1,1);
        aroundMineNumber += checkMine(coordinateX-1,coordinateY,1);
        aroundMineNumber += checkMine(coordinateX-1,coordinateY+1,1);
        aroundMineNumber += checkMine(coordinateX,coordinateY-1,1);
        aroundMineNumber += checkMine(coordinateX,coordinateY+1,1);
        aroundMineNumber += checkMine(coordinateX+1,coordinateY-1,1);
        aroundMineNumber += checkMine(coordinateX+1,coordinateY,1);
        aroundMineNumber += checkMine(coordinateX+1,coordinateY+1,1);
        
        if(aroundMineNumber == mb.getMineNumber()){
            for(int x = coordinateX - 1;x < coordinateX + 2;x++){
                for(int y =coordinateY -1;y < coordinateY +2;y++){
                    if(((x != coordinateX)||(y != coordinateY))&&(x >= 0)&&(y >= 0)&&(x < 30)&&(y < 16)){
                        MineButton mb2 = (MineButton)(buttonList.get(30*y + x));
                        if(!(mb2.checkIsMarkedMine())){
                            revealMine(x,y);
                        }
                    }
                }
            }
        }
    }
    
    private void revealAround(int coordinateX,int coordinateY){
        //interactively used with normal check and intelligent clear methods
        revealMine(coordinateX-1,coordinateY-1);
        revealMine(coordinateX-1,coordinateY);
        revealMine(coordinateX-1,coordinateY+1);
        revealMine(coordinateX,coordinateY-1);
        revealMine(coordinateX,coordinateY+1);
        revealMine(coordinateX+1,coordinateY-1);
        revealMine(coordinateX+1,coordinateY);
        revealMine(coordinateX+1,coordinateY+1);
    }
    
    private void checkIsWin(){
        //method called each time a click is finished to check if you have won
        if(fieldsToClear == 0){
        lblCaption.setText("YOU WIN!");
        isActive = false;
        doStatistics(true);
        }
    }
    
    private void loseGame(){
        //method deals with situation in which you lose the game
        lblCaption.setText("YOU LOSE");
        isActive = false;
        for(int coordinateX = 0;coordinateX < 30; coordinateX++){
            for(int coordinateY = 0;coordinateY < 16;coordinateY++){
                MineButton mb = (MineButton)(buttonList.get(30*coordinateY + coordinateX));
                if(mb.checkIsMine()){
                    mb.setBackground(Color.RED);
                }else if(mb.checkIsMarkedMine()){
                    mb.setBackground(Color.ORANGE);
                }else{
                    mb.setBackground(Color.WHITE);
                    int mineNumber = mb.getMineNumber();
                    if(mineNumber==0){
                        mb.setText(" ");
                    }else{
                        mb.setText(Integer.toString(mineNumber));
                    }
                }
            }
        }
        
        doStatistics(false);
    }
    
    private void doStatistics(boolean isWin){
        int gamesPlayed = Integer.parseInt(lblGamesPlayed.getText());
        gamesPlayed++;
        lblGamesPlayed.setText(Integer.toString(gamesPlayed));
        int gamesWon = Integer.parseInt(lblGamesWon.getText());
        
        if(isWin){
            gamesWon++;
            lblGamesWon.setText(Integer.toString(gamesWon));
        }
        
        int winRate = gamesWon * 100 / gamesPlayed;
        lblWinRate.setText((Integer.toString(winRate))+"%");
    }
    
    //--------------------------------------overridden methods from MouseListener interface--------------------------------------
    public void mouseClicked(MouseEvent me) {
        if(isActive){
            MineButton mb = (MineButton)(me.getSource());
        
            if(me.getModifiers() == me.BUTTON1_MASK){
                //Left Button Clicked
                if((mb.getBackground() != Color.RED)&&(mb.getBackground() != Color.WHITE)){
                    if(mb.checkIsMine()){
                        loseGame();
                    }else{
                        int index = buttonList.indexOf(mb);
                        int coordinateY = index / 30;
                        int coordinateX = index % 30;
                        
                        revealMine(coordinateX,coordinateY);
                    }
                }
            }else if(me.getModifiers() == me.BUTTON3_MASK){
                //Right Button Clicked
                mb.toggleMarkedMine();
            }else if(me.getModifiers() == me.BUTTON2_MASK){
                //Middle Button Clicked
                int index = buttonList.indexOf(mb);
                int coordinateY = index / 30;
                int coordinateX = index % 30;
                
                testAround(coordinateX,coordinateY);
            }
        
            checkIsWin();
        }
    }
    
    //the methods below are overridden but without a body
    public void mouseEntered(MouseEvent e){}; 
    public void mouseExited(MouseEvent e){}; 
    public void mousePressed(MouseEvent e){}; 
    public void mouseReleased(MouseEvent e){};
}

 

 

Gari 说:
Sep 03, 2018 08:18:10 AM

I have been using this product for a long time and it is pretty amazing one. I am thinking about when i had lost my way essay about it using some essay writing help such that new buyers get the idea about it.

 
custom dissertation 说:
Oct 13, 2018 12:54:03 AM

Winter is coming so does tooth senstivity, these are good remedies to overcome winter tooth senstivity. Going to share this post with my friends as well, Good post


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter