Lottozahlen ohne Wiederholung
-
Bin schon die ganze Zeit am Ausprobieren...
wie vergleicht man die bereits gezogene Zahl mit der neuen?
-
Mit einer Funktion. Der übergibst du das array und die Kandidatenzahl und sie liefert ob vorhanden oder nicht.
Sowas nennt man auch Programmstrukturierung.
-
Hallo,
typischer Algorithmus für Lottozahlen ziehen ist:
Array a mit Zahlen 1 bis 49 for i=0 bis 5 { x = rand(49-i) result[i] = a[x]; swap(a[x], a[49-i]); // gezogene Zahl aus dem rand-Bereich raus nehmen }
-
Leider komme ich immer noch nicht weiter... eure Denkanstöße haben mich schon ein kleines Stückchen weitergebracht, aber letztendlich bräuchte ich noch Hilfe.
Die Erstellung einer Funktion gelingt mir nicht.
-
Kürzer wirst du es nicht hinkriegen.
#include <stdio.h> #include <stdlib.h> #include <time.h> enum {MYSIZE=6,MYASIZE=49}; int enthaelt(const int *a,int z) { int i; for(i=0;i<MYSIZE;++i) if(a[i]==z) return 1; return 0; } int main() { int i, x, array[MYSIZE]={0}; srand(time(0)); //Zufallszahlengenerator for(i=0; i<MYSIZE; i++) // Schleife zur Bestimmung der 6 Felder { while( enthaelt(array,x=rand()%MYASIZE+1) ); printf(" %d ",array[i]=x); } return 0; }
-
Vielen Dank! Das ist genau so, wie ich es haben soll.
Könntest du einmal kurz erklären was enum bedeutet?
-
@Luckyingmar sagte in Lottozahlen ohne Wiederholung:
Vielen Dank! Das ist genau so, wie ich es haben soll.
Mag zwar sein, dass dein Lehrer das so akzeptiert, aber wenn du wirklich etwas lernen möchtest, dann arbeite lieber den Vorschlag von Jockelx durch. Warum hat Jockelx das wohl vorgeschlagen? Wo liegen die Vorteile? Wieso ist bei 6 aus 49 die andere Lösung von Wutz auch ganz gut?
-
Ich habe versucht, den Vorschlag von Wutz und Jockelx durchzuarbeiten. Allerdings bin ich nicht weit gekommen. Ich konnte mit den Denkanstößen nicht viel anfangen, ich bin auch noch ziemlich unerfahren in der Thematik.
Ich versuche die Lösung von Wutz an meine Schreibweise anzupassen und diese zu verstehen!
-
Ich möchte nochmal SeppJs Frage zum Vergleich der beiden Lösungen erweitern, vielleicht hilft dir das auch weiter bei der Beantwortung:
Was passiert, wenn ich statt 6 aus 49 ein neues Spiel entwerfe mit
- 6 aus 49000
- 48900 aus 49000
-
also ich würde es so machen:
#define NUMNUMBERS 6 #define NUMBERMIN 1 #define NUMBERMAX 49 int main() { //Deklarationen unsigned int numbers[NUMBNUMBERS]; int i, j; //Schleife zur Bestimmung der Zufallszahlen for(i = 0; i < NUMNUMBERS; i++) { numbers[i] = NUMBERMIN + (rand() % (NUMBERMAX - NUMBERMIN + 1)); //Zufallszahl in [NUMBERMIN, NUMBERMAX] bestimmen for(j = 0; j < i; j++) //Schleife zum Abgleich aller bisherigen Zahlen mit der neuen { if(numbers[j] == numbers[i]) //Bisherige Zahl ist vorhanden { break } } if(numbers[i] == numbers[j]) { i--; //continue bewirkt Sprung ans Schleifenende, d.h. i wird inkrementiert. Um wieder an die gleiche Stelle im Array zu schreiben, wird i daher hier dekrementiert. continue; } } }
-
@Wade1234 : Das ist ja das gleiche wie von Wutz, aber in schlechter lesbar. Da muss man ja erst einmal gründlich nachdenken, was Zeile 25 bezwecken soll und ob das überhaupt legal ist. Der lange Kommentar, der zur Erklärung von vier Zeichen nötig ist, sollte ein Alarmzeichen sein.
Du hast dich übrigens auch prompt gleich mehrmals verschrieben, es funktioniert so nicht. Und damit sind nicht nur Syntaxfehler gemeint. Selbst nach deren Korrektur ist dein Programm eine Endlosschleife.
Als Vorbild daher denkbar schlecht geeignet, aber @Luckyingmar kann sich ja mal daran versuchen, die Fehler zu finden, verstehen, und zu beheben. Daher sage ich auch absichtlich nicht, wo die Fehler liegen. Die meisten sollten für den geübten Leser offensichtlich sein (und falls nicht-offensichtliche Fehler drin sind, kenne ich sie schließlich selber nicht )
-
@SeppJ ich habs nochmal korrigiert und dieses mal auch getestet.
#include <stdlib.h> #define NUMNUMBERS 6 #define NUMBERMIN 1 #define NUMBERMAX 49 int main() { unsigned int numbers[NUMNUMBERS]; int i, j; for(i = 0; i < NUMNUMBERS; i++) { numbers[i] = NUMBERMIN + rand() % (NUMBERMAX - NUMBERMIN + 1); for(j = 0; j < i; j++) { if(numbers[j] == numbers[i]) { i--; continue;; } } } return 0; }
ich glaube, dass ich es vorher auch so (mit den fehlern) geschrieben hatte, aber irgendwie hatte ich dann plötzlich einen einfall oder so. das von wutz halte ich eigentlich für sehr unsauber, also eine zuweisung in printf geht z.b. gar nicht.
-
So ist das auch schon wesentlich verständlicher. Aber die Zeilen 20 und 21 finde ich immer noch fies. Die logische Anforderung "ziehe so lange eine neue Zahl, bis diese nicht in der Liste der schon gezogenen Zahlen ist" lässt sich nahezu 1:1 in richtig feines C hin und zurück übersetzen. Deine Lösung hingegen ergibt sich nicht als direkte Übersetzung der logischen Beschreibung, und die Rückübersetzung ist erst recht verwirrend.
-
@Wade1234 Gibt es eigentlich einen Grund, warum du auf Macros statt Konstanten gegangen bist?
-
@wob sagte in Lottozahlen ohne Wiederholung:
@Wade1234 Gibt es eigentlich einen Grund, warum du auf Macros statt Konstanten gegangen bist?
C89 Kompatibilität? Ginge natürlich auch mit enums, siehe Wutz, aber da die Werte keine Beziehung zueinander haben, ist es ziemlich wurscht. Aber wie in C++ mit
const
ginge es erst ab C99.
-
@Jockelx sagte in Lottozahlen ohne Wiederholung:
Hallo,
typischer Algorithmus für Lottozahlen ziehen ist:
Array a mit Zahlen 1 bis 49 for i=0 bis 5 { x = rand(49-i) result[i] = a[x]; swap(a[x], a[49-i]); // gezogene Zahl aus dem rand-Bereich raus nehmen }
Noch besser ist übrigens einfach nur gezogenen Zahlen ans Ende (oder auch Anfang) des Arrays a zu swappen und das result Array komplett wegzulassen.
-
@Wade1234 Warum ein
continue
?
Beim ersten Match ist die Zahl doppelt und es muss neu gezogen werden.
Wenn mehr als eine Zahl doppelt ist, funktioniert der Algorithmus nicht.
-
@SeppJ also ich habe es jetzt so gemacht:
#include <stdlib.h> #include <time.h> #include <stdio.h> #define NUMNUMBERS 6 #define NUMBERMIN 1 #define NUMBERMAX 49 int main() { unsigned int numbers[NUMNUMBERS]; unsigned int tempnumber; int i, j; srand(time(0)); for(i = 0; i < NUMNUMBERS; i++) { for(;;) { tempnumber = NUMBERMIN + rand() % (NUMBERMAX - NUMBERMIN + 1); for(j = 0; j < i; j++) { if(tempnumber == numbers[j]) { break; } } if(j == i) { numbers[i] = tempnumber; printf("%u\n", numbers[i]); break; } } } printf("\n"); return 0; }
@wob ehrlich gesagt habe ich das irgendwann einfach so gelernt. enums verwendet man / ich bei fortlaufenden konstanten, weil da unkompliziert weitere konstanten eingefügt werden können.
@DirkB ja den gedanken, dass nur die innere schleife erneut durchlaufen wird, hatte ich auch und deshalb habe ich da oben auch dieses komische programm zusammengefrickelt.
-
@TGGC sagte in Lottozahlen ohne Wiederholung:
Noch besser ist übrigens einfach nur gezogenen Zahlen ans Ende (oder auch Anfang) des Arrays a zu swappen und das result Array komplett wegzulassen.
Oh ja, das stimmt allerdings.
-
Endlosschleifen mit
if ... break
als Kontrollelement. Benutzung von Zählvariablen nach Abschluss einer Schleife. Findest du das wirklich gut? Vielleicht solltest du noch einmal Abstand nehmen und nicht versuchen, deinen jetzigen Ansatz zu reparieren, sondern in Ruhe einen schönen Ansatz zu finden.Dein Programm besteht derzeit aus einer Reihe von Fehlerkorrekturalgorithmen für den jeweils davor liegenden Algorithmus. Zerlege das Problem in kleinere Unterprobleme, und finde einfache, korrekte Lösungen für diese Probleme. Dann setz diese Lösungen zusammen. Wutzs Programm hat nicht deshalb 10 Zeilen, weil er Zuweisungen in Funktionsaufrufen macht (ok, ein bisschen trägt das schon bei, aber nicht alles), sondern weil er effiziente Teillösungen effizient zusammen gebaut hat.