This site requires JavaScript, please enable it in your browser!
Greenfoot back
StrauXX
StrauXX wrote ...

2018/5/1

Help with minesweeper squares with an value of 0

StrauXX StrauXX

2018/5/1

#
I tried to make a minesweeper game and everything works fine except for one thing. Normally if you click a square with and value of 0, all the squares around that squarey should also be pressed, this works also, but if one of the squares that are automaticly pressed is also a square with an value of 0, that square should also be pressed, this is the thing that doesnt work. (the game is based on an 2D Array in the MyWorld class)
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List; //wird für die ".getNeighbours()" methode benötigt

/**
 * Write a description of class blankSquare here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class blankSquare extends Actor
{
    boolean flag = false;
    int x = 0;
    int y = 0;

    /**
     * Act - do whatever the blankSquare wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        MouseInfo mi = Greenfoot.getMouseInfo();
        if(Greenfoot.mouseClicked(this) && mi.getButton() == 1){
            x = this.getX();
            y = this.getY();
            if(MyWorld.playingField[x][y] == 0){
                setImage("square_0.png");
                clickTouching(false,0,0);
            }
            if(MyWorld.playingField[x][y] == 1){
                setImage("square_1.png");
            }
            if(MyWorld.playingField[x][y] == 2){
                setImage("square_2.png");
            }
            if(MyWorld.playingField[x][y] == 3){
                setImage("square_3.png");
            }
            if(MyWorld.playingField[x][y] == 4){
                setImage("square_4.png");
            }
            if(MyWorld.playingField[x][y] == 5){
                setImage("square_5.png");
            }
            if(MyWorld.playingField[x][y] == 6){
                setImage("square_6.png");
            }
            if(MyWorld.playingField[x][y] == 7){
                setImage("square_7.png");
            }
            if(MyWorld.playingField[x][y] == 8){
                setImage("square_8.png");
            }
            if(MyWorld.playingField[x][y] == -1){
                setImage("mine.png");
                Greenfoot.stop();
            }
        }
        if(Greenfoot.mouseClicked(this) && mi.getButton() == 3){
            if(flag == false){
                setImage("flag.png");
            }
            if(flag == true){
                setImage("square.png");
            }

            if(flag == true){
                flag = false;
            }
            else if(flag == false){
                flag = true;
            }
        }
    }
    //everything above is for "flaging", clicking the squares and giving the squares the correct picture/number. The code abover works perfectly!
    private void clickTouching(boolean chainReaction, int x2, int y2){ //chainReaction = if true the coordinates x2 and y2 will be used for the neighbour list; x2 = only used if chainReaction = true; x2 = only used if chainReaction = true
        List neighbours = this.getNeighbours(1, true, blankSquare.class);
        if(chainReaction == true){
            neighbours.clear();
            neighbours = ((blankSquare)getOneObjectAtOffset(x2, y2, blankSquare.class)).getNeighbourList(); //casts an actor at the position x,y to an object so it is possible to call a method with it
        }
        for(int i = 0; i < neighbours.size(); i++){
            Actor a = (Actor) neighbours.get(i);
            int x = a.getX();
            int y = a.getY();

            if(MyWorld.playingField[x][y] == 0){    //if the square has the value 0, normaly every other square with the value 0 should be clicked, like a chain reaction (thats the reason for the name of the boolean varible). Because of this, if the square is 0 the click touching mehod is called, but with chainReaction = true and x2 and y2 as the possition of the square.
                a.setImage("square_0.png");
                clickTouching(true,a.getX(),a.getY());  //throws null pointer exception, outcomment if you want to try the game at its current status
            }
            if(MyWorld.playingField[x][y] == 1){    //the game is based on an static 2d Array which is in the MyWorld class, the if's look which value the 2d Array has on the position x,y and then gives the square the matching picture.
                a.setImage("square_1.png");
            }
            if(MyWorld.playingField[x][y] == 2){
                a.setImage("square_2.png");
            }
            if(MyWorld.playingField[x][y] == 3){
                a.setImage("square_3.png");
            }
            if(MyWorld.playingField[x][y] == 4){
                a.setImage("square_4.png");
            }
            if(MyWorld.playingField[x][y] == 5){
                a.setImage("square_5.png");
            }
            if(MyWorld.playingField[x][y] == 6){
                a.setImage("square_6.png");
            }
            if(MyWorld.playingField[x][y] == 7){
                a.setImage("square_7.png");
            }
            if(MyWorld.playingField[x][y] == 8){
                a.setImage("square_8.png");
            }
            if(MyWorld.playingField[x][y] == -1){
                a.setImage("mine.png");
                Greenfoot.stop();
            }
        }
    }

    public List getNeighbourList(){ //is called if chainReaction = true. Returns a list of neighbours.
        return this.getNeighbours(1,true,blankSquare.class);
    }
There is also some code in the MyWorld class, but that is only for preparing the playingField and such things.
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class MyWorld here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class MyWorld extends World
{
    static int[][] playingField = new int[10][10];    
    /**
     * Constructor for objects of class MyWorld.
     * 
     */
    public MyWorld()
    {
        super(10, 10, 16); 
        prepare();
    }

    /**
     * Prepare the world for the start of the program.
     * That is: create the initial objects and add them to the world.
     */
    private void prepare()
    {
        for(int i = 0; i <= 10; i++){
            for(int a = 0; a <= 10; a++){
                addObject(new blankSquare(), i,a);
            }
        }
        preparePlayingField();
    }
    private void preparePlayingField(){
        for(int i = 0; i < 10; i++){
            int x = (int)(Math.random() * 10);
            int y = (int)(Math.random() * 10);
            if(playingField[y][x] != -1){
                playingField[y][x] = -1;
                try{
                    if(playingField[y-1][x-1] != -1){
                        playingField[y-1][x-1] += 1;
                    }
                }
                catch(Exception e){
                }
                try{
                    if(playingField[y-1][x-1] != -1){
                        playingField[y-1][x-1] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y-1][x] != -1){
                        playingField[y-1][x] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y-1][x+1] != -1){
                        playingField[y-1][x+1] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y][x-1] != -1){
                        playingField[y][x-1] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y][x] != -1){
                        playingField[y][x] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y][x+1] != -1){
                        playingField[y][x+1] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y+1][x-1] != -1){
                        playingField[y+1][x-1] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y+1][x] != -1){
                        playingField[y+1][x] += 1;
                    }
                }
                catch(Exception e){                
                }
                try{
                    if(playingField[y+1][x+1] != -1){
                        playingField[y+1][x+1] += 1;
                    }
                }
                catch(Exception e){                
                }
            }
            else{
                i--;
            }
        }
    }
}
Super_Hippo Super_Hippo

2018/5/1

#
What I would do is: Each squarewhich potentially has a mine should have a boolean to save whether or not it was already revealed. Then in the "chain reaction" (if the clicked square doesn't have a neighbor with a mine), you can get your list of neighbors around the clicked square and each one which is not revealed (!)will be revealed and if one of them has no neighbor with a mine, it will continue... If you don't do this and you have two squares next to each other without neighbors with mines, they will constantly activate the other one and vice versa. (I would also not have an array and save all those numbers there. I would create all squares and then, change a "mine" boolean in 10 (in your example) of the squares. Then you get your list of neighbors when you reveal one and see how many of them have a mine.)
StrauXX StrauXX

2018/5/1

#
Ok thank you, i will try that, but the thing is that i can't even start the programm because it throws a NullPointerException in the blankSquare class at the lines 80 89 89 28 edit: i have to use the 2D Array, its a homework
StrauXX StrauXX

2018/5/1

#
Ok i have now changed the code, but it still throws the exceptions
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List; //wird für die ".getNeighbours()" methode benötigt

/**
 * Write a description of class blankSquare here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class blankSquare extends Actor
{
    boolean flag = false;
    int x = 0;
    int y = 0;
    boolean clicked = false;

    /**
     * Act - do whatever the blankSquare wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        MouseInfo mi = Greenfoot.getMouseInfo();
        if(Greenfoot.mouseClicked(this) && mi.getButton() == 1){
            clicked = true;
            x = this.getX();
            y = this.getY();
            if(MyWorld.playingField[x][y] == 0){
                setImage("square_0.png");
                clickTouching(false,0,0);
            }
            if(MyWorld.playingField[x][y] == 1){
                setImage("square_1.png");
            }
            if(MyWorld.playingField[x][y] == 2){
                setImage("square_2.png");
            }
            if(MyWorld.playingField[x][y] == 3){
                setImage("square_3.png");
            }
            if(MyWorld.playingField[x][y] == 4){
                setImage("square_4.png");
            }
            if(MyWorld.playingField[x][y] == 5){
                setImage("square_5.png");
            }
            if(MyWorld.playingField[x][y] == 6){
                setImage("square_6.png");
            }
            if(MyWorld.playingField[x][y] == 7){
                setImage("square_7.png");
            }
            if(MyWorld.playingField[x][y] == 8){
                setImage("square_8.png");
            }
            if(MyWorld.playingField[x][y] == -1){
                setImage("mine.png");
                Greenfoot.stop();
            }
        }
        if(Greenfoot.mouseClicked(this) && mi.getButton() == 3){
            if(flag == false){
                setImage("flag.png");
            }
            if(flag == true){
                setImage("square.png");
            }

            if(flag == true){
                flag = false;
            }
            else if(flag == false){
                flag = true;
            }
        }
    }
    //everything above is for "flaging", clicking the squares and giving the squares the correct picture/number. The code abover works perfectly!
    private void clickTouching(boolean chainReaction, int x2, int y2){ //chainReaction = if true the coordinates x2 and y2 will be used for the neighbour list; x2 = only used if chainReaction = true; x2 = only used if chainReaction = true
        List neighbours = this.getNeighbours(1, true, blankSquare.class);
        if(chainReaction == true){
            neighbours.clear();
            neighbours = ((blankSquare)getOneObjectAtOffset(x2, y2, blankSquare.class)).getNeighbourList(); //casts an actor at the position x,y to an object so it is possible to call a method with it
        }
        for(int i = 0; i < neighbours.size(); i++){
            Actor a = (Actor) neighbours.get(i);
            int x = a.getX();
            int y = a.getY();

            if(MyWorld.playingField[x][y] == 0){    //if the square has the value 0, normaly every other square with the value 0 should be clicked, like a chain reaction (thats the reason for the name of the boolean varible). Because of this, if the square is 0 the click touching mehod is called, but with chainReaction = true and x2 and y2 as the possition of the square.
                a.setImage("square_0.png");
                if(((blankSquare)getOneObjectAtOffset(x2, y2, blankSquare.class)).getClickedStatus() == false){
                    clickTouching(true,a.getX(),a.getY());  //throws null pointer exception, outcomment if you want to try the game at its current status
                }
            }
            if(MyWorld.playingField[x][y] == 1){    //the game is based on an static 2d Array which is in the MyWorld class, the if's look which value the 2d Array has on the position x,y and then gives the square the matching picture.
                a.setImage("square_1.png");
            }
            if(MyWorld.playingField[x][y] == 2){
                a.setImage("square_2.png");
            }
            if(MyWorld.playingField[x][y] == 3){
                a.setImage("square_3.png");
            }
            if(MyWorld.playingField[x][y] == 4){
                a.setImage("square_4.png");
            }
            if(MyWorld.playingField[x][y] == 5){
                a.setImage("square_5.png");
            }
            if(MyWorld.playingField[x][y] == 6){
                a.setImage("square_6.png");
            }
            if(MyWorld.playingField[x][y] == 7){
                a.setImage("square_7.png");
            }
            if(MyWorld.playingField[x][y] == 8){
                a.setImage("square_8.png");
            }
            if(MyWorld.playingField[x][y] == -1){
                a.setImage("mine.png");
                Greenfoot.stop();
            }
            ((blankSquare)getOneObjectAtOffset(x2, y2, blankSquare.class)).setClickedStatus(true);
        }
    }

    public List getNeighbourList(){ //is called if chainReaction = true. Returns a list of neighbours.
        return this.getNeighbours(1,true,blankSquare.class);
    }
    public boolean getClickedStatus(){
        return clicked;
    }
    public void setClickedStatus(boolean status){
        clicked = status;
    }
}
java.lang.NullPointerException at blankSquare.clickTouching(blankSquare.java:123) at blankSquare.act(blankSquare.java:30) at greenfoot.core.Simulation.actActor(Simulation.java:604) at greenfoot.core.Simulation.runOneLoop(Simulation.java:562) at greenfoot.core.Simulation.runContent(Simulation.java:221) at greenfoot.core.Simulation.run(Simulation.java:211)
Super_Hippo Super_Hippo

2018/5/1

#
You are using the line
clickTouching(true,a.getX(),a.getY());
and the parameters are used for the "getObjectsAtOffset" method. It does not get the object at the location of the x/y you pass, but of x+getX and y+getY. So 0/0 will find objects at the current location of the actor the method is called on/from.
Super_Hippo Super_Hippo

2018/5/1

#
The array is part of the homework. Does it say that you have to use the number of mine neighbors or would it be allowed to have 1 for squares with mines and 0 for squares without?
StrauXX StrauXX

2018/5/2

#
well every square except the ones with an value of 0 have mine neighbours. I could make a boolean mineNeighbour; if(getValue() == 0){ mineNeighbour = false; } else{ mineNeighbour = true; } but i don't know what benefits this would bring?
Super_Hippo Super_Hippo

2018/5/2

#
I meant 1 = there is a mine and 0 = there is no mine and then you can check how many neighbors with mines there are when checking the neighbors in the array.
danpost danpost

2018/5/2

#
I used an 2d int array in my MineSweeper scenario. Each of the 21 possible values gave an exact description of the cell it refers to except for one, which indicated the cell was exposed (no description beyond that is needed for exposed cells). There are 9 possible numbers for neighbors (0 through 8) and there are mines, which makes 10 possible values. Each of these 10 type cells could be flagged, so that doubles the possible values to 20. Then, there is the state of a cell being exposed. Once a cell is exposed, its initial value (flagged state and neighboring mines) is no longer needed, so any and all exposed cells can be given the same value. So that make 21 possible values. I used -1 for exposed cells, 1 through 9 for neighboring mines (9 for blanks, or no neighbors) and 10 for mines. When flagged, I just added 11; and, of course, when a flag was removed, subtract the 11. All that was needed beyond the array was (1) how many mines were placed; (2) how many flags are currently being used; and (3) how many cells are currently exposed. Although you could extract these from the array, it is much easier to just track those values. Once exposed cells plus the number of flags equals the total number of cells, the puzzle becomes successfully completed. I probably could have used a more suitable numbering system (0 through 8 for neighbors, 9 for mines, plus 9 for flagged and -1 for exposed), but makes little difference (there may have been a reason I did it the way I did, not saying it was a good reason). I cannot now say why I added 11 and not 10 for flags and I do not know why, or cannot remember why, I used 9 instead of 0 for blanks.
StrauXX StrauXX

2018/5/2

#
currently the game works perfectly, except for the squares with a value of 0 click themselves, if i click a square with an value of 0 all the squares around it will update. What I wanted to do is, if one of the squares that are clicked automaticly, i get the actor with getObjectAtOffset()... , cast it to an object an then i call the "autoclicking" method again and because now its called from another object/actor the getX() and getY() values will be different so it will also automaticliy click all to squares which are around and in case another blank square is clicked again, the method is called again and so on. I hope my explaination isn't to complicated
danpost danpost

2018/5/2

#
A correction to my last post: with the more suitable numbering system, 10 would need to be added for flags (if zero was to be used for blanks and 9 for mines). By using actors, everything becomes more complicated. Each click would be on some individual actor instead of on the world. It even complicates things more when you have the actors store cell states. All data is scattered among the actors and that means it would take a lot of data fetching with each exposure of a blank cell. With the entire state of the game tracked by the array in the world, all that needs done is to offset an index or two, check if they are valid cell indices and work with the data at hand.
You need to login to post a reply.