# Lottoziehung mithilfe einer Liste



## user1234569 (22. Jan 2019)

Hallo! Für die Klausurvorbereitung mache ich grade ein paar Aufgaben und eine lautet wie folgt: "Implementieren Sie die Ziehung der Lottozahlen (6 aus 49) mit Hilfe einer Liste! Die Liste soll aus den Zahlen von 1 bis 49 bestehen. Wenn eine Zahl gezogen wurde, soll sie aus der Liste ausgekettet werden." - dabei ist die Verwendung der Collection-Klassen untersagt.

Nach ewig langem Hin und Her habe ich jetzt auch eine Lösung, die auf den ersten Blick gut aussah - sich auf den zweiten allerdings als falsch herausstellte - irgendwie werden manchmal 5 oder auch 7 Zahlen "gezogen" und das sind dann auch noch andere als meine Math.random() Methode erstellt hat. Hier ist mein Code: (Pastebin Link: https://pastebin.com/cuq3QYaF)

```
public class Aufg1LottoZahl {
    int zahl;
    Aufg1LottoZahl next;
    Aufg1LottoZahl prev;
 
    public Aufg1LottoZahl(int zahl) {
        this.zahl = zahl;
    }
 
    public Aufg1LottoZahl() {
        this.zahl = -1;
    }
 
    public int getZahl() {
        return zahl;
    }
 
    public void setNext(Aufg1LottoZahl next) {
        this.next = next;
    }
 
    public Aufg1LottoZahl getNext()  {
        return next;
    }
    public void setPrev(Aufg1LottoZahl next) {
        this.next = next;
    }
 
    public Aufg1LottoZahl getPrev()  {
        return next;
    }
}
```


```
public class Aufg1LottoMain {
    public static void main(String[] args) {
        Aufg1LottoZahl[] lottozahlen = new Aufg1LottoZahl[49];
        for (int i = 0; i < lottozahlen.length; i++) {
            lottozahlen[I] = new Aufg1LottoZahl(i + 1);
            if (i > 0 && i < 48) {
                lottozahlen[I].setNext(lottozahlen[i + 1]);
                lottozahlen[I].setPrev(lottozahlen[i - 1]);
            }
            else if (i == 48) {
                lottozahlen[I].setNext(lottozahlen[0]);
                lottozahlen[I].setPrev(lottozahlen[i - 1]);
            }
            else if (i == 0) {
                lottozahlen[I].setPrev(lottozahlen[48]);
                lottozahlen[I].setNext(lottozahlen[i + 1]);
            }
        }
        ziehung(lottozahlen);
    }
  
    public static void ziehung(Aufg1LottoZahl[] lottozahlen) {
        int randomZahl;
        for (int i = 0; i < 6; i++) {
            randomZahl = (int) (Math.random() * 49);
            while (lottozahlen[randomZahl].getNext() == null && lottozahlen[randomZahl].getPrev() == null) {
                randomZahl = (int) (Math.random() * 49);
            }
            System.out.print(randomZahl + "  "); //Ausgabe der 6 erstellten Random Zahlen zum Abgleich mit den eigentlichen 6 Zahlen
            (lottozahlen[randomZahl].getPrev()).setNext(lottozahlen[randomZahl].getNext());
            (lottozahlen[randomZahl].getNext()).setPrev(lottozahlen[randomZahl].getPrev());
            lottozahlen[randomZahl].setNext(null);
            lottozahlen[randomZahl].setPrev(null);
        }
        System.out.println();
        for (int i = 0; i < 49; i++) {
            if (lottozahlen[I].getNext() == null && lottozahlen[I].getPrev() == null) {
                System.out.print(lottozahlen[I].getZahl() + "  ");
            }
        }
    }
}
```


----------



## Robat (22. Jan 2019)

Gibt es dazu auch eine Frage?


----------



## user1234569 (22. Jan 2019)

Robat hat gesagt.:


> Gibt es dazu auch eine Frage?


DIe Frage ist warum funktioniert mein Code nicht/was mache ich falsch? Warum werden manchmal 5,6 oder 7 Zahlen gezogen und warum sind diese dann komplett andere als die durch die Math.random() Funktion erstellten


----------



## Robat (22. Jan 2019)

Ich würde sagen, es ist eher Zufall, dass dein Programm funktioniert.
Suche hier mal die 2 Fehler. 

```
public void setPrev(Aufg1LottoZahl next) {
        this.next = next;
    }
 
    public Aufg1LottoZahl getPrev()  {
        return next;
    }
```
Wenn du die Fehler verbessert hast, sollten dir die Exceptions nur so um die Ohren fliegen


----------



## user1234569 (22. Jan 2019)

Super danke das war wirklich ein dummer Fehler, sowas kommt davon wenn man einfach die Getter und Setter von Next kopiert und für Prev einfügt haha! Habe das jetzt korrigiert und zusätzlich noch den Code in der Main Methode geändert und aus der einen for Schleife zwei gemacht; siehe hier:

```
public static void main(String[] args) {
        Aufg1LottoZahl[] lottozahlen = new Aufg1LottoZahl[49];
        for (int i = 0; i < lottozahlen.length; i++) {
            lottozahlen[i] = new Aufg1LottoZahl(i + 1);
        }
        for (int i = 0; i < lottozahlen.length; i++) {
            if (i > 0 && i < 48) {
                lottozahlen[i].setNext(lottozahlen[i + 1]);
                lottozahlen[i].setPrev(lottozahlen[i - 1]);
            }
            else if (i == 48) {
                lottozahlen[i].setNext(lottozahlen[0]);
                lottozahlen[i].setPrev(lottozahlen[i - 1]);
            }
            else if (i == 0) {
                lottozahlen[i].setPrev(lottozahlen[48]);
                lottozahlen[i].setNext(lottozahlen[i + 1]);
            }
        }
        ziehung(lottozahlen);
    }
```

Jetzt habe ich auch immer nur genau 6 Zahlen - das passt also soweit! Allerdings sind die ausgegebenen Random Zahlen immer noch unterschiedlich zu den ausgegeben "ausgeketteten" (also quasi gezogenen) Zahlen. Warum?


----------



## user1234569 (22. Jan 2019)

user1234569 hat gesagt.:


> Allerdings sind die ausgegebenen Random Zahlen immer noch unterschiedlich zu den ausgegeben "ausgeketteten" (also quasi gezogenen) Zahlen. Warum?


Okay hat sich auch geklärt! Die Zahlen sehen nur auf den ersten Blick unterschiedlich aus - auf den zweiten fällt auf, dass sie nur sortiert werden und +1 addiert wird (da es ja Zahlen von 1-49 sind; in der Math.random() Funktion aber Zahlen von 0-48).
Danke nochmal für die Hilfe!


----------



## mihe7 (23. Jan 2019)

@user1234569 Du arbeitest ausschließlich mit einem Array, in dem Elemente einer verketteten Liste stecken. Die ganze Logik fußt auf dem Array und nebenher passt Du (weil es halt gefordert ist) noch die internen Verkettungen der "Liste" an. 

Ich denke nicht, dass das Sinn der Aufgabe ist:
a) Du übergibst an ziehung() ein Array und keine Liste
b) die Elemente einer verketteten Liste sind ein Implementierungsdetail, auf das du von außen keinen Zugriff hast oder haben solltest. 

Davon einmal abgesehen brauchst Du keine doppelt verkettete Liste. 

Neue Herausforderung: wie sieht die Lösung aus, wenn Du auf Arrays vollständig verzichtest?


----------



## Robat (23. Jan 2019)

mihe7 hat gesagt.:


> wie sieht die Lösung aus, wenn Du auf Arrays vollständig verzichtest?


Schöner


----------



## mihe7 (23. Jan 2019)

@Robat volle Punktzahl.


----------



## user1234569 (25. Jan 2019)

mihe7 hat gesagt.:


> @user1234569 Du arbeitest ausschließlich mit einem Array, in dem Elemente einer verketteten Liste stecken. Die ganze Logik fußt auf dem Array und nebenher passt Du (weil es halt gefordert ist) noch die internen Verkettungen der "Liste" an.
> 
> Ich denke nicht, dass das Sinn der Aufgabe ist:
> a) Du übergibst an ziehung() ein Array und keine Liste
> ...


Das hat mir mein Prof auch gesagt haha, ich arbeite derzeit an einer solchen Lösung


----------



## user1234569 (25. Jan 2019)

--


----------



## mihe7 (25. Jan 2019)

user1234569 hat gesagt.:


> arbeite derzeit an einer solchen Lösung


Wir sind schon gespannt.


----------



## user1234569 (26. Jan 2019)

mihe7 hat gesagt.:


> Wir sind schon gespannt.


Ich komme einfach nicht drauf. Habe jetzt die LottoZahl Klasse minimal abgeändert sodass es eine einfach verkettete Liste wird siehe hier:

```
public class LottoZahl {
    int zahl;
    LottoZahl next;
  
    public LottoZahl(int zahl) {
        this.zahl = zahl;
    }
  
    public void setZahl(int zahl) {
        this.zahl = zahl;
    }
    public int getZahl() {
        return zahl;
    }
  
    public void setNext(LottoZahl next) {
        this.next = next;
    }
    public LottoZahl getNext() {
        return next;
    }
}
```
Die Main Klasse habe ich nahezu komplett geändert; die Ziehung findet in einem Array statt. Dann wird jedes Listen Element auf Gleichheit mit einem der Array Werte überprüft und falls es gleich ist wird es (in der Theorie) aus der Liste ausgekettet.
Am Ende wird die Liste ohne ausgekettete Elemente ausgegeben.
Allerdings scheint er bei mir nicht die Elemente auszuketten, denn es werden einfach alle Zahlen von 1-49 ausgegeben.

```
public class LottoListe {
    public static void main(String[] args) {
       //Erstellen der Liste mit den 49 verketteten Elementen
        LottoZahl start = null;
        start = new LottoZahl(1);
        LottoZahl temp = start;
        for (int i = 1; i < 49; i++) {
            LottoZahl k = new LottoZahl(i + 1);
            temp.setNext(k);
            temp = k;
        }
        //Würfeln der 6 random Zahlen
        int[] randomZahlen = new int[6];
        for (int i = 0; i < 6; i++) {
            randomZahlen[i] = (int) (Math.random() * 49 + 1);
            if (i == 0);
            else {
                for (int j = 0; j < i; j++) {
                    while (randomZahlen[i] == randomZahlen[j]) {
                        randomZahlen[i] = (int) (Math.random() * 49 + 1);
                    }
                }
            }
        }
      //gezogene Zahlen ausklinken
        LottoZahl durchlaufen = start;
        while (durchlaufen != null) {
            for (int i = 0; i < 6; i++) {
                if (durchlaufen.getZahl() == randomZahlen[i]) {
                    //dann klinke diese Zahl aus
                    LottoZahl zuloeschen = durchlaufen;
                    LottoZahl einsvorloeschen = start;
                    while (einsvorloeschen.getNext() != zuloeschen) {
                        einsvorloeschen = einsvorloeschen.getNext();
                    }
                    einsvorloeschen.setNext(zuloeschen.getNext());
                    zuloeschen.setNext(null);
                }
            }
            durchlaufen = durchlaufen.getNext();
        }
       //Ausgabe aller Listenelemente
        LottoZahl ausgeben = start;
        while (ausgeben != null)   {
            System.out.print(ausgeben.getZahl() + " ");
            ausgeben = ausgeben.getNext();
        }
//Ausgabe der 6 gezogenen Zahlen (optional)
//        System.out.println();
//        for (int i = 0; i < 6; i++) {
//            System.out.print(randomZahlen[i] + " ");
//        }
    }
}
```


----------



## mihe7 (26. Jan 2019)

user1234569 hat gesagt.:


> die Ziehung findet in einem Array statt.


Kein Array verwenden. Deine Klasse LottoZahl stellt ein Element der Liste dar. Die Listen-Semantik (size, get, remove, ...) musst Du natürlich schon noch irgendwie implementieren. Der Ziehungs-Algorithmus ist dann trivial:

```
wiederhole 6 mal
    n := Zufallszahl zwischen 0 und size (excl.)
    gib n-tes Element aus Liste aus
    entferne n-tes Element aus Liste
```


----------



## temi (26. Jan 2019)

Das ganz erscheint mir nicht sehr logisch. Deine Klasse "LottoZahl" ist in Wirklichkeit keine einzelne Zahl (wie der Name der Klasse suggeriert) sondern eine Art Liste. Eine Klasse "LottoZahl" müsste eigentlich ungefähr so aussehen:

```
public class Lottozahl {
    private int value;

    public Lottozahl(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}
```

Dann solltest du dir auf jeden Fall einmal anschauen, welche Methoden eine Liste haben sollte und einen Teil davon (size, add, get, remove) implementieren.


```
public class LottozahlenListe {

    public void add(Lottozahl zahl) {
        // ...
    }

   // usw...
}
```

Diese Klassen kannst du dann in der Main verwenden.

Edit: Die oben beschriebene Klasse "Lottozahl" ist natürlich so trivial, dass man auf sie verzichten kann und gleich "int" nimmt. Deine Klasse "LottoZahl" entspricht damit der Listenklasse, nur solltest du das "setNext" und "getNext" weglassen und in den Methoden "add", "remove" usw. kapseln. Und den Namen solltest du auch anpassen.


----------



## mihe7 (26. Jan 2019)

@temi seine Aufgabe besteht darin, eine verkettete Liste zu verwenden


----------



## temi (26. Jan 2019)

mihe7 hat gesagt.:


> @temi seine Aufgabe besteht darin, eine verkettete Liste zu verwenden


Schon klar. Ich wollte nur auf die ungünstig benannten Klassen hinweisen, denn seine Klasse "LottoZahl" ist keine einzelne Zahl, sondern eine Art von Liste, während die Klassse "LottoListe" keine Liste ist, sondern das Hauptprogramm.

Vermutlich habe ich jetzt erreicht, dass der TO komplett verwirrt ist


----------



## Rah2k (26. Jan 2019)

Also bei verketten Listen machen ich mir immer 2 Klassen: "Node" und "List". Node enthält eben alle benötigten Attribute während List Methoden zur Listen-Erstellung enthält. Damit bin ich immer ganz gut klar gekommen


----------



## mihe7 (26. Jan 2019)

temi hat gesagt.:


> Vermutlich habe ich jetzt erreicht, dass der TO komplett verwirrt ist


Das schadet gar nix


----------



## mihe7 (26. Jan 2019)

Rah2k hat gesagt.:


> Also bei verketten Listen machen ich mir immer 2 Klassen


Du brauchst dafür auch zwei Klassen. Was bei Dir Node ist, ist bei ihm Lottozahl und Deine List-Klasse fehlt ihm komplett. Dagegen heißt seine Main-Klasse LottozahlenListe. Anders formuliert: nimmt man an, dass seine Klasse Lottozahl Dein Node ist und weiter, dass LottozahlenListe die List sein soll, dann fehlt seiner Main-Klasse die List-Semantik.


----------



## Xyz1 (26. Jan 2019)

mihe7 hat gesagt.:


> Das schadet gar nix


Und die Steigerung wäre, das verschlimmert es nicht.


----------

