Minesweeper

Swim

Mitglied
Hallo Java-Freunde,

ich bin gerade dabei Minesweeper zu programmieren, jedoch hab ich noch ein großes Problem:
Ich weiß nicht, wie ich es anstellen soll, dass sich mehrere Felder gleichzeitig öffnen.
Bis jetzt funktionier alles sehr gut und wenn man das Programm ausführt, zeigt es die Minen richtig an und man kann auch die Buttons drücken und es erscheint der richtige Text dazu.
Ich hoffe es kann mir jemand helfen:
Es sind insgesamt 5 Dateien:

Hier werden die Parameter festgelegt:
[Java]public class Param {

static final int Fensterhöhe = 800;
static final int Fensterbreite = 800;
static final int Felderhöhe = 10;
static final int Felderbreite = 10;
static final int mines = 10;

}[/code]


Hier sind die Zustände die ein Button annehmen kann:

[Java]
public enum Entry {

Mine, Nix, Eins, Zwei, Drei, Vier, Fünf, Sechs, Sieben, Acht, Flagge;

public String toString(){
if(this == Mine){
return this.name();
}

if(this == Nix){
return "";
// return this.name();
}
if(this == Eins){
return "1";
}
if(this == Zwei){
return "2";
}
if(this == Drei){
return "3";
}
if(this == Vier){
return "4";
}
if(this == Fünf){
return "5";
}
if(this == Sechs){
return "6";
}
if(this == Sieben){
return "7";
}
if(this == Acht){
return "8";
}
if(this == Flagge){
return "F";
}else{
return this.name();
}

}

public void setText(String a) {


}



}[/code]


Das hier ist meine Logic, wo zum Beispiel berechnet wird, was passiert, wenn ich an den Rändern klicke.

[Java]

import java.util.Random;

public class MineLogic {

private Entry[][] board;
private int counter = 0;
private int c = 0;
private Random r = new Random();

public MineLogic() {

board = new Entry[Param.Felderhöhe][Param.Felderbreite];

for (int l = 0; l < Param.Felderhöhe; l++) {
for (int m = 0; m < Param.Felderbreite; m++) {
board[l][m] = Entry.Nix;
}
}

while (counter < Param.mines) {
int s = r.nextInt(Param.Felderhöhe);
int s2 = r.nextInt(Param.Felderbreite);

if (board[s2] == Entry.Nix) {
board[s2] = Entry.Mine;
counter++;
}
}

}

public void setText(String text){

}

public String getAsString(int x, int y) {
return board[x][y].toString();

}

public String getAsString(Entry a) {
return a.toString();

}

public Entry get(int x, int y) {
return board[x][y];
}




public boolean set(int x, int y) {
if (board[x][y] == Entry.Nix) {

// Für die rechte untere Ecke gilt:

while (x == board.length - 1 && y == board[x].length - 1) {
if (board[x - 1][y] == Entry.Mine) {
c++;
}
if (board[x][y - 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y - 1] == Entry.Mine) {
c++;
}

board[x][y] = umwandeln(c);

c = 0;
return true;
}

// Für linke untere Ecke gilt:

while (x == board.length - 1 && y == 0) {

if (board[x][y + 1] == Entry.Mine) {
c++;
}

if (board[x - 1][y] == Entry.Mine) {
c++;
}

if (board[x - 1][y + 1] == Entry.Mine) {
c++;
}

board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Für linke obere Ecke gilt:

while (x == 0 && y == 0) {
if (board[x][y + 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y + 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Für rechte obere Ecke gilt:

while (x == 0 && y == board[x].length - 1) {
if (board[x + 1][y] == Entry.Mine) {
c++;
}
if (board[x + 1][y - 1] == Entry.Mine) {
c++;
}
if (board[x][y - 1] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Für Unten gilt:

while (x == board.length - 1) {
if (board[x][y + 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y] == Entry.Mine) {
c++;
}
if (board[x][y - 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y - 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y + 1] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Für Rechts gilt:

while (y == board[x].length - 1) {

if (board[x + 1][y] == Entry.Mine) {
c++;
}
if (board[x - 1][y] == Entry.Mine) {
c++;
}
if (board[x][y - 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y - 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y - 1] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Für Oben gilt:

while (y == 0) {

if (board[x + 1][y] == Entry.Mine) {
c++;
}
if (board[x][y + 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y + 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y + 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Für Links gilt:

while (x == 0) {

if (board[x + 1][y] == Entry.Mine) {
c++;
}
if (board[x][y + 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y + 1] == Entry.Mine) {
c++;
}
if (board[x][y - 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y - 1] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

// Wenn Entry.Nix nicht am Rand liegt wird das ausgeführt:

if (board[x + 1][y] == Entry.Mine) {
c++;
}
if (board[x][y + 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y + 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y] == Entry.Mine) {
c++;
}
if (board[x][y - 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y - 1] == Entry.Mine) {
c++;
}
if (board[x + 1][y - 1] == Entry.Mine) {
c++;
}
if (board[x - 1][y + 1] == Entry.Mine) {
c++;
}
board[x][y] = umwandeln(c);
c = 0;
return true;
}

if (board[x][y] == Entry.Mine) {
return true;
}
return false;
}

// Hier wird die Anzahl an Counts in den entsprechenden Eintrag umgeändert.

public Entry umwandeln(int c) {

if (c == 1) {
return Entry.Eins;
}
if (c == 2) {
return Entry.Zwei;
}
if (c == 3) {
return Entry.Drei;
}
if (c == 4) {
return Entry.Vier;
}
if (c == 5) {
return Entry.Fünf;
}
if (c == 6) {
return Entry.Sechs;
}
if (c == 7) {
return Entry.Sieben;
}
if (c == 8) {
return Entry.Acht;
} else {

return Entry.Nix;
}
}

}
[/code]

Hier werden die Buttons festgelegt ( Hier versuch ich an dem Problem zu arbeiten)
[Java]package Minesweeper;

import java.awt.Button;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;


public class MineButton extends JButton {


private int x;
private int y;
private MineLogic logic;
Object a;

public MineButton(MineLogic logic, int x, int y) {
this.x = x;
this.y = y;
this.logic = logic;

for (int l = 0; l < this.x; l++) {
for (int m = 0; m < this.y; m++) {

}
}

addMouseListener(new MyMouseAdapter());
}






class MyMouseAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {


if (e.getButton() == MouseEvent.BUTTON1) {
// Linksklick


if (logic.set(x, y)){

setMargin(new Insets(0,0,0,0));
setEnabled(false);
setText(logic.getAsString(x,y));
setVisible(true);

if(logic.get(x, y) == Entry.Mine){
JOptionPane.showInputDialog("Blöd gelaufen, du hast Verloren!");

}
}


}
if (e.getButton() == MouseEvent.BUTTON3) {
// Rechtsklick
if(logic.get(x, y) == Entry.Flagge){
setMargin(new Insets(0,0,0,0));
setText(logic.getAsString(Entry.Nix));
setVisible(true);
}else{
setMargin(new Insets(0,0,0,0));
setText(logic.getAsString(Entry.Flagge));
setVisible(true);
}


}
}

public void mouseReleased(MouseEvent e){

}



}

}
[/code]


Hier wird nur das Spiel vorbereitet und erzeugt:
[Java]package Minesweeper;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JFrame;


public class Mine extends JFrame{



public Mine(){

setTitle("Minesweeper");
setSize(Param.Fensterbreite, Param.Fensterhöhe);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


MineLogic logic = new MineLogic();
Container container = getContentPane();
container.setLayout(new GridLayout(Param.Felderhöhe,Param.Felderbreite));

for(int y = 0; y < Param.Felderhöhe; y++){
for(int x = 0; x < Param.Felderbreite; x++){
container.add(new MineButton(logic, x,y));
}
}

setVisible(true);

}

public static void main(String[] args){
Mine m = new Mine();
}

}[/code]
 

truesoul

Top Contributor
Ohne mir jetzt den Quelltext angeschaut zu haben würde ich sagen das du z.B ein Backtracking-Algorithmus dafür verwenden könntest.

Gruß
 
Zuletzt bearbeitet:
G

Gast2

Gast
Ich weiß nicht, wie ich es anstellen soll, dass sich mehrere Felder gleichzeitig öffnen.
Das kannst du zum Beispiel rekursiv lösen. Wenn das Feld auf dem geklickt wurde leer ist, also keine Zahl / keine Mine drunter, dann bewegst du dich rekursiv in alle 4 Richtungen.
Triffst du auf ne Zahl deckst du das Feld noch auf und brichst die Rekursion ab.
Triffst du auf nen weiteres leeres Feld, gehst du wieder in alle 4 Richtungen weiter.
Triffst du auf nen Feld das bereits aufgedeckt ist machst du gar nichts.
 

Swim

Mitglied
Vielen Dank schon mal.
Also mir ist das Prinzip eigentlich schon klar: Ich muss einfach bei dem aufgedeckten Button schauen, ob um ihn herum weitere Buttons mit einer Null sind und die ebenfalls aufdecken und so weiter...

Aber ich hab keinen Plan wie ich das in Java umsetzten soll. Ich müsste irgendwie Zugriff auf die Buttons bekommen nur wie???
 

Fu3L

Top Contributor
Hab deine Quelltexte auch nicht gelesen, aber generell: Speichere die Buttons alle nochmal extra in einer Liste oder einem Array (vllt zweidimensional). Dann kannst du über die Indexe des Arrays oder der Liste auf die Buttons zugreifen.

Also beim 2D Array wärs in etwa so:

Java:
int jetzigerButtonX = 2;
int jetzigerButtonY = 3;
for(int x = jetzigerButtonX-1; x < jetzigerButtonX+1; x++) {
   for(int y = jetzigerButtonY-1; y jetzigerButtonY+1; y++) {
       //Hier prüfen, ob eigenes Feld
      //Hier prüfen, ob im Array
      //Hier aufdecken und co
      //zB: buttons[x][y].isMine()
    }
}
 
G

Gast2

Gast
Du solltest auf jedenfall dein Model von deinem View trennen, also nicht anfangen irgendwelche Button[] Arrays erstellen wo du dann irgendwie an die Information kommst ob Bombe, leer oder Zahl.

Erstell dir ein Array aus int's bzw. aus enums (würde sich hier anbieten). Das kannst du dann auch wunderbar einfach testen. Einfache main, Ausgabe auf Konsole, etc.
 

Swim

Mitglied
Wenn ich jetzt ein Array mit ints mache
Java:
button = new int[x][y];
		for (int l = 0; l < this.x; l++) {
			for (int m = 0; m < this.y; m++) {
				button[l][m] = 1;
			}
		}
dann verstehe ich nicht ganz, was ich damit anfangen kann.
Ich hätte gerne eine Objekt, das ich dann in meiner "mouseClicked"-Methode aufrufen kann und mit
Java:
 setEnabled(false);
				  setText(logic.getAsString(x,y));
				  setVisible(true);
versehen kann. Versteht ihr was ich meine? Ich will einfach nur meine Buttons aufrufen um diese dann "einzudrücken" und einen Text darunter auszugeben.
 

Fu3L

Top Contributor
Du hast doch deine Klasse MineButton, dann machste damit ein Array vom Typ MineButton:

Java:
MineButton[][] mines = new MineButton[20[20]; //Wäre das Feld 20 Objekte hoch und breit)

Dann kansnt du das anwenden, was ich schrieb, wenn du den index des gedrückten Buttons (x und y werte) kennst.
Natürlich wäre es schön, wenn Modell von View getrennt wäre, aber von dem, was du bisher hast, wäre das das einfachste.

Allerdings muss ich sagen, auch nur den Code überflogen zu haben, mein eigenes Progrämmchen strengt mich grad zu sehr an^^ ;)
 

Swim

Mitglied
Und wenn ich dann dieses Array erstellt habe,
Java:
MineButton[][] button = new MineButton[Param.Felderhöhe][Param.Felderbreite];

aber leider immer noch nicht mit z.B. setText ausgeben.
Java:
setText(logic.getAsString(x,y));

PS.: Ich bin ein ziemlicher Neuling was Java anbelangt.
 

Fu3L

Top Contributor
Es wäre besser, wenn jeder MineButton, der ja quasie ein Feld repräsentiert, selbst wüsste, ob eine Mine unter ihm liegt oder wie viele um ihn rum sind. Dann könntest du nämlich eine Methode reinsetzen, mit der du abfragen kannst, ob der Button aufgedeckt werden sollte. Wenn ja, markierst du dieses Feld als betrachtet. Dann führst du die oben geschriebene Schleife nochmal aus Sicht dieses Feldes durch und das geht dann so lange weiter, bis alle Felder, die in Frage kommen, betrachtet wurden.
 

Fu3L

Top Contributor
Also zur Darstellung nutzt du moment entweder Bilder oder Zeichen. Egal, welches von beidem der Fall ist, das Vorgehen ist sehr ähnlich:

Wird in der Schleife ein Button darum gebeten, sich aufzudecken, wird eben im Button entweder ein anderes Icon per setIcon oder ein anderer Text per setText() gesetzt. Da mein Vorschlag von vorher lautete, dass jedes Feld wisssen sollte, wie viele Minen es umgeben, weißt du, wie der neue Text lauten sollte.
 

Ähnliche Java Themen


Oben