Bestimmte Zahlen bei Math.random ausschließen?

Wuast

Bekanntes Mitglied
Hallo,
gibt es eine elegante Lösung um auszuschließen, dass mehrere integer, die mittels der math.random initialisiert wurden, die gleiche Zahl erhalten?

Java:
// es sollen zwei Punktobjeke mit den Zufalls-Koordinaten x1/y1 und x2/y2 geben

for (int i = eingabe; i <= eingabe2; i++) {    //eingabe und eingabe 2 kommen von der Konsole und geben den Spielfeldrahmen vor
          
        x1 = (int) ((Math.random() * eingabe2)+1);   
        y1 = (int) ((Math.random() * eingabe1)+1);         
  
        x2 = (int) ((Math.random() * eingabe2)+1);          // x2 soll != 1 sein, wenn
        y2 = (int) ((Math.random() * eingabe1)+1);          // y2 ==y1 ist (und vice versa)

        java.awt.Point Spieler1 = new java.awt.Point(x1, y1);          //
        java.awt.Point Spieler2 = new java.awt.Point(x2, y2);          //

}

Meine Gedanken gehen in Richtung

Java:
if (Spieler1 == Spieler2) {
    ... //  noch keine konkrete Idee, Vorschläge sind natürlich sehr willkommen
 
}

oder vllt.
    do {
        // wie könnte ich das formulieren? vllt. einfach wieder so:
         x2 = (int) ((Math.random() * eingabe2)+1);
         y2 = (int) ((Math.random() * eingabe1)+1);
    }
while (Spieler1 == Spieler2)

    // die Punkte dürfen nicht die gleichen Koordinaten haben

Was sagt ihr zu den Vorschlägen? Da es im Verlauf mehr als zwei Spieler geben kann, bin ich unsicher, ob ich mit der if-Abfrage oder dem do-While so gut fahre.
Kennt ihr aber vllt. noch etwas "besseres", was verhindert, dass Math-Random die gleichen Zufallskoordinaten ausspuckt?

Grüße Yannik
 
Ich habe jetzt
Java:
do {
            x2 = (int) ((Math.random() * spielfeldBreite)+1);
            y2 = (int) ((Math.random() * spielfeldHöhe)+1);
        }
        while (spieler1.equals( spieler2) );    //spieler2.x=x2 //spieler2.y=y2
wenn es etwas schickeres gibt, was ich direkt in die Math.random packen kann, freue ich mich über eine Info 🙂

Ich möchte noch eine andere (wichtigere) Frage ergänzen:

Wie kann ich sicherstellen, dass die Spielerpositionen im Rahmen des Spielfeldes gesetzt werden? Manchmal wird mit ein Spieler nicht in der Konsole angezeigt.

Die Eingaben definieren den Rahmen, in welchem die Spieler gesetzt werden.
eingabe1 entspricht der y-Achse, eingabe2 der x-Achse (also Höhe und Breite), die als System.out.print('-') dargestellt werden.

Java:
for (int y = 0; y < eingabe1; y++) {
                for (int x = 0; x < eingabe2; x++) {
                    java.awt.Point p = new java.awt.Point(x, y);
                    if (spieler1.equals(p)) {
                        System.out.print('1');
                    }
                    else if (spieler2.equals(p)) {
                        System.out.print('2');
                    }
                    else System.out.print('-');
                }
                System.out.println();

Manchmal scheint einer der spieler außerhalb des Spielfeldes zu liegen.

Danke und LG

PS: Ich hoffe, ich stifte hier keine Verwirrung und das Gerüst ist klar 🙂 Sonst bitte nochmal darauf hinweisen.
 
Zuletzt bearbeitet:
gibt es eine elegante Lösung um auszuschließen, dass mehrere integer, die mittels der math.random initialisiert wurden, die gleiche Zahl erhalten?
Naja, was heißt elegant? Man kann sich erst einmal überlegen, dass gilt: (a,c) == (b,d) gdw. a == b und c == d.

D. h. die Koordinaten a, c und b können schon mal beliebig innerhalb ihrer Grenzen gewählt werden: Wenn a != b gilt, können wir auch d beliebig wählen, nur wenn a == b gilt, muss d so gewählt werden, dass c != d gilt.
Java:
Random rand = new Random();
int a, b, c, d;

a = rand.nextInt(breite);
b = rand.nextInt(breite);
c = rand.nextInt(hoehe);
if (a == b) {
    // TODO: wähle d aus der Menge [0, hoehe[ \ {c}
} else {
    d = rand.nextInt(hoehe);
}
Betrachten wir noch das TODO.

Wir hatten c aus der Menge [0, hoehe[ ⊆ ℕ gewählt. Diese Menge hat hoehe Elemente, d. h. für die Wahl von c standen hoehe verschiedene Möglichkeiten zur Verfügung. Da wir das c nun aus der Menge der Möglichkeiten für d herausnehmen wollen, gibt es für d nur noch hoehe-1 Möglichkeiten.

Wir wählen d also aus der Menge [0, hoehe-1[ ⊆ ℕ. Gilt d < c, haben wir unser d gefunden. Gilt d >= c, dann brauchen wir d nur um 1 zu erhöhen, um das d in das Intervall ]c, hoehe[ zu verschieben. Ersetzen wir also das TODO durch:
Java:
    d = Math.nextInt(hoehe-1);
    if (d >= c) {
        d++;
    }
Fertig.

Damit sollte auch die Frage
Wie kann ich sicherstellen, dass die Spielerpositionen im Rahmen des Spielfeldes gesetzt werden?
beantwortet sein.
 
Danke für deine ausführliche Antwort!!

Ich übertragedeine abcd-Konstanten gedanklich auf mein Bsp., demnach wäre bei mir
spieler1(x,y) = spieler1(a,c) und spieler2(b,d), korrekt?^^

So ganz habe ich es noch nicht. Schau mal bitte:

Java:
public class Spiel {
   
    public static void main(String[] args) {
       
        int eingabe1 = new java.util.Scanner(System.in).nextInt(); //Spielfeldbreite
        int eingabe2; //Spielfeldhöhe
       
        do{
        int eingabe2 = new java.util.Scanner(System.in).nextInt(); //Spielfeldhöhe festlegen
            if (eingabe2 >= eingabe1){
                System.out.println("bitte kleiner"); //Sollte breiter als hoch sein, macht den Code nachfolgend einfacher denke ich?! sieht jedenfalls besser aus
            }
        }
        while (eingabe2 >= eingabe1)
           
    //Ist das so überhaupt korrekt?

    for (int i = eingabe1; i <= eingabe2; i++) {
        x1 = (int) ((Math.random() * eingabe2)+1);    //dein a
        y1 = (int) ((Math.random() * eingabe2)+1);    //dein c
       
        x2 = (int) ((Math.random() * eingabe2)+1);    //dein b
        y2 = (int) ((Math.random() * eingabe2)+1);    //dein d
       
        //jetzt deine TODO? Irgendwas stimmt doch hier noch nicht :D
       
        if (x1 == x2){
            if (y2 >= y1){
                y2 ++;
            }
        }
       
        for (int y = 0; y < eingabe2; y++)    //koordinaten d. nachfolgenden Punktobjekts
            for (int x = 0; x < eingabe1; x++){
                java.awt.Point p = new java.awt.Point(x,y);
                if (spieler1.equals(p)){
                    System.out.print('1');
                }
                if (spieler2.equals(p)){
                    System.out.print('2');
                }
                else System.out.print('-');
            }
       
    }

Das habe ich jetzt aktuell dazu. Deine Erläuterung macht für mich - wenn auch mathematischer ausgedrückt als es mir lieb ist 😀 - durchaus Sinn. Einfach ausgedrückt muss ich ja nur sicherstellen, dass wenigstens eine x oder eine y-Koordinate bei den Spieler-Punktobjekten abweichend von der jeweils anderen ist?!
Aber so richtig KLICK gemacht hat es noch nicht :/
 
Einfach ausgedrückt muss ich ja nur sicherstellen, dass wenigstens eine x oder eine y-Koordinate bei den Spieler-Punktobjekten abweichend von der jeweils anderen ist?!
Richtig.

Machen wir das mal mit einer Dimension.

Aufgabe: wähle zufällig zwei verschiedene(!) Zahlen zwischen 0 und 5.

Wir können uns gedanklich eine Liste mit diesen 6 Zahlen aufschreiben:
012345

Jetzt können wir mit rand.nextInt(6) zufällig eine dieser Zahlen wählen. Sagen wir mal, wir hätten die 2 ermittelt. Soweit kein Problem. Wie können wir jetzt aber die 2 beim Ermitteln der nächsten Zahl ausschließen?

Streichen wir die 2 mal gedanklich aus unserer Liste:
012345

Offensichtlich stehen nur noch 5 Zahlen zur Wahl: 0, 1, 3, 4 und 5 sind fünf Stück. Also rufen wir nextInt(5) auf und erhalten so eine Zahl zwischen 0 und 4. Das können wir mal mit einem Sternchen in die Tabelle einzeichnen:

012345
*****

Wenn die zufällig gezogene Zahl kleiner als die gestrichene 2 ist, können wir sie unmittelbar verwenden. Ist sie größer oder gleich 2, müssen wir sie nur um eine Spalte nach rechts verschieben, also 1 addieren, dann ergibt sich folgendes Bild:

012345
*****

Damit wäre die Aufgabe gelöst und im Code sähe das so aus:
Java:
int zahl1 = rand.nextInt(6);
int zahl2 = rand.nextInt(5);
if (zahl2 >= zahl1) {
    zahl2++;
}
Jetzt klar?
 
Ja, das schon! Danke! 😁👌

Also im Code konkrekt bei dann
Java:
if (x1 == x2 && y1 == y2){
    if (x2 >= x1 || y2 >= y1 ){
        y2++;
    }
}

richtig?? Ich muss ja nur aktiv werden, wenn sowohl x1undx2, als auch y1undy2 gleich sind. Ansonsten ist es ja egal.

Müsste nicht aber folgender Code auf das gleiche rauskommen?
Java:
do {
            x2 = (int) ((Math.random() * spielfeldBreite)+1);
            y2 = (int) ((Math.random() * spielfeldHöhe)+1);
        }
        while (spieler1.equals( spieler2) );
Dieser Teil bewirkt doch, dass - immer wenn spieler1 (Punkt mit den Koordinaten x1,y1) und spieler2 (Punkt mit den Koordinaten x2,y2) equal sind, wird spieler2 einfach neu zufällig bestimmt.

Nur das Problem, dass manchmal Spieler1 oder Spieler2 außerhalb des Feldes gesetzt werden, wird doch dadurch nicht gelöst, oder (also weder durch deine Lösung mit der if-Abfrage, noch durch meinen Vorschlag mit der dowhile-Schleife)? Weil im Code habe ich doch weiterhin

Java:
y2= (int) ((Math.random() * eingabe2)+1);

Müsste dann statt +1 -1 dahin? (in Gedanken bei deiner ersten Antwort)
Wir hatten c aus der Menge [0, hoehe[ ⊆ ℕ gewählt. Diese Menge hat hoehe Elemente, d. h. für die Wahl von c standen hoehe verschiedene Möglichkeiten zur Verfügung. Da wir das c nun aus der Menge der Möglichkeiten für d herausnehmen wollen, gibt es für d nur noch hoehe-1 Möglichkeiten.

Wir wählen d also aus der Menge [0, hoehe-1[ ⊆ ℕ. Gilt d < c, haben wir unser d gefunden. Gilt d >= c, dann brauchen wir d nur um 1 zu erhöhen, um das d in das Intervall ]c, hoehe[ zu verschieben. Ersetzen wir also das TODO durch:
Java:
    d = Math.nextInt(hoehe-1);
    if (d >= c) {
        d++;
    }
Fertig.

Damit sollte auch die Frage

beantwortet sein.
Vielen Dank für deine Hilfe!!
 
Müsste nicht aber folgender Code auf das gleiche rauskommen?
Das Snippet als solches bewirkt entweder nichts oder eine Endlosschleife, weil Du in der Schleife weder an spieler1 noch an spieler2 etwas geändert wird.

Was Deine Erklärung betrifft: die wäre natürlich richtig. Der Unterschied ist nur: mit oder ohne Schleife. Die Schleife wird halt ggf. mehrfach durchlaufen.

Bau Dir doch einfach ein paar Methoden:
Java:
/** Returns a random integer.
 *
 * @param  bound  upper bound.
 * @return random int between 0 and bound-1.
 */
static int randomInt(int bound) {
     return (int)(Math.random() * bound);
}

/** Returns a random integer different from a given value.
 * 
 * @param  bound  upper bound
*  @param  excluding  the value the result must not match
*  @return random int between 0 and bound-1, guaranteed to be different from {@code excluding}.
*/
static int randomIntExcluding(int bound, int excluding) { 
    if (excluding < 0 || excluding >= bound) {
        return (int)(Math.random() * bound);
    }

    int value = (int) (Math.random() * (bound-1));
    if (value >= excluding) {
        value++;
    }
    return value;
}

Die kannst Du dann einfach testen (dazu müsstest Du allerdings java.util.Random mit einem Seed verwenden und evtl. in eine Klasse auslagern) und auch verwenden:

Java:
int x1 = randomInt(spielfeldBreite);
int y1 = randomInt(spielfeldHoehe);
int x2 = randomInt(spielfeldBreite);
int y2 = (x1 == x2) ? randomIntExcluding(spielfeldHoehe, y1) : randomInt(spielfeldHoehe);

Nur das Problem, dass manchmal Spieler1 oder Spieler2 außerhalb des Feldes gesetzt werden, wird doch dadurch nicht gelöst,
Das Problem wird dadurch gelöst, dass Du Dir klar machst, dass man von 0 beginnt zu zählen 🙂 Eine Breite von 10 heißt, dass der Spieler an Positionen 0, 1, 2, 3, ..., 9 sein kann.
 
Bau Dir doch einfach ein paar Methoden:
Entspricht leider nicht mehr den Vorgaben: 3 Methoden., d.h. Menü inkl. Einstellungen, Spiel, Main zum Aufrufen.

In die Einstellungen stopfe ich gerade alles rein, was so nötig ist, um das Spiel zu konfigurieren. Dazu zählt z.B. die Möglichkeit, das Spielfeld einstellen zu können, sprich eingabe1 und eingabe2.

Spieler1 und Spieler2 müssen jetzt irgendwo zufällig in diesem Rahmen gesetzt werden, d.h. deren Koordinaten x1y1 und x2y2 sind zufällig zu ermitteln.
Dazu habe ich folgende Möglichkeit recherchiert und versucht auf meine Situation bezogen richtig anzuwenden (s.oben):

Java:
 for (int i = eingabe1; i <= eingabe2; i++) {
        x1 = (int) ((Math.random() * eingabe2)+1);    //dein a
        y1 = (int) ((Math.random() * eingabe2)+1);    //dein c
     
        x2 = (int) ((Math.random() * eingabe2)+1);    //dein b
        y2 = (int) ((Math.random() * eingabe2)+1);    //dein d

Das man bei 0 anfängt habe ich mal gelernt, stimmt 😉 Daraus folgt die -1, weil wenn ich z.B. 10 Felder/Möglichkeiten/... generiere, macht der Rechner daraus 0-9 (das entspricht 10 Feldern/Möglichkeiten/...). Soweit klar!

Übertragen auf die for-Schleife heißt das, ich multipliziere die Math.random-Zahl mit der Breite (der Maximal-Wert) und rechne dann -1 und nicht +1?! oder müsste es lauten
Java:
        x1 = (int) ( ((Math.random() * eingabe2)-1) +1);
?


Ich kann verstehen, dass hier keine Lösungen präsentiert werden und grundsätzlich möchte ich das auch nicht. Aber ich bin an einem Punkt angekommen wo mir etwas der Schädel raucht und ich es nicht noch komplizierter machen kann als es für mich schon ist 😀 (also noch zusätzlich rumexperimentieren und random mit seed und so, dass verschiebe ich auf wenn ich den Kopf wieder frei habe 😉 )

Insofern frage ich jetzt mal ganz direkt: Habe ich das so richtig umgesetzt
Java:
if (x1 == x2 && y1 == y2){
    if (x2 >= x1 || y2 >= y1 ){
        y2++;
    }
}
oder nicht? 🤯😭


Wie immer dickes Dankeschön!
In größerwerdender Verzweiflung
Yannik
 
Übertragen auf die for-Schleife heißt das, ich multipliziere die Math.random-Zahl mit der Breite (der Maximal-Wert) und rechne dann -1 und nicht +1?!
Du multiplizierst einfach mit der Breite. Fertig. Die Breite ist nicht der Maximalwert, sondern die obere Grenze, die niemals erreicht wird.

Warum?

Math.random() liefert eine Gleitkommazahl zwischen 0 und 1, jedoch ohne die 1.

Für y = Math.random() gilt somit 0 <= y < 1.

Multipliziert mit der nicht-negativen Breite b ergibt sich 0 <= y*b < b, d. h. insbesondere, dass Math.random()*b eine Zahl liefert, die kleiner als die Breite b ist.

Castest Du jetzt noch auf ein int, schneidest Du damit halt noch die Nachkommastellen weg und damit gilt:

0 <= (int)(Math.random() * b) <= (b-1)
 
Du multiplizierst einfach mit der Breite. Fertig. Die Breite ist nicht der Maximalwert, sondern die obere Grenze, die niemals erreicht wird.

Warum?

Math.random() liefert eine Gleitkommazahl zwischen 0 und 1, jedoch ohne die 1.

Für y = Math.random() gilt somit 0 <= y < 1.

Multipliziert mit der nicht-negativen Breite b ergibt sich 0 <= y*b < b, d. h. insbesondere, dass Math.random()*b eine Zahl liefert, die kleiner als die Breite b ist.

Castest Du jetzt noch auf ein int, schneidest Du damit halt noch die Nachkommastellen weg und damit gilt:

0 <= (int)(Math.random() * b) <= (b-1)
JETZT...wo ich das lese.. frage ich mich, ob ich wirklich so beschränkt bin 😀

Vielen Dank!! 🙂
 
Was sind den das für Vorgaben? Wie lautet die Aufgabenstellung?
2 Spieler (Jäger, Gejagter) zufällige Positionen mehrerer Punktobjekte, d.h. Spieler und Ausgang, Spielfeld einstellbar. Main zur Ausführung, Klasse Einstellungen, Klasse Spielfeld und sinnvolle Aufteilung und Untergliederung der Methoden. Vereinfacht ausgedrückt. 😀

Aber mit mihes Erörterungen sieht es jetzt ganz brauchbar aus.

Ein Problem habe ich noch zu lösen, da habe ich irgendwas bei den Einstellungen vermurkst aber vllt. und hoffentlich kriege ich es alleine hin. Ansonsten gibts bald nen neuen Thread. Der Rest sieht aber ganz gut aus würd ich sagen
 
Spieler (Jäger, Gejagter) zufällige Positionen mehrerer Punktobjekte, d.h. Spieler und Ausgang, Spielfeld einstellbar. Main zur Ausführung, Klasse Einstellungen, Klasse Spielfeld und sinnvolle Aufteilung und Untergliederung der Methoden. Vereinfacht ausgedrückt.
Da steht aber nichts von einer Limitierung auf nur 3 Methoden.
 
das kann man durchaus auch als das komplette Gegenteil von:

verstehen.
tja... was soll ich machen 😀 lass mich erstmal korrigieren: 3 Klassen. innerhalb derer ist eine sinnvolle Methodenwahlzu erstellen und in der Main entsprechend darauf zuzugreifen.
Da steht aber nichts von einer Limitierung auf nur 3 Methoden.
klassen, sorry. s.o.

bin bisschen durch damit gerade 😀

Darf ich in einer Methode nicht mehrere returns haben?

Java:
         x1 = (int) ((Math.random() * eingabe2); 
        y1 = (int) ((Math.random() * eingabe2); 
  
        x2 = (int) ((Math.random() * eingabe2); 
        y2 = (int) ((Math.random() * eingabe2); 
                  
    Point spieler1 = new java.awt.Point(x1,y1);
    Point spieler2 = new java.awt.Point(x2,y2);
                  
                    return spieler1;
                    return spieler2; //geht nicht... unreachable code WARUM??? :D

Muss man sowas immer über getter machen wenn ich mehrere Werte zurückgeben möchte?
 
Nein. Dafür kann man sich selber einen Typ (Klasse) bauen und dann ein Objekt dieser Klasse zurückgeben.
Driet.. es bleibt spannend!
Aber eigentlich kann ich die Spielerpositionen ja auch in die selbe Methode packen, die dann den Spielablauf steuert.

Oder meinst du, dass wäre "nicht elegant"? Ist ja kein riesen Spiel, nur ein kleines Progrämmchen, da wirds ja nicht unübersichtlich. ^^
 
hmmm @Wuast , wie wärs damit?

Java:
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class NoDuplicatesIterator implements Iterable<Integer> {
    public class NoDuplicatePointsIterator implements Iterable<Point> {
        @Override
        public Iterator<Point> iterator() {
            final NoDuplicatesIterator xsIterator1 = new NoDuplicatesIterator(n);
            final NoDuplicatesIterator ysIterator1 = new NoDuplicatesIterator(n);

            return new Iterator<>() {
                private Iterator<Integer> xsIterator2 = xsIterator1.iterator();
                private Iterator<Integer> ysIterator2 = ysIterator1.iterator();

                @Override
                public boolean hasNext() {
                    return ysIterator2.hasNext();
                }

                @Override
                public Point next() {
                    Point p1 = new Point(xsIterator2.next(), ysIterator2.next());
                    if (!ysIterator2.hasNext()) {
                        ysIterator2 = ysIterator1.iterator();
                    }
                    if (!xsIterator2.hasNext()) {
                        xsIterator2 = xsIterator1.iterator();

                        ysIterator2.next();
                    }
                    return p1;
                }
            };
        }
    }

    private final int n;
    private final ArrayList<Integer> list = new ArrayList<>();

    public NoDuplicatesIterator(int n) {
        this.n = n;
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
        Collections.shuffle(list);
    }

    @Override
    public Iterator<Integer> iterator() {
        return list.iterator();
    }

    public static void main(String[] args) {
        for (Point p1 : new NoDuplicatesIterator(4).new NoDuplicatePointsIterator()) {
            System.out.println(p1);
        }
    }
}

Rennt in O(n). 😀
 
@Kamil1
Dein Code lässt nicht zu, dass sich X oder Y Koordinate gleichen. Es muss aber nur verhindert werden, dass x und y Koordinate gleich sind.

Wird spätestens dann problematisch, wenn Du n unterschiedliche Punkte hast mit n > xmax oder n>ymax. Also z.B. 11 unterschiedliche Punkte auf einem 10x10 Spielfeld.
 
Aber eigentlich kann ich die Spielerpositionen ja auch in die selbe Methode packen, die dann den Spielablauf steuert.

Oder meinst du, dass wäre "nicht elegant"? Ist ja kein riesen Spiel, nur ein kleines Progrämmchen, da wirds ja nicht unübersichtlich. ^^
Damit hast Du sehr schön erkannt, wie es dazu kommt, dass Code immer schlechter wird. Ist ja nur eine kleine Änderung und so unübersichtlich ist es nicht. Und wenn doch, dann hat man ja einen Kommentar dazu gepackt ... Außerdem hat man doch gerade jetzt gar keine Zeit, es richtig zu machen.

Generell sollte man sich immer gut überlegen, wie die Dinge aufgebaut sind und dann auch Elemente, die zusammen gehören, zusammen packen.

Die Position der Spieler gehört zu dem Spieler. Damit sind wir uns doch erst einmal einig denke ich mal. Also sowas wie
Java:
public class Player {
    private Point position;
    
    // ...
}

Die Zwei Spieler mit Ihrer Position: Was bedeutet das denn genau? Die Position sind ja Koordinaten... Von was? Das ist doch eine Map oder Spielfeld oder so. Damit haben wir ja schon die nächste Klasse: Es gibt eine Map mit Spielern:
Java:
public class GameMap {
    private List<Player> player;
    
    // ...
}

Nun müssen n Spieler positioniert werden. Aber doch natürlich auf dem Spielfeld. Also überlegen wir uns einmal, wo das hin gehören würde. Methoden, die etwas in einen Container packen, sind immer am Container zu finden. List.add z.B. Ist hier auch nicht anders:
-> Die Methode gehört in die GameMap.

Wenn Du etwas so aufteilst, dann kann dieses Problem nie entstehen. Denn jede Methode macht ja etwas anderes. Eine Methode, die also A und B erzeigt und die hängen auch nicht wirklich zusammen, kann es so eigentlich nie geben. Dann wären es ja auch zwei Methoden geworden. Oder sie gehören zusammen - dann muss der Zusammenhang irgendwo abgebildet sein ("A gehört zu B" oder "A und B gehören zu C". Hier ist es letzteres: Die Spieler gehören zum Spielfeld.)

Jetzt kannst Du da den Code auch schreiben. Unabhängig davon, was wir bisher so alles hatten an Vorgehen im Thread, kann man sich das von Grund auf überlegen. Das kann man sich auch ganz einfach bildlich vorstellen:

Du hast ein Spielfeld von 6x6 und einen Würfel. Du sollst da jetzt eine Reihe Spielfiguren plazieren. Also was machst Du?

So lange wie ich noch unplazierte Spielfiguren habe:
- ich nehme den Würfel und würfle -> neue X Position
- ich nehme den Würfel und würfle -> neue Y Position
- Wenn die Position (X,Y) frei ist: platziere die nächste Figur dort.

Das kann man durchspielen und schauen, ob es funktioniert.
==> Erster Algorithmus ist soweit fertig. Kann man testen und dürfte gut funktionieren.

==> Ein typisches Vorgehen um mehrere unterschiedliche zufällige Elemente zu bekommen. Kann man also im Hinterkopf behalten.

Nun wollen wir aber 36 Spielfiguren auf dem 6 mal 6 Spielfeld platzieren.
Wir stellen uns nur die Situation vor: nur ein Platz ist frei. Und du würfelst jetzt so lange, bis der erste Wurf die freie x-Koordinate ergibt und der zweite Wurf die freie y Koordinate. Das ist etwas doof. Mit 6 mal 6 mag es noch gehen, aber stell Dir vor Du hast 1000x1000 Felder ...

Schauen wir in die Welt: Wie klappt das denn da? Lotto-Zahlen 6 aus 49: Da sind nie Doppelte!
Wenn wir uns so ein Gerät anschauen, dann sehen wir: Das Gerät nimmt aus einer Menge von Kugeln eine raus. Die ist dann aus der Menge entfernt. Das können wir auch abbilden. Wir erzeugen eine Liste aller Möglichkeiten und nehmen da ein zufälliges Element raus und entfernen es.
==> Das geht von der Laufzeit sehr gut, aber man erkennt den nächsten Nachteil: Das braucht Vorbereitung und Speicherplatz: Schreibe mal alle Felder einer 1000x1000 Spielfeldes auf Zettel und pack die in kleine Ü-Ei Behälter. 1 Millionen Behälter brauchen viel Platz... Aber da kannst Du dann schön immer einzelne Kugeln entnehmen. Wirst Du aber vermutlich nicht machen, wenn Du nur 5 Werte brauchst.

==> Zweiter, universeller Ansatz. Inkl. einer kleinen Betrachtung von Vor- und Nachteilen.

Was will ich damit aufzeigen: Saubere, objektorientierte Struktur und die Dinge passen direkt gut zusammen. Und dabei immer ruhig den bildlichen Vergleich haben. Das geht in den meisten Fällen und hilft dann auch, die natürlichen Grenzen zu erkennen und entsprechend im Model abzubilden.

Ich hoffe, ich konnte diese Punkte etwas erläutern.
 
Oder meinst du, dass wäre "nicht elegant"? Ist ja kein riesen Spiel, nur ein kleines Progrämmchen, da wirds ja nicht unübersichtlich. ^^
Oder du könntest ein Spielfeld machen in das Spielobjekte eingefügt werden können. Die Spielobjekte haben die Positionen.
Die Methode
Java:
public SpielFeld(){
    ..
    boolean add( SpielObjekt o ){
        // prüfe
        // ob Postion von o erlaubt ist sonst --> false
        // ob Postion von o besetzt ist sonst --> false
        // füge o zum Spielfeld hinzu --> true
    }
}
 
Naja also wenn die Erwartung ist, den Code einfach zu halten, damit er übersichtlich und leicht lesbar bleibt, finde ich es mit meiner kaum vorhandenen Erfahrung sinnvoll, nicht für jeden Kram eine Klasse und Methode zu schreiben, sondern es kompakt zu halten (sofern möglich und sinnvoll). Die Grundstruktur von dem Code ist bereits gegeben (und der Insel zu entnehmen). Nun soll es entsprechend den Vorgaben angepasst und um ein Hauptmenü ergänzt werden, sprich die Klassen und sinnvolle Methoden. Im Buch ist das gesamte Spiel in der main auf 2 Seiten geschrieben. Finde ich nicht unübersichtlich, da mit Kommentaren versehen.

Aber wahrscheinlich fehlt mir hier der von Erfahrungswerten gestützte Blick und das Know-How, um es besser umzusetzen.
Oder du könntest ein Spielfeld machen in das Spielobjekte eingefügt werden können. Die Spielobjekte haben die Positionen.
[/CODE]
So soll es aussehen, genau.
 
hmmm @Wuast , wie wärs damit?
(...)

Rennt in O(n). 😀
Danke für deine Überlegungen, aber ungeachtet der Anmerkungen von Kneiztel ist mir das an dieser Stelle zu viel unbekanntes. Habe es doch jetzt lösen können mit mihe7s Erklärungen und Vorschlägen.


Damit hast Du sehr schön erkannt, wie es dazu kommt, dass Code immer schlechter wird. Ist ja nur eine kleine Änderung und so unübersichtlich ist es nicht. Und wenn doch, dann hat man ja einen Kommentar dazu gepackt ... Außerdem hat man doch gerade jetzt gar keine Zeit, es richtig zu machen.

==> Ein typisches Vorgehen um mehrere unterschiedliche zufällige Elemente zu bekommen. Kann man also im Hinterkopf behalten.


Ich hoffe, ich konnte diese Punkte etwas erläutern.

Rieche ich da Sarkasmus? 😀

Das typische Vorgehen werde ich mir merken!

Danke
 
Naja also wenn die Erwartung ist, den Code einfach zu halten, damit er übersichtlich und leicht lesbar bleibt, finde ich es mit meiner kaum vorhandenen Erfahrung sinnvoll, nicht für jeden Kram eine Klasse und Methode zu schreiben, sondern es kompakt zu halten
Das kann ich in keiner Weise nachvollziehen. Gerade ohne Erfahrung wirst Du kaum in der Lage sein, den stark verschachtelten Code, der ohne eben Methoden und Klassen entsteht, auch nur ansatzweise zu verstehen. Von so Dingen wie Kommentierung durch gut gewählte Bezeichner rede ich da noch nicht einmal.

Das ist ein Punkt, der von Anfang an schlicht existenziell ist und viel zu wenig gerade den Anfängern vermittelt wird.
 
Das kann ich in keiner Weise nachvollziehen. Gerade ohne Erfahrung wirst Du kaum in der Lage sein, den stark verschachtelten Code, der ohne eben Methoden und Klassen entsteht, auch nur ansatzweise zu verstehen. Von so Dingen wie Kommentierung durch gut gewählte Bezeichner rede ich da noch nicht einmal.

Das ist ein Punkt, der von Anfang an schlicht existenziell ist und viel zu wenig gerade den Anfängern vermittelt wird.
Scheinbar. Ich glaube dir wirklich und werde es beherzigen.
In diesem Fall möchte ich nur darauf hinweisen, dass der Code im Leittext an einem Stück geschrieben ist und ich ihn gut verstehen kann (wirklich sehr einfach, ohne viel Schnickschnack). Die Leistung jetzt besteht darin, den gegebenen Code anzupassen und zu sortieren (damit er auch mit den Ergänzungen lesbar bleibt denke ich?! - wobei ich sagen muss, dass es mir leichter gefallen wäre, die Ergänzungen in der main zu implementieren, wäre eine halbe Seite Code on top gewesen und gut ist, jetzt quäl ich mich durch Klassen, Methodenaufrufe, Parameterübergaben etc. und komme mehr durcheinander als alles andere - aber wie gesagt: wenig Erfahrung und know-how).

Was mich z.B. zur Verzweiflung bringt.. ich habe jetzt in einer Klasse in einer Methode die zufälligen Punktobjekte in Abhängigkeit von Spielereingaben (Spielfeldgröße) erzeugt. Diese wird nun in der main in einer Schleife gebraucht, damit ich die Menüführung haben kann. Die Werte dieser Klasse benötige ich nun in einer anderen Klasse, welche den Spielablauf steuern soll. Der Spielstart wird über die Main in der While-Schleife gschachtelt mit einer switch case Abfrage gestartet. Wenn ich in dieser Abfrage im case ("Spielstart") die Methode Spielablauf aufrufen möchte, muss ich ja was mitgeben.
Java:
case x: spielablauf.spielfeld();
wie ich es drehe und wende, es will nicht. Wäre für mich deutlich leichter, alles in der main zu haben. 🙁
 
Zuletzt bearbeitet:
Wenn Du tatsächlich meinst, dass es einfacher wäre, dann mach es so. Dann ist alles in der main.

Aber hier im Thread hat man ja schon etwas gesehen, dass dies eben nicht leichter ist, denn gerade dann wird es schwer, alles mit den Schleifen und co eben sinnvoll zusammen zu setzen. Aber probiere es einfach weiter aus.

Das mit den Methoden und deren Aufrufen ist etwas, das man nur einmal verstehen muss. Das ist aber etwas, um das Du auch kaum drum herum kommst. Denn Du willst ja z.B. Dinge des Frameworks nutzen. Und da wirst Du Instanzen von diversen Klassen erstellen und darauf dann Methoden aufrufen müssen.
 
Wenn Du tatsächlich meinst, dass es einfacher wäre, dann mach es so. Dann ist alles in der main.
Ne darf ich ja hier nicht.
Ist ja auch egal, muss ich ja nicht diskutieren. Vorgaben sind eben so und damit versuch ich nun klar zu kommmen. Was das angeht
Das mit den Methoden und deren Aufrufen ist etwas, das man nur einmal verstehen muss. Das ist aber etwas, um das Du auch kaum drum herum kommst. Denn Du willst ja z.B. Dinge des Frameworks nutzen. Und da wirst Du Instanzen von diversen Klassen erstellen und darauf dann Methoden aufrufen müssen.
dachte ich eigntl ich hab das geschnallt. Von Klasse 2 nach Klasse 1(main) ist kein Problem. Von Klasse 2 nach Klasse 3 oder Klasse 2 nach 1 und dann an 3 tu ich mich irgendwie schwerer.. 😀 Aber man lernt ja noch!
 
Die Frage ist dabei immer, woran es evtl. scheitert. Wichtig ist natürlich, dass man die Aufteilung richtig hin bekommt. Da ist eine gewisse Übung durchaus nicht unwichtig. Bezüglich der Herangehensweise hat mir damals das Buch "Object thinking" sehr gut gefallen. Vielleicht gibt es das ja in der Fernleihe oder so (Das Buch ist recht alt, kaufen würde ich es mir nicht - es sei denn du findest es extrem preiswert).

Aber ist schon lange her, dass ich es gelesen habe - nicht, dass meine Erinnerung verfälscht ist.
 
Die Frage ist dabei immer, woran es evtl. scheitert. Wichtig ist natürlich, dass man die Aufteilung richtig hin bekommt. Da ist eine gewisse Übung durchaus nicht unwichtig.
Ich vermute mal: Mangelnde Erfahrung, fehlende Übung, fehlendes Know-How, kein Coding-Überflieger, bin noch nicht lange dabei, in kurzer Zeit viel Input sodass ich viel verwechsel und auch das eine oder andere vergesse und Lernen um den Alltag rum ^^ da kommt eins zum anderen.

Mein größtes Problem ist glaube ich aktuell, mit Werten und Ergebnissen einer Klasse/Methode in anderen Klassen/Methoden weiterzuarbeiten. Aber ich fuchs mich nochmal da rein..
 

Neue Themen


Zurück
Oben