BlueJ 4 Gewinnt Gewinnbedingung

Aehl

Mitglied
Ich hab das Problem, dass ich die Gewinnbedingung nicht fertiggestellt bekomme. Ich denke, dass ich die Methode Linie in der Klasse Gewinnbedingung falsch verwende. Wäre toll, wenn mir wer da helfen kann. Auch die Methode innerhalbDesFeldes gibt noch eine Fehlermeldung bei Ausführung des Programmes aus.

[CODE lang="java" title="Gewinnbedingung"] public boolean GewinnBedingung(){
for(int x = Xpos - 3; x < Xpos + 4; x++){
for(int y = Ypos - 3; y < Ypos + 4; y++){
if(linie(x,y,1,0,1) || //waagerecht
linie(x,y,0,1,1) || //senkrecht
linie(x,y,1,1,1) || //senkrecht runter
linie(x,y,1,-1,1)){ //senkrecht rauf
return true;
}
}
}
return false;
}
[/CODE]
[CODE lang="java" title="Linie"] public boolean linie(int x, int y, int xRichtung, int yRichtung, int spielerNr){
for(int i=0;i<4;i++){
if((innerhalbDesFeldes(x-i,y-i) && spielfeld[xRichtung-i][yRichtung-i] == spielerNr)){
return false;
}
}
return true;
}[/CODE]
[CODE lang="java" title="Restliches Programm"]public class VierGewinnt{
private int breite = 7; //Die X-Achse in der Tabelle
private int hoehe= 6; //Die Y-Achse in der Tabelle
private int[][] spielfeld = new int[hoehe][breite];
private boolean gewonnen; //true, wenn die Methode gewinnbedingung erfuellt ist
private boolean SpielerEins; //Um die Spieler durchzuwechseln
private int[] Spaltenfuelle = new int[7]; //Zeigt die Fuelle der Spalte an
private int aktuelleSpalte =0; // kann überprüfe, wie viele Steine in einem Feld sind
private int Xpos;
private int Ypos;

public VierGewinnt(){
gewonnen=false;
SpielerEins=true;
System.out.print('\u000C');
}

public void AusgabeSpielfeld(){
System.out.println("| 1 | 2 | 3 | 4 | 5 | 6 | 7 |");
System.out.println("|____|____|____|____|____|____|____|");
for(int b=0; b<hoehe;b++){
System.out.println("| | | | | | | |");
for(int a=0; a<breite;a++){
System.out.print("|");
switch(spielfeld[a]){
case 0: System.out.print(" ");break;
case 1: System.out.print("X");break;
case 2: System.out.print("O");break;
}
System.out.print(" ");
}
System.out.print("|");
System.out.println();
System.out.println("|____|____|____|____|____|____|____|");
}
System.out.println();

if(SpielerEins == true){
System.out.println("Spieler 1 ist dran");
}else{
System.out.println("Spieler 2 ist dran");
}
}

public void SpielsteinInSpalteHinzufuegen(){
Scanner scannerVariable = new Scanner(System.in);
int input = scannerVariable.nextInt();
if(input<1 || input>7){
System.out.println();
System.out.println("Falsche Zahl eingegeben. Probieren Sie es erneut");
SpielsteinInSpalteHinzufuegen();
}else{
if(Spaltenfuelle[input -1]>5){
System.out.println("Diese Spalte ist schon vollständig gefuellt");
SpielsteinInSpalteHinzufuegen();
}else{
aktuelleSpalte=input;
Spielzug();
Spaltenfuelle[input-1]=Spaltenfuelle[input-1]+1;
Xpos= input;
Ypos= Spaltenfuelle[input-1];
System.out.println("Xpos= " + Xpos + " Ypos= " + Ypos); //Zum Überprüfen für mich selber
}
}
}

public void Spielzug(){
if(SpielerEins==true){
spielfeld[5-Spaltenfuelle[aktuelleSpalte-1]][aktuelleSpalte-1]=1;
SpielerEins=false;
}else{
spielfeld[5-Spaltenfuelle[aktuelleSpalte-1]][aktuelleSpalte-1]=2;
SpielerEins=true;
}
}

/**
* Gibt zurück, ob sich der Punkt (x|y) innerhalb des Feldes befindet.
*/
public boolean innerhalbDesFeldes(int x, int y){
return x > -1 && x < breite && y > -1 && y < hoehe;
}
public void abspann(){
Scanner scannerVariable = new Scanner(System.in);
if(SpielerEins=true){
System.out.println("Herzlichen Glückwunsch. "+" Spieler 1 hat gewonnen");
System.out.println("Wollen Sie eine weitere Partie beginnen?"+" "+"Drueken Sie 1 für JA und 2 fuer NEIN.");
int temp = scannerVariable.nextInt();
if(temp==1){
Game();
}else{
System.out.println("Danke fuer´s spielen");
}
}else{
System.out.println("Herzlichen Glückwunsch. "+" Spieler 2 hat gewonnen");
System.out.println("Wollen Sie eine weitere Partie beginnen?"+" "+"Drueken Sie 1 für JA und 2 fuer NEIN.");
int temp = scannerVariable.nextInt();
if(temp==1){
Game();
}else{
System.out.println("Danke fuer´s spielen");
}
}
}

public void Game(){
while(!GewinnBedingung()){
AusgabeSpielfeld();
SpielsteinInSpalteHinzufuegen();
System.out.print('\u000C');
}
abspann();
}
}[/CODE]
 

mihe7

Top Contributor
linie soll true liefern, dann und nur dann, wenn vier Steine von einem Spieler auf der angegebenen Linie innerhalb des Spielfelds belegt werden. Im übrigen bezeichnet der erste Index die y-Koordinate im spielfeld-Array, zumindest nach
Java:
    private int breite = 7; //Die X-Achse in der Tabelle
    private int hoehe= 6; //Die Y-Achse in der Tabelle
    private int[][] spielfeld = new int[hoehe][breite];
zu urteilen.

Macht also:
Java:
   public boolean linie(int sx, int sy, int xRichtung, int yRichtung, int spielerNr){
        for(int i=0;i<4;i++){
            int x = sx + i*xRichtung;
            int y = sy + i*yRichtung;
            if (!innerhalbDesFeldes(x,y) || spielfeld[y][x] != spielerNr)){
                return false;
            }
        }
        return true;
    }

Deine GewinnBedingung() (übrigens in Java schreibt man Bezeichner für Methoden und Variablen in lowerCamelCase) ist auch etwas seltsam.

Fangen wir von vorne an: wenn ich es richtig sehe, setzt Du einen Stein und möchtest wissen, ob der Spieler durch diesen Stein zum Gewinner wird. Du möchtest also wissen, ob eine Senkrechte, Waagerechte oder Diagonale, die "durch den Stein führt", mehr als drei aufeinanderfolgende Steine des gleichen Spielers enthält.

Lass uns zählen!

Java:
int zaehleGleicheSteine(int sx, int sy, int xRichtung, int yRichtung) {
    int anzahl = 1;
    int x = sx + xRichtung;
    int y = sy + yRichtung;

    while (innerhalbDesFeldes(x,y) && spielfeld[y][x] == spielfeld[sy][sx]) {
        anzahl++;
        x += xRichtung;
        y += yRichtung;
    }
    return anzahl;
}

Wenn wir die Methode für eine Richtung und in die entgegengesetzte Richtung aufrufen, können wir die Gesamtzahl auf einer Linie berechnen:
Java:
int zaehleSpielerSteine(int sx, int sy, int xRichtung, int yRichtung) {
    return  zaehleGleicheSteine(sx, sy, xRichtung, yRichtung) +
            zaehleGleicheSteine(sx, sy, -xRichtung, -yRichtung) - 1; // -1, da (sx,sy) zuvor zweimal gezählt wird
}

Damit lässt sich nun die Frage nach dem "Siegerstein" einfach beantworten:
Java:
boolean istSiegerStein(int sx, int sy) {
    return  zaehleSpielerSteine(sx, sy, 1, 0) > 3 ||
            zaehleSpielerSteine(sx, sy, 0, 1) > 3 ||
            zaehleSpielerSteine(sx, sy, 1, 1) > 3;
}
 

Aehl

Mitglied
sx und sy sind doch für die Aktuelle Position des Spielsteines gedacht, richtig? Weil wenn ich als Parameter die Xpos und die Ypos eingebe. liefert der immer treu, oder mache ich was falsch?
 

uuu3uuu

Aktives Mitglied
@Aehl hast Du hier mal geschaut:


in der Top-Answer steht Code:

Java:
public boolean areFourConnected(int player){

    // horizontalCheck
    for (int j = 0; j<getHeight()-3 ; j++ ){
        for (int i = 0; i<getWidth(); i++){
            if (this.board[i][j] == player && this.board[i][j+1] == player && this.board[i][j+2] == player && this.board[i][j+3] == player){
                return true;
            }           
        }
    }
    // verticalCheck
    for (int i = 0; i<getWidth()-3 ; i++ ){
        for (int j = 0; j<this.getHeight(); j++){
            if (this.board[i][j] == player && this.board[i+1][j] == player && this.board[i+2][j] == player && this.board[i+3][j] == player){
                return true;
            }           
        }
    }
    // ascendingDiagonalCheck
    for (int i=3; i<getWidth(); i++){
        for (int j=0; j<getHeight()-3; j++){
            if (this.board[i][j] == player && this.board[i-1][j+1] == player && this.board[i-2][j+2] == player && this.board[i-3][j+3] == player)
                return true;
        }
    }
    // descendingDiagonalCheck
    for (int i=3; i<getWidth(); i++){
        for (int j=3; j<getHeight(); j++){
            if (this.board[i][j] == player && this.board[i-1][j-1] == player && this.board[i-2][j-2] == player && this.board[i-3][j-3] == player)
                return true;
        }
    }
    return false;
}

diesen könntest Du adaptieren.
 

mihe7

Top Contributor
sx und sy sind doch für die Aktuelle Position des Spielsteines gedacht, richtig? Weil wenn ich als Parameter die Xpos und die Ypos eingebe. liefert der immer treu, oder mache ich was falsch?
Hast Du den Stein zuvor auf (sx,sy) gesetzt? Ansonsten werden leere Felder gezählt.

EDIT: noch was, weil es mir gerade auffällt: ich habe einen Fall (die zweite Diagonale) vergessen.
Java:
boolean istSiegerStein(int sx, int sy) {
    return  zaehleSpielerSteine(sx, sy, 1, 0) > 3 ||
            zaehleSpielerSteine(sx, sy, 0, 1) > 3 ||
            zaehleSpielerSteine(sx, sy, 1, 1) > 3 ||
            zaehleSpielerSteine(sx, sy, 1, -1) > 3;
}
 

uuu3uuu

Aktives Mitglied
@Aehl hier bitte:

Java:
import java.util.Arrays;

public class ConnectFour {
    private int maxx = 8;
    private int maxy = 6;
    private int[][] board = new int[maxx][maxy];

    public int getWinner() {
        int[][] directions = {{1, 0}, {1, -1}, {1, 1}, {0, 1}};
        for (int[] d : directions) {
            int dx = d[0];
            int dy = d[1];
            for (int x = 0; x < maxx; x++) {
                for (int y = 0; y < maxy; y++) {
                    int lastx = x + 3 * dx;
                    int lasty = y + 3 * dy;
                    if (0 <= lastx && lastx < maxx && 0 <= lasty && lasty < maxy) {
                        int w = board[x][y];
                        if (w != 0 && w == board[x + dx][y + dy]
                                && w == board[x + 2 * dx][y + 2 * dy]
                                && w == board[lastx][lasty]) {
                            return w;
                        }
                    }
                }
            }
        }
        return 0; // no winner
    }

    public void printBoard() {
        for (int[] a : board) {
            System.out.println(Arrays.toString(a));
        }
        System.out.println("Winner: " + getWinner());
    }

    public static void main(String[] args) {
        ConnectFour c4 = new ConnectFour();
        c4.printBoard();
        c4.board[3] = new int[]{0, 2, 1, 1, 1, 1};
        c4.printBoard();
    }
}
 

mihe7

Top Contributor
Oder eben:
Java:
import java.util.Arrays;

public class ConnectFour {
    private int width = 8;
    private int height = 6;
    private int[][] board = new int[height][width];

    boolean isWinningMove(int sx, int sy) {
        return  countPieces(sx, sy, 1,  0) > 3 ||
                countPieces(sx, sy, 0,  1) > 3 ||
                countPieces(sx, sy, 1,  1) > 3 ||
                countPieces(sx, sy, 1, -1) > 3;        
    }

    int countPieces(int sx, int sy, int dx, int dy) {
        return  countPiecesDirected(sx, sy,  dx,  dy) +
                countPiecesDirected(sx, sy, -dx, -dy) - 1;
    }

    int countPiecesDirected(int sx, int sy, int dx, int dy) {
        int count = 1;
        int x = sx + dx;
        int y = sy + dy;
        while (onBoard(x, y) && board[y][x] == board[sy][sx]) {
            count++;
            x += dx;
            y += dy;
        }
        return count;
    }

    boolean onBoard(int x, int y) {
        return x >= 0 && x < width && y >= 0 && y < height;
    }

    public void printBoard() {
        for (int[] a : board) {
            System.out.println(Arrays.toString(a));
        }
    }

    void printWinningMoves() {
        System.out.print("Winning moves: ");            
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (board[y][x] != 0 && isWinningMove(x, y)) {
                    System.out.printf("(%d, %d) ", x, y);
                }
            }
        }
        System.out.println();
    }

    ConnectFour place(int sx, int sy, int dx, int dy, int count, int player) {
        int x = sx;
        int y = sy;
        for (int i = 0; onBoard(x,y) && i < count; i++) {
            board[y][x] = player;
            x += dx;
            y += dy;
        }
        return this;
    }

    public static void main(String[] args) {
        int[][] placements = {
            {2, 3, 1, 0, 3, 1}, {2, 3, 1, 0, 4, 1},
            {2, 1, 0, 1, 3, 2}, {2, 1, 0, 1, 4, 2},
            {2, 2, 1, 1, 3, 1}, {2, 2, 1, 1, 4, 1},
            {1, 5, 1, -1, 3, 2}, {1, 5, 1, -1, 4, 2}
        };
    
        for (int[] placement : placements) {
            ConnectFour c4 = new ConnectFour()
                    .place(placement[0], placement[1], placement[2], placement[3],
                           placement[4], placement[5]);
            c4.printBoard();
            c4.printWinningMoves();
        }
    }
}
 

Aehl

Mitglied
Danke für die ganzen Vorschläge, aber irgendwie schaff ich es trotz diesen Hilfen nicht. Ich will ja auch nicht einfach was anderes kopieren. Danke trotzdem
 

Marinek

Bekanntes Mitglied
Hi,
angenommen du hast ein Feld 10x10. Dann kannst du dieses als ein zweidimensionales Array sehen. Dann allerdings hast du das Problem, dass du jetzt viele permutationen hast, die du prüfen musst.

Lösung 1 könnte sein:

Das Feld als ein eindimensionales Array sehen. index % 10 sind dann die Reihen. Dann wird das einfacher. Sagen wir du hast ein Stein in der Mitte des Feldes also index 50(x).

Dann das Feld links ist 49 (x-1)
das Feld rechts ist 50 (x+1)
Das Feld drüber ist 60 (x+10)
Das Feld drunter ist 40 (x-10)

Du müsstest jetzt die Logik sehen, wie man die Diagonalen findet.

Du kannst nun naiv prüfen, für jedes X, ob du von da aus 4 gleiche findest nach dem Schema oben.

achte darauf, dass rechts bei 10ern endet. Und dann die globalen Bounds bei 0 und 99 liegen. wenn du also index 99 prüfst und dort +1 addierst, dann bekommst du eine ArrayIndexOutOfBound excpetion. Das ist dein Problem von oben.

Aber Glückwunsch. Sinnlos Code zu kopieren hilft ja nicht das nächste Problem zu lösen.
 

Neue Themen


Oben