Zufälliges "Mischen" mittels eines Arrays

smallone

Mitglied
Hallo Programmierer,

ich möchte ein Windowsprogramm schreiben, das dem Benutzer 36 verschiedene *.wav - Files jeweils genau einmal über die Soundkarte vorspielt und eine Bewertung der Lautstärkeempfindung vom Benutzer abfragt und in einem Textfile speichert.

Ich habe eine MFC-Anwendung mit Visual C++ 6.0 begonnen, aber ein paar Probleme damit:

Mein Ansatz für die nur einmalige zufällige Darbietung ist folgender:

Code:
// Array zum Auswählen der Signale mit srand() und zum Speichern des "schon gespielt-Flags 

int Signals[36] = { 0,1,2,3,4,5,..... usw. 35};

Dieses Array habe ich als globale Variable direkt unter die Includes meiner ...Dlg.cpp geschrieben, um bei jedem erneuten Aufruf der Funktion "Play" die Flags beizubehalten. (nach erfolgter Eingabe der Lautstärkeempfindung soll der Benutzer den Button "Play" drücken)

Leider kennt die folgende Funktion "Play" die Variable Signals[] nicht mehr:


Code:
int CDialogeDlg::Play()
{
	int Zufall;

	do	// solange Zufallszahlen produzieren
	{	srand( time(NULL) );       // Initialisiert Zufallszahl Generator 
		Zufall = rand()%36;
	}
	while (Signals[Zufall] == 99); // bis ein Arrayeintrag kommt, der noch nicht war 
	
	int SignalsInhalt = Signals[Zufall];    // Array Signals auslesen

	switch( SignalsInhalt)
	{
    	    case 0 :
 	    {
	         PlaySound("D:\\ ... .wav ... NULL, SND_FILENAME);	
	         Signals[0] = 99;            // nach einmaligem abspielen auf 99 setzen
                              // der Wert 99 ist mein Flag als Zeichen, daß der Arrayeintrag schon gespielt wurde.
	    }
	break;

	case 1 : .... usw.



Habt ihr eine Idee, wo oder wie ich das Array Signals defenieren oder initialisieren muß, damit es in der ganzen Anwendung bekannt und zugänglich ist ?

Über eure Hilfe würde ich mich sehr freuen, bin gespannt auf intelligentere Ansätze als meinen eigenen ;-)

Ich habe bei den MFC noch nicht verstanden, welche Klasse während der "Lebensdauer" der Anwendung unverändert existent bleibt. Denn dort müßte ich doch eigentlich das Array einmal initialisieren können um von allen Funktionsaufrufen (z.B. nach einem Buttenclick) darauf zugreifen zu können.

Vielen Dank
Grüße, BEN
 
Zuletzt bearbeitet:
Du kannst die Variable über:

extern int Signals[36];

bekannt machen.

Andere Möglichkeit du definierst das Array als statische Variable in deienem Dialog.
Dann kann man über CDialogeDlg::Signals drauf zugreifen.
 
Hey, klasse!

die Definition "extern" hat mein Problem gelöst, vielen Dank !

Wobei die Lösung über "CDialogeDlg::Signals" sicherlich schönerer C++ Stil ist ;-)

Gruß BEN
 
Ich habe noch zwei Vorschläge zum Mischen einer Liste usw. Vielleicht sind sie nützlich für dich.

1. Du könntest die Einträge in eine std::list packen (sozusagen eine Playlist). Noch zu spielende Titel werden hinten angehängt, bereits gespielte vorne gelöscht.

2. Egal, ob du ein Array verwendest oder eine std::list, könntest du std::random_shuffle() verwenden, um die Liste zu mischen. Das würde im Fall des Arrays so aussehen:
Code:
#include <algorithm>

//...

int Signals[36] = { 0,1,2,3,4,5,..... usw. 35};

//...

std::random_shuffle( Signals, Signals + 36 );

// fertig
 
Hallo !

std::random_shuffle( Signals, Signals + 36 );

von der shuffle - Funktion hatte ich vorher schon bei der Lösungssuche was gelesen.

Leider ist die Shuffle-Funktion nicht so ohne weiteres mit einem eigenen Anfangswert (Seed heißt das glaube ich) initialisierbar, um "echte" Zufälligkeit zu erhalten.

Daher habe ich die umständlichere Array-Lösung gewählt, die sich bei 36 Einträgen als zu langsam herausstellt (do - while-schleife, bis endlich der letzte noch nicht vorgekommene Eintrag "zufällig" gewählt wird)


Kennt jemand einen Work-Arround für die Shuffle-Funktion, damit sie "echt zufällig" wird ?
(ich brauche bei jedem Programmstart eine neue, echt zufällige Reihenfolge)

Ansonsten ist mein Programm fast fertig, dank eurer Hilfe !
 
Hallo,

nach einiger Suche bin ich auf einer wie ich finde recht guten Seite fündig geworden, wie man der random_shuffle() einen dritten Parameter übergeben kann:
http://cplus.kompf.de/artikel/functors.html


Ziel ist, laut dem Tutorial, folgendes:
Code:
RandomNumber rnd;
random_shuffle( Signals, Signals + 36 , rnd);



Nun habe ich versucht, mit dem Klassenassistenten eine entsprechende RandomNumber - Klasse anzulegen:

RandomNumber.h sieht folgendermaßen aus:
Code:
#include <cstdlib>
#include <ctime>

class CRandomNumber  
{
public:
	CRandomNumber() { 
		srand(time(0)) ;
	}

	 int operator() ( int n) {
        return (int)(n * rand()/(RAND_MAX+1.0));
    }
	
	virtual ~CRandomNumber();

};


RandomNumber.cpp so:
Code:
CRandomNumber::CRandomNumber()
{

}

CRandomNumber::~CRandomNumber()
{

}


Ich erhalte folgende Fehlermeldung :

D:\\RandomNumber.cpp(20) : error C2084: Funktion '__thiscall CRandomNumber::CRandomNumber(void)' hat bereits einen Funktionsrumpf


ich bin daran gescheitert, den Konstruktor in der *.cpp vernünftig zu initialisieren, daran wirds wohl liegen. Aber ich habe keine Ahnung, wie ich das machen soll.
 
Der Konstruktor hat seinen Funktionsrumpf ja bereits in der Klassendefiniton, deshalb ist es falsch, die Funktion in der *.cpp erneut zu definieren. Den leeren Destruktor kannst du auch weglassen, wenn du nicht vorhast, von deiner Klasse Kindklassen zu entwerfen. Und dann wäre er auch nur wegen des "virtual" wichtig.

Mein Vorschlag:
Code:
class CRandomNumber  
{
public:
  CRandomNumber()
  { 
    srand(time(0)) ;
  }

  int operator() ( int n ) const
  {
    return (int)(n * rand()/(RAND_MAX+1.0)); // <-- Keine Ahnung, ob das stimmt
  }
};
Die *.cpp kannst du auch ganz weglassen, wenn da sonst nichts drinsteht.
 
Perfekt,

nun kann ich mit

Code:
#include <algorithm>

extern int Signals[36] = { ...Werte... };
	
      CRandomNumber rnd;
      std::random_shuffle( Signals, Signals + 36, rnd);

und deiner CRandomNumber.h

mein Array super schnell beim Programmstart mischen !

Vielen Dank für die wertvolle Hilfe, Kachelator !

Grüsse,
BEN
 
Zurück