• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[C#] Mehrdimensionales Array mit Zufallsauswahl

Hector

Board-Paladin

Registriert
16 Juli 2013
Beiträge
4.383
Moin.. auch mal ne blöde Frage, die wahrscheinlich mit einem "Meine Fresse, bin ich blöd!" endet....

Das, was ich will geht wahrscheinlich vieeel einfacher, aber dennoch wüsste ich gerne, wieso mein Ansatz nicht funktioniert.
Ich habe ein Fenster mit 5 Images, die Gegner darstellen sollen. Per Knopfdruck sollen diese nun zufällig neu über dem Formular verteilt werden.
Die Möglichen Positionen verwalte ich jeweils für die X und Y- Koordinate in einem Array, daraus wird zufällig je ein X und Y Wert gewählt und in einem mehrdimensionalen Array gespeichert, um diese Werte später zuzuweisen (Das ist der Punkt, der vermutlich um Welten einfacher geht, aber seis drum..^^)

Das ganze mache ich mit einer Schleife 5x, damit ich für jeden "Gegner" am Ende einen Wert ala "250,600" erhalte, womit dieser auf dem Fenster platziert werden kann.
Wenn ich mit dem Debugger wirklich bis zum Ende durchgehe, kann ich wunderbar erkennen, wie das mehrdimensionale Array mit den Werten gefüllt wird. Das passt also alles

Wenn dann jedoch die Gegner platziert werden, kommt es zu 2 Problemen:
1. Sie stehen alle auf der gleichen Position (obwohl jeder einen anderen Wert aus dem Array zugewiesen bekommt, die unterschiedlich sind!)
2. Das Muster wiederholt sich sehr auffällig, es scheint, als würde die Platzierung nur in einem bestimmten Bereich des Fensters stattfinden, obwohl die Werte eigentlich jeden möglichen Punkt ansprechen...

Naja hier mal der Code:

[src=csharp]
public void setEnemies()
{

//Mögliche Koordinaten und mehrdimensionales Array
int[] enemyPosX = new int[] { 0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750 };
int[] enemyPosY = new int[] { 0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500 };
int[,] savedPos = new int[5, 2];


//Schleifen zur Auswahl von 5 zufälligen X und Y Werten und befüllen des mehrdim. Arrays
int n = 1;
int posx = 0;


while (n < 6)
{

Random enemyRndX = new Random();
int ix = enemyRndX.Next(0, 15);

savedPos[posx, 0] = enemyPosX[ix];
posx++;

n++;
}


posx = 0;


n = 1;

while (n < 6)
{
Random enemyRndY = new Random();
int iy = enemyRndY.Next(0, 10);

savedPos[posx, 1] = enemyPosY[iy];
posx++;

n++;

}


//Gegner anhand der ermittelten Positionen verteilen:
sprEnemy1.Location = new Point(savedPos[0, 0], savedPos[0, 1]);
sprEnemy2.Location = new Point(savedPos[1, 0], savedPos[1, 1]);
sprEnemy3.Location = new Point(savedPos[2, 0], savedPos[2, 1]);
sprEnemy4.Location = new Point(savedPos[3, 0], savedPos[3, 1]);
sprEnemy5.Location = new Point(savedPos[4, 0], savedPos[4, 1]);


}



[/src]


Bis zum Punkt "Gegner anhand der ermittelten Positionen verteilen:" stimmt anhand des Debuggers wirklich jeder Wert....Wenn ich mir hier den Inhalt des mehrdim. Arrays ausgeben lasse, passt alles. Wieso die Dinger dann alle auf dem gleichen Platz, und dann noch so eingeschränkt sitzen....keine Ahnung... :unknown:

Weiß jemand Bescheid?
 

evillive

EXIL

Registriert
24 Juli 2013
Beiträge
930
ich würde folgendes

Random enemyRndX = new Random();

mal außerhalb der Schleife positionieren
 

Hector

Board-Paladin

Registriert
16 Juli 2013
Beiträge
4.383
  • Thread Starter Thread Starter
  • #3
Yay, das klappt :D
Danke. Nun hängen sie nicht mehr alle auf dem gleichen Fleck rum :D

Aber die "Verteilung" auf dem Fenster ist immer noch recht eintönig..... die gammeln alle mehr oder weniger in der Mitte rum...
Denke mal, hier ist wahrsch. die rnd-Funktion schuld weil nicht wirklich "zufall" halt... da muss ich bessere Werte erwischen, scheints....

Edit: Für mehr randomisierung tuts der gute alte Unix-Timestamp. Alles schön verteilt nun :D
 
Zuletzt bearbeitet:

accC

gesperrt

Registriert
14 Juli 2013
Beiträge
5.250
Es gibt in vielen Sprachen verschiedene Random-Funktionen. Die einen erzeugen einen billigen Pseudozufallswert, die anderen erzeugen kryptographisch bessere Zufallswerte.
Wie das bei C# ist, weiß ich nicht auswendig, aber du kannst ja mal nachschauen.
 

Mr_J

Neu angemeldet

Registriert
14 Juli 2013
Beiträge
991
Dein Ansatz wirkt sehr sehr kompliziert. Warum nicht eine einzelne Schleife bauen die Folgendes macht:
- Random mit Range 0 bis 10 multipliziert mit 50 ergibt posX
- das Gleiche für posY
- das verpackt man in eine Whileschleife die prüft ob die Position auf der Karte (darstellbar mit einem 2d Array 10x10 Werte) bereits belegt ist und die Position besetz wenn sie frei ist
- außerdem wird bei Erfolg ein Counter hochgezählt, der die Abbruchbedingung für die Whileschleife darstellt, erreicht dieser 5 bricht die Schleife ab

MfG
Mr. J
 

Hector

Board-Paladin

Registriert
16 Juli 2013
Beiträge
4.383
  • Thread Starter Thread Starter
  • #6
@Mr_J:
Ja, das klingt einfacher :D
Naja, verrenne mich dabei oft in irgendwelche Lösungen, die sich mit etwas Abstand dann aber als seltsam herausstellen..^^
Ich bau mal anhand deiner Empfehlung ein bisschen dran rum, wenn der Rest fertig ist... im Moment bin ich froh, dass es einigermaßen läuft.. "Optimierung" dann am Ende...
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.507
Dein Ansatz wirkt sehr sehr kompliziert. Warum nicht eine einzelne Schleife bauen die Folgendes macht:
- Random mit Range 0 bis 10 multipliziert mit 50 ergibt posX
- das Gleiche für posY
- das verpackt man in eine Whileschleife die prüft ob die Position auf der Karte (darstellbar mit einem 2d Array 10x10 Werte) bereits belegt ist und die Position besetz wenn sie frei ist
Persönlich würde ich das Vorgehen vermeiden, da allgemein nicht ausgeschlossen werden kann, dass beliebig oft eine Zahl mit belegtem Feld erzeugt wird.
Ich schlage alterantiv folgendes vor:

Array validPositions[länge];
Für i=1 bis anzahlZuBesetzenderPositionen mache
{
Generiere Zufallszahl k aus dem Bereich [0,länge];
wähle newPos = validPositions[k] als neue Gegnerposition;
entferne newPos aus validPositions;
länge = validPositions.länge;
}

Auf diese Weise ist jede Wahl einer Zufallsfahl zu dem Zeitpunkt gültig, also noch nicht belegt so das auf jeden fall genau "anzahlZuBesetzenderPositionen"-mal durch die Schleife gelaufen wird.
 
Zuletzt bearbeitet:

Mr_J

Neu angemeldet

Registriert
14 Juli 2013
Beiträge
991
Um eine Endlosschleife zwingend zu erhalten muss man mehr Werte anfordern als Felder frei sind, allerdings ist es nicht besonders schwer noch ein Abbruchkriterium zu definieren. Zweiten Counter einbauen der bei jedem Durchlauf hochzählt und bei Erreichen von 100 oder so nen Break macht.

MfG
Mr. J
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.507
Das ist klar.
Ich wollte nur als Option anregen, dass per se die generierte Zahl verwendbar ist, statt sie nach der Generierung darauf zu prüfen.
Die Begründung ist, dass in zweiterem Fall unbekannt ist, wie oft die while Schleife durchlaufen werden muss.

Aber die "Verteilung" auf dem Fenster ist immer noch recht eintönig..... die gammeln alle mehr oder weniger in der Mitte rum...
Das ist seltsam. Ein Zufallsgenerator sollte gleichverteilte Zahlen liefern.

Ist dir klar, warum "Random enemyRndX = new Random();" außerhalb der Schleife gehört?

Edit: Für mehr randomisierung tuts der gute alte Unix-Timestamp. Alles schön verteilt nun
Bin nicht vertraut mit C#, würde mich aus prinzip interessieren was das problem war.
 

CroneKorkN

★ ☆ ☆ ☆ ☆

Registriert
6 Aug. 2014
Beiträge
289
Ort
0176 323 223 71
Da bei Random.Next() der obere Grenzwert außerhalb des möglichen Bereiches liegt, müsste es "(0,16)" heißen.
[src=csharp]
int ix = enemyRndX.Next(0, 16);
[/src]
Darüber bin ich bei Google gestolpert, habe aber selbst noch keine Zeile c# Code geschrieben. Von daher würde mich interessieren, warum der Zufallsgenerator außerhalb der Schleife initiert werden muss. Aus der Bennennung der Funktion ".Next" könnte man Ableiten, dass die Zufallszahlen voneinander abhängen. Beim Initialisieren also immer die selbe Entropie verwendet wird und man Somit insgesamt nur eine Instanz von Random existieren darf.
 
Zuletzt bearbeitet:

evillive

EXIL

Registriert
24 Juli 2013
Beiträge
930
Kurz: Es gibt eine Folge von Zufallszahlen, die zufällig erzeugt wurde. Wenn du nun

[src=csharp]Random enemyRndX = new Random();[/src]

aufrufst, dann holst du dir diese Folge. Wenn du das mehrmals machst dann beginnst du immer mit der ersten Zahl aus dieser Folge.

BurnerR seine Lösung ist sehr gut. Stell dir einen Topf mit Lottozahlen vor. Zunächst kommen dort die alle Kugeln rein. Dann wählst du zufällig immer eine Kugel aus, die du aus dem Topf herausholst. ... auf diese Weise ersparst du dir die Prüfung, ob du eine Zahl bereits hattest oder nicht und wenn genug Kugeln im Topf sind, dann hat man keine Endlosschleife. Stell dir vor du hast Zahlen von 1 bis 10. Du brauchst nun 9 Zahlen und keine darf doppelt vorkommen.
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.507
Vielleicht noch etwas konkreter: Solche Funktionen liefern typischerweise gleichverteilte Zahlenfolgen, abhängig von einem eingangsparameter. Zweiter Aufruf mit selbem Eingangsparameter = selbe Zahlenfolge.
Wenn der Eingangsparameter nun z.B. CPU Temperatur * Uhrzeit in Millisekunden ist haben sich beide Werte womöglich von einem Schleifendurchlauf zum nächsten gar nicht geändert, sprich man hat dann öfters mal doppelte Zahlen.
Dazu stellt sich die Frage ob die jeweils ersten Werte so einer Funktion bei varriierendem Eingangsparameter zusammen dann zwangsläufig gleichverteilt sind.
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
[src=csharp] public int MachZufallsZahl(int min, int max)
{
RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
// Ein Integer bedeutet 4 Byte
byte[] zufall = new byte[4];
rngCryptoServiceProvider.GetBytes(zufall);
int ergebnis = Math.Abs(BitConverter.ToInt32(zufall, 0));
return ergebnis % max + min;
}[/src]
 
Oben