Blöde Frage.

  • Themenstarter Themenstarter Guest
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo!

Derzeit bin ich am lernen für eine Java Klausur und habe da n kleines Problem... eine Übungsaufgabe ist nicht direkt ein Memory Spiel zu entwickeln, sondern das Austeilen der Karten zu simulieren... Nun habe ich auch eine Musterlösung, jedoch hatte ich auch einen eigenen Ansatz und möchte den nicht unbedingt aufgeben! *g*

Ziel ist es zumindest, das Zahlenpärchen erstellt werden in einem 2-dimensionalen Array, welches zufällig gefüllt werden soll... also d.h. wenn man das Programm mehrmals aufruft, soll die Ausgabe unterschiedlich sein und jede Ziffer mit derselben Wahrscheinlichkeit an jeder Position des Array stehen!

Einmal ein Beispiel wie es aussehen soll:

Bitte Hoehe des Spielfeldes eingeben: 3
Bitte Breite des Spielfeldes eingeben: 6
Inhalt des Spielfeldes:

0 1 6 2 3 6
3 1 0 2 8 8
4 4 7 7 5 5

... naja klappt auch alles recht gut, nur ist es bei mir so, das die 0en immer die letzten beiden sind...

Bsp:

1 6 2 3 6 3
1 2 8 8 4 4
7 7 5 5 0 0

Das ist mein Quellcode:

Code:
import java.io.*;

class Memory {
  
  public static void main(String args[]) throws IOException{
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    System.out.print("Bitte Hoehe des Spielfeldes eingeben: );
    int n = Integer.parseInt(in.readLine());
    System.out.print("Bitte Breite des Spielfeldes eingeben ");
    int m = Integer.parseInt(in.readLine());
    showField(fillField(n, m));
  }
  
  static int[][] fillField(int n, int m) {
    int[][] memory = new int[n][m];
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j < m; ++j) {
        memory[i][j] = (int) (Math.ceil(((Math.random() * ((n*m) / 2)))));
        if(checkValue(memory, i, j)) {
          --j;
        }
      }
    }
    return memory; 
  }
  
  static void showField(int[][] memory) {
    for(int i = 0; i < memory.length; ++i) {
      for(int j = 0; j < memory[0].length; ++j) {
        System.out.print(memory[i][j] + " ");
      }
    System.out.println();
    }
  }
  
  static boolean checkValue(int[][] a, int i, int j) {
    int h = 0;
    boolean[] x = new boolean[3];
    for(int k = 0; k < a.length; ++k) {
      for(int l = 0; l < a[k].length; ++l) {
        if(a[i][j] == a[k][l]) {
          x[h] = true;
          h++;
        } 
        if(h == 3) {
          boolean b = true;
          return b;
        }
      }
    }
    boolean b = false;
    return b;
  }
  
}


Ich wäre für jeden Rat und Verbesserungsvorschlag sehr dankbar!

Gruß, Marco
Code:
 
hmpf sry da war in Zeile 18 noch n test... denke nämlich das es daran liegt... eigentlich nur so:

Code:
import java.io.*;

class Memory {
  
  public static void main(String args[]) throws IOException{
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    System.out.print("Bitte Hoehe des Spielfeldes eingeben: );
    int n = Integer.parseInt(in.readLine());
    System.out.print("Bitte Breite des Spielfeldes eingeben ");
    int m = Integer.parseInt(in.readLine());
    showField(fillField(n, m));
  }
  
  static int[][] fillField(int n, int m) {
    int[][] memory = new int[n][m];
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j < m; ++j) {
        memory[i][j] = (int) (Math.random() * ((n*m) / 2));
        if(checkValue(memory, i, j)) {
          --j;
        }
      }
    }
    return memory; 
  }
  
  static void showField(int[][] memory) {
    for(int i = 0; i < memory.length; ++i) {
      for(int j = 0; j < memory[0].length; ++j) {
        System.out.print(memory[i][j] + " ");
      }
    System.out.println();
    }
  }
  
  static boolean checkValue(int[][] a, int i, int j) {
    int h = 0;
    boolean[] x = new boolean[3];
    for(int k = 0; k < a.length; ++k) {
      for(int l = 0; l < a[k].length; ++l) {
        if(a[i][j] == a[k][l]) {
          x[h] = true;
          h++;
        } 
        if(h == 3) {
          boolean b = true;
          return b;
        }
      }
    }
    boolean b = false;
    return b;
  }
  
}
 
ist das wirklich dein Programm, überlege doch mal ne halbe Minute, was darin so passiert,
z.B. ob bei
memory[j] = (int) (Math.random() * ((n*m) / 2));
ein Wert von 0 möglich ist oder nicht (notfalls mit System.out.println() prüfen)
und ob dieser Wert 0 dann von checkValue() akzeptiert wird (notfalls mit System.out.println() prüfen)
usw.

dein Programm ist doch keine BlackBox, du kannst jede einzelne Entscheidung nachvollziehen
und die Bedingungen für diese Entscheidung dann bei Bedarf anpassen
 
Hoi,

/sign SlaterB

Sieht so aus, als ob die letzten Werte niemals durch random() befüllt werden. Sprich sie niemals erreicht werden oder irgendetwas passiert, damit da nichts reingeschrieben wird.

Prüf das mal nach.

greetz
SLi
 
Danke für die Antworten, hab es jetzt auch rausgefunden warum es nicht geklappt hat. Konnte leider nicht früher schreiben weil ich bis 8 in der Uni war 🙁

Also... das Problem ist, dass ich ja bei checkValue überprüfe ob der zufällig erstellte Wert schon 2x vorhanden ist, wenn ja (also true) wird ein neuer Wert erstellt.... und leider hab ich vergessen, dass wenn ich ein Array erstelle ALLES erstmal auf 0 gesetzt wird..... 😳 Daher wird natürlich der Wert 0 immer verworfen bis man bei den letzten beiden Stellen angekommen ist!!! 😎 Trotzdem nochmal danke fürs anschauen!

Und zu Slater: natürlich ist das mein Programm?! Warum sollte es das nicht sein ? Zeige euch mal die Musterlösung... hätte es doch besser so machen sollen *g*

Code:
class BuildMemory {

  public static void main(String[] args) {
    Out.print("Bitte Hoehe des Spielfeldes eingeben: ");
    int n = In.readInt();
    Out.print("Bitte Breite des Spielfeldes eingeben: ");
    int m = In.readInt();
    int[][] field = new int[n][m];
    fillField(field);
    showField(field);
  }

  static void fillField(int[][] field) {
    // verwendet den im Aufgabenblatt beschriebenen Algorithmus
    int n = field.length;
    int m = field[0].length;
    int noDigits = (n * m) / 2;
    int[] availableDigits = new int[noDigits];
    for (int i = 0; i < noDigits; ++i) {
      availableDigits[i] = 2;
    }
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) {
        int random;
        do {
          random = (int) (Math.random() * noDigits);
        } while (availableDigits[random] == 0);
        // Jetzt ist die Ziffer random noch verfuegbar.
        --availableDigits[random];
        field[i][j] = random;
      }
    }
  }

  static void showField(int[][] field) {
    Out.println("Inhalt des Spielfeldes: ");
    for (int i = 0; i < field.length; ++i) {
      for (int j = 0; j < field[0].length; ++j) {
        Out.print(field[i][j] + "  ");
      }
      Out.println();
    }
  }

}

Das is doch um einiges effizienter... muss das dann doch nochmal zwecks Übung umschreiben... aber dachte evtl klappts ja auch so 😀

Gruß, Marco
 
st das wirklich dein Programm, überlege doch mal ne halbe Minute, was darin so passiert,
z.B. ob bei
memory[j] = (int) (Math.random() * ((n*m) / 2));
ein Wert von 0 möglich ist


Und ja klar der Wert 0 ist möglich, bin ich zumindest der Meinung... hatte die Aufgabe ja schon mal gelöst vor ca. 3-4 Monaten, aber da hatte ich n anderen Algorithmus... Dachte halt nur, dass ich das noch etwas verschönern könnte. Naja 🙂

Wie kann ich denn jetzt n häkchen an das Thema machen ? Weil Thema ist ja eigentlich beendet... Und ansonsten ist der Programmierstil doch in Ordnung oder? Weil dafür könnte es sonst auch Punktabzug immer geben :-(
 
Und ansonsten ist der Programmierstil doch in Ordnung oder? Weil dafür könnte es sonst auch Punktabzug immer geben :-(
Ich weiß nicht, welche Anforderungen an euch gestellt werden, aber das Paradigma der Objektorientierung ist in deinem Programm nicht wirklich zu erkennen. (Du hast drei statische Methoden und reichst dort das Array durch. Objekorientierter wäre, ein Memory-Objekt zu erstellen, mit dem Array als Attribut!)
 
Ok danke für den Hinweis! Das musste ich gleich mal machen, und es wäre echt super wenn da nochmal jemand Zeit hätte kurz drüber zu schauen... Hab dieses mal auch die Exceptions abgefangen und dazu auch eigene Exception Klassen erstellt. Wäre super wenn ich dazu nochmal ein paar statements bekommen könnte!

Code:
import java.io.*;

class BuildMemory{

  public static void main(String[] args) {
  BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  try{
    System.out.print("Bitte Hoehe des Spielfeldes eingeben: ");
    int n = Integer.parseInt(in.readLine());
    System.out.print("Bitte Breite des Spielfeldes eingeben: ");
    int m = Integer.parseInt(in.readLine());
    // Überprüfen ob ungerade Zahl oder negative Zahl eingegeben wurde...
    if((n * m) % 2 != 0) {
      throw new NoOddNumbers(n * m);
    } else if(n < 0 || m < 0) {
      throw new NoNegativeNumbers(n * m);
    }
    Memory mem = new Memory(n, m);
    mem.showField();
  } catch(IOException x) {
    System.err.print("Lese-/Schreibfehler!");
  } catch(NoOddNumbers y) {
    System.err.print(y.getOdd() + " ist eine ungerade Zahl und daher "
                    + "ungueltig!");
  } catch(NoNegativeNumbers z) {
    System.err.print(z.getNegative() + " ist eine negative Zahl und "
                    + "daher ungueltig!");
  }
  
  }

}

Code:
class Memory {
  
  public boolean initialized;
  // n = Hoehe des Spielfeldes
  public int n;
  // m = Breite des Spielfeldes
  public int m;
  public int[][] mem;
  
  
  public Memory(int n, int m) {
    initialized = true;
    this.n = n;
    this.m = m;
    mem = new int[n][m];
    /* noDigits = Anzahl der verschiedenen Zahlenpärchen
       Bsp: n = 4, m = 5 --> 10 Zahlenpärchen --> 0,1,2,...,9 */
    int noDigits = (n * m) / 2;
    /* Erstellen eines Arrays der Länge noDigits... Initialisierung
       mit 2, da dies für die folgende Abbruchbedingung benötigt wird */
    int[] allowedDigits = new int[noDigits];
    for(int i = 0; i < allowedDigits.length; ++i) {
      allowedDigits[i] = 2;
    }
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j < m; ++j) {
        mem[i][j] = (int) (Math.random() * ((n*m) / 2));
        if(allowedDigits[mem[i][j]] == 0) {
        // Wenn == 0 ist das jeweilige Zahlenpärchen schon vorhanden,
        // also wird j verringert und das feld erneut berechnet.
          --j;
        } else --allowedDigits[mem[i][j]];
      }
    }
  }
  
  public void showField() {
    assert initialized;
    for(int i = 0; i < mem.length; ++i) {
      for(int j = 0; j < mem[0].length; ++j) {
        System.out.print((mem[i][j] > 9 ? mem[i][j] : " " + mem[i][j]) + " ");
      }
    System.out.println();
    }
  }
  
  
  
}

Code:
class NoOddNumbers extends Exception {
  
  int odd;
  
  NoOddNumbers() {
    super();
  }
  NoOddNumbers(int i) {
    odd = i;
  }
  public int getOdd() {
    return odd;
  }
}

Code:
class NoNegativeNumbers extends Exception{

  int negative;
  
  NoNegativeNumbers() {
    super();
  }
  NoNegativeNumbers(int i) {
  negative = i;
  }
  public int getNegative() {
    return negative;
  }
}

Das ist sicherlich nicht eine ideale Lösung, daher wäre ich für jeden Verbesserungsvorschlag und jegliche andere Kritik dankbar... selbstverständlich auch positive Kritik! 😀
 
Eine Exception in der Main-Methode zu schmeißen ist nicht wirklich sinnvoll, da du, wie du siehst sie dort auch wieder abfangen musst. Warum machst du die Überprüfung der Werte nicht in der Memory-Klasse? Es könnte ja jemand anderes das Memory-Objekt wiederverwenden wollen und der darf auch keine negativen Zahlen eingeben.
 
Jo, den Post von HLX kann ich nur unterstreichen. Was auch nocht nicht perfekt ist, ist die Organisation deines Memory-Objekts. Zum einen sind alle Attribute public (das ist nicht gut, sie sollten privat sein und du solltest getter-und setter-Methoden bereitstellen) und zum anderen hast du dort redundante Attribute gespeichert.

boolean initialized: Wozu soll das gut sein? Du hast nur einen Konstruktor und der initialisiert das Feld, setzt die Variable auf true. Wenn du ein Memory-Objekt hast, ist es also in jedem Fall initialized. Was sagt das Attribut also aus?

Höhe und Breite: brauchst du auch nicht extra abspeichern. Kannst du in den get-Methoden einfach über mem.length und mem[0].length rausfinden.

Noch was zur Methode show-Field: Ein bisschen elegenater wäre, den Rückgabetypen auf String zu setzen. Das ausgeben auf den Bildschirm kann eine aufrufende Klasse machen. Ist vielseitiger.
 
Ok, danke 🙂

Da werd ich mich nochma dran setzen! Aber muss nochma paar Wissensfragen nu pauken und letzte Vorbereitungen treffen!
 
Hallo!

Hab das Programm nochmal abgeändert und wollte gern nochmal wissen was denn nun der Vorteil ist wenn ich den Rückgabetyp auf String setze...???Weil ich dacht es wär schon gut wenn ich mem.showField(); mache und es automatisch ausgegeben wird... nun musste ich ne for-Schleife in die BuildMemory machen damit es nicht nur in einer Zeile steht, sondern natürlich die Höhe und Breite korrekt ausgegeben werden. Ist wahrscheinlich auch noch immer nich ausgereift, würde trotzdem sehr gerne nochmal n feedback haben. das wäre echt super!!!

Mein Code:

Code:
import java.io.*;

class BuildMemory {

  public static void main(String[] args) {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    try{
    System.out.print("Bitte Hoehe des Spielfeldes eingeben: ");
    int n = Integer.parseInt(in.readLine());
    System.out.print("Bitte Breite des Spielfeldes eingeben: ");
    int m = Integer.parseInt(in.readLine());
    Memory mem = new Memory(n, m);
    // Ausgeben des Memory Spielfeldes durch mitgabe eines counters i
    for(int counter = 0; counter < mem.getWidth(); ++i) {
      System.out.println(mem.showField(counter));
    }
    } catch(IOException x) {
      System.err.print("Lese-/Schreibfehler!");
    }
    
  
  }

}

Code:
class Memory {
  
  private int[][] mem;
 
  public Memory(int n, int m) {
    // Überprüfen ob ungerade Zahl oder negative Zahl eingegeben wurde...
    try{
    if((n * m) % 2 != 0) {
      throw new NoOddNumbers(n * m);
    } else if(n < 0 || m < 0) {
      throw new NoNegativeNumbers(n * m);
    }
    } catch(NoOddNumbers y) {
      System.err.println(y.getOdd() + " ist eine ungerade Zahl und daher "
                      + "ungueltig!");
    } catch(NoNegativeNumbers z) {
      System.err.println(z.getNegative() + " ist eine negative Zahl und "
                      + "daher ungueltig!");
    }
    mem = new int[n][m];
      /* noDigits = Anzahl der verschiedenen Zahlenpärchen
       Bsp: n = 4, m = 5 --> 10 Zahlenpärchen --> 0,1,2,...,9 */
    int noDigits = (n * m) / 2;
    /* Erstellen eines Arrays der Länge noDigits... Initialisierung
       mit 2, da dies für die folgende Abbruchbedingung benötigt wird */
    int[] allowedDigits = new int[noDigits];
    for(int i = 0; i < allowedDigits.length; ++i) {
      allowedDigits[i] = 2;
    }
    for(int i = 0; i < n; ++i) {
      for(int j = 0; j < m; ++j) {
        mem[i][j] = (int) (Math.random() * noDigits);
        if(allowedDigits[mem[i][j]] == 0) {
        // Wenn == 0 ist das jeweilige Zahlenpärchen schon vorhanden,
        // also wird j verringert und das feld erneut berechnet.
          --j;
        } else --allowedDigits[mem[i][j]];
      }
    }
  }
  
  public int getWidth() {
    return mem.length;
  }
  
  public int getHeight() {
    return mem[0].length;
  }
  
  public String showField(int i) {
    StringBuffer s = new StringBuffer();
    if(i < mem.length) {
      for(int j = 0; j < mem[i].length; ++j) {
        s.append(mem[i][j]);

        if(mem[i][j] > 9) {
          s.append(" ");
        } else s.append("  ");
      }
    } return s.toString();
  }
  
}

Gruß,

Marco
 
Marco1983 hat gesagt.:
nun musste ich ne for-Schleife in die BuildMemory machen damit es nicht nur in einer Zeile steht, sondern natürlich die Höhe und Breite korrekt ausgegeben werden.

So hatte ich das nicht gemeint. Du kannst das ruhig in einem einzigen String zurückgeben, nicht zeilenweise. Dazu kannst du im String einfach Zeilenumbrüche einfügen! Unter Linux wäre das "\n", unter Windows "\r\n", aber es gibt auch irgendeine Methode, die JVM den passenden Zeilenumbruch wählen zu lassen, die fällt mir nur grad nicht ein. Ansonsten sieht das schon sehr gut aus.
 
Achso mit \r\n .... ich hatte es nur mit \n versucht und hab win xp drauf... muss ich wohl überlesen haben auf der seite... hmpf 🙂 Und dann is mir nix besseres eingefallen, also hab ich das einfach so gemacht... Werde das auf jeden Fall nochmal abändern, danke!
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben