Archief - C# random niet echt random

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

Hell

Legacy Member
ik ben een yahtzee spel aan het schrijven en ben bijna klaar.
Wat ik alleen raar vind is dat mijn dobbelstenen altijd van 6 naar 1 gaan.
De 2de worp is ALTIJD 1 of 2 kleiner dan de voorgaande worp.
En als het op 1 komt, dan is de volgende vaak 6 of 5...

de code is:
Code:
Random gooi = new Random();
Ogen = gooi.Next(1,7);

Ik weet dat 2de parameter MaxValue is en normaal 6 moet zijn, maar 6 kwam nooit op scherm dus heb ik 7 gemaakt. Dat even terzijde...

Met die Random zou het normaal toch willekeurige waarden moeten nemen ipv een soort van aftelling...

iemand enig idee ?

Tyfius

Legacy Member
Ja en neen. Software matige random's zijn nooit echt random. Daar zit altijd min of meer een soort sequentie achter die wel te achterhalen is. Wat je kan doen om iets meer random te zijn is telkens een nieuwe instantie aanmaken in plaats van telkens dezelfde te gebruiken.
Code:
Ogen = new Random().Next(1, 7);
Eventueel kan je zelf nog een seed genereren aan de hand van een guid.

Als alternatief kan je ook beroep doen op de RNGCryptoServiceProvider klasse, maar dat lijkt mij veel te veel overkill en die is ook redelijk traag ten opzichte van de gewone Random klasse.

De reden dat je 7 moet ingeven is omdat de MaxValue niet in de range wordt opgenomen. (Is dat wiskundig niet iets als [1,7[ ?) Dat staat nochtans vermeld op de documentatie pagina van Next.

Krueger

Legacy Member
Ik heb ook ff wat ge-experimenteer, en wat ik merk is het volgende:

volgende code heeft absoluut geen random resultaten:
Code:
for (int i = 0; i < 100; i++)
{
    Random gooi = new Random();
    var Ogen = gooi.Next(1, 7);
    Console.WriteLine(Ogen);
}
Dan kan het zijn dat ik 100 keer 3 heb als resultaat.

De volgende code doet het al veel beter:
Code:
for (int i = 0; i < 100; i++)
{
    Random gooi = new Random();
    System.Threading.Thread.Sleep(10);
    var Ogen = gooi.Next(1, 7);
    Console.WriteLine(Ogen);
}

Dus ik vermoed dat er in het random algoritme een tijdsafhankelijkheid zit bij het aanmaken van de random. Misschien dat je hier ook oploopt, waardoor je een bepaalde vaste sequentie krijgt.

Wat uiteindelijk wel een goed onvoorspelbaar resultaat oplevert is:
Code:
Random gooi = new Random();
for (int i = 0; i < 100; i++)
{
    var Ogen = gooi.Next(1, 7);
    Console.WriteLine(Ogen);
}

Dus ik zou zeggen, kijk zeker ook eens hoe, waaar en wanneer je die random aanmaakt.

Tyfius

Legacy Member
Ja, de huidige tijd wordt gebruikt om dat random getal mee te bepalen. Als je de Random() buiten je loop gaat initialiseren levert dat betere resultaten op.

Kemblin

Legacy Member
Tis vrij logisch dat dit niet werkt:

Ik ken niks van C# maar naar bij het aanmaken van een random object gebruikt ge normaal steeds een seed (=een getal). Op basis van de seed worden u random numbers gegenereerd. Geeft ge dus steeds dezelfde seed, dan gaat ge ook steeds dezelfde sequentie 'random' getallen krijgen.

Code:
for (int i = 0; i < 100; i++)
{
    Random gooi = new Random();
    var Ogen = gooi.Next(1, 7);
    Console.WriteLine(Ogen);
}

reden dat dit vb niet werkt is omdat ge in de for loop telkens opnieuw uw random object aanmaakt. Random gooi = new Random(); In het geval van C# wordt er, als je zelf geen seed meegeeft, als seed de tijd gebruikt. Maar omdat uw for loop zo snel is hebt ge dus elke iteratie dezelfde seed (=hier de tijd dus).
Ge start dus telkens dezelfde random sequentie en ge vraagt het eerste getal er van op.

Code:
for (int i = 0; i < 100; i++)
{
    Random gooi = new Random();
    System.Threading.Thread.Sleep(10);
    var Ogen = gooi.Next(1, 7);
    Console.WriteLine(Ogen);
}
werkt ook, maar vuil :p Omdat ge telkens een sleep doet gaat uw for loop trager itereren en zal de tijd voor de for loop anders zijn als hij terug bij Random gooi = new Random(); aankomt. Hier zal dus telkens het eerste getal van een andere random sequentie worden opgevraagd.

Code:
 Random gooi = new Random();
for (int i = 0; i < 100; i++)
{
    var Ogen = gooi.Next(1, 7);
    Console.WriteLine(Ogen);
}

Zal dan weer wel werken, aangezien je nu echt gebruikt maakt van de .next om je sequentie te verkrijgen.

Code:
Random gooi = new Random(10);
var Ogen = gooi.Next(1, 7);
Console.WriteLine(Ogen);
Je moet dit maar eens proberen, ogen zal telkens je het programma runt dezelfde value hebben omdat de seed hier een vast getal 10 is.

NeverwinterX

Legacy Member
Random generators zijn altijd "pseudo-random" generators. Random generators werken ook bijna altijd met een "seed" van waaruit men de random number berekent.

De default Random constructor neemt de huidige tijd als seed. Daarom als je telkens een nieuwe Random maakt zal je een andere seed krijgen als de tijd ver genoeg uiteen ligt. Met de constructor new Random(Int32) kan je zelf de seed meegeven. Je kan daar misschien een wat ingewikkelder seed aan meegeven: met de tijd, mss wat extra informatie van het systeem (het vrij geheugen ofzo als je dat kan opvragen) met mss nog wat bitshifts met variabelen uit je programma.

Telkens opnieuw een nieuwe Random aanmaken en vandaar nieuwe random numbers genereren kan er ook toe leiden dat die random numbers hetzelfde zijn, zoals je ziet bij Krueger's code voorbeelden 1 vs 3, als de tijd waarop die Random's gemaakt worden hetzelfde is (afhankelijk van de precisie van het tijdmechanisme van C#, ws milliseconde) omdat de seed exact hetzelfde is. Het is beter om 1 Random te maken en die bij te houden en van daaruit nieuwe random numbers te genereren (en ook efficiënter).

Als dat niet goed genoeg is, kan je ook altijd een andere random generator gebruiken zoals hier.

Hell

Legacy Member
@Tyfius, ik merk nog geen verschil. Is hetzelfde voor mij als daarvoor.

@Krueger, als ik mijn random buiten de klasse zet, gaat het al helemaal mis. Ik gebruik nl geen loops maar inheritance met eigen controls.
Dat tijd belangrijke rol speelt had ik ook al door. Ik heb er een timer bijgestoken dat pauzeert tussen elke dobbelsteen zodat ze niet allemaal dezelfde waarden hebben.

@NeverwinterX, dat is overkill die random generator :D hehe

Ik heb een dobbelsteen control gemaakt en deze control zet ik 5 maal in een winform.
De dobbelsteen control bevat alleen de methode gooi() en een property om aan de value te geraken vanuit het winform.

Omdat een inherited control doorgeven niet meteen zal werken en ik wil ook niet zo direct heel mijn yahtzee spel mee doorgeven, heb ik de "dobbelstenen" opnieuw gemaakt in een winform als test.
Hier is de code natuurlijk wel anders dan mijn inherited control, maar de principe blijft hetzelfde alsook het probleem!
Na een paar keer "gooien" kan je uitmaken dat het ALTIJD van 6 naar 1 aftelt.
Doordat de timer van 1000ms ertussen komt, valt er wel een à twee getallen tussenin weg (en maar goed ook lol).

Wat je nodig hebt:
5 timers
5 labels
1 button
1 listbox

code:
Code:
   using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace dobbelsteenTest
{
    public partial class Form1 : Form
    {
        private int Ogen;
        public Form1()
        {
            InitializeComponent();
        }

        public int propOgen 
        {
            get { return Ogen; }
            set { Ogen = value; } 
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Start();
            button1.Visible = false;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Stop();
            Ogen = new Random().Next(1, 7);
            label1.Text = Ogen.ToString();
            timer2.Start();
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            timer2.Stop();
            Ogen = new Random().Next(1, 7);
            label2.Text = Ogen.ToString();
            timer3.Start();
        }

        private void label3_Click(object sender, EventArgs e)
        {

        }

        private void timer3_Tick(object sender, EventArgs e)
        {
            timer3.Stop();
            Ogen = new Random().Next(1, 7);
            label3.Text = Ogen.ToString();
            timer4.Start();
        }

        private void timer4_Tick(object sender, EventArgs e)
        {
            timer4.Stop();
            Ogen = new Random().Next(1, 7);
            label4.Text = Ogen.ToString();
            timer5.Start();
        }

        private void timer5_Tick(object sender, EventArgs e)
        {
            timer5.Stop();
            Ogen = new Random().Next(1, 7);
            label5.Text = Ogen.ToString();
            listBox1.Items.Add(label1.Text+" "+label2.Text+" "+label3.Text+" "+label4.Text+" "+
                label5.Text);
            listBox1.SelectedIndex = listBox1.Items.Count - 1;
            button1.Visible = true;
        }
    }
}

staat ook hier

en voor de luieriken hier de volledige solution in rar (ik gebruik visual studio 2008)

Kemblin

Legacy Member
hebt ge mijn post wel gelezen?

Waarom maakt ge nu elke keer een nieuw random object aan :/
Code:
Ogen = new Random().Next(1, 7);

roep gewoon die next aan, telkens op hetzelfde object, dan hebt ge toch helemaal geen timer nodig...


Code:
public partial class Form1 : Form
    {
    	Random r = new Random();
    	
    	
    	private een_functie()
        {
            Ogen = r.Next(1, 7);
            label1.Text = Ogen.ToString();
        }
        
        ....

Hell

Legacy Member
Kemblin zei:
hebt ge mijn post wel gelezen?

Waarom maakt ge nu elke keer een nieuw random object aan :/
Code:
Ogen = new Random().Next(1, 7);

roep gewoon die next aan, telkens op hetzelfde object, dan hebt ge toch helemaal geen timer nodig...


Code:
public partial class Form1 : Form
    {
    	Random r = new Random();
    	
    	
    	private een_functie()
        {
            Ogen = r.Next(1, 7);
            label1.Text = Ogen.ToString();
        }
        
        ....

khad uw post wel gelezen , maar gij moet die van mij ook eens leren lezen he :)
want krueger had dit al eerder voorgesteld
Voor u speciaal, upload ik mijn control (hopelijk steelt niemand dit van mijn klas haha)

see for yourself, ge zult wel weten wat ik dan bedoel.

(link verwijderd, kan nog op aanvraag via pm)

Tyfius

Legacy Member
Dat komt omdat de Random in .NET een pseudo random generator is en jij op dezelfde seconde een lijst met random getallen wil. Wil je echt zeker random getallen dan moet je ofwel de link die NeverwinterX gepost heeft volgen, ofwel beroep doen op een externe bron, ofwel eens die RNGCryptoServiceProvider klasse eens bekijken.

Kemblin

Legacy Member
mja ik ken niks van C# dus kga al uw code ni bezien, maar het leek mij gewoon omslachtig wat ge daar aan het doen waart. Als ge zelf zeker zijt dat het juist is, n/m dan ze :)

Hell

Legacy Member
haha ok
dan houd ik het wel bij mijn oplossing met timers.
Die voorspelbare aftelling trek ik mij niets van aan.
Nog even een goede code schrijven voor die "kleine/grote straat" en yahtzee is af :)

Cycloon

Legacy Member
forloRn_ zei:
Duidelijk geflawed dus, die Random-klasse in C#.

Idd, hell zou het moeten melden als bug en misschien beter nog, al een patch schrijven om die random generator te fixen.

Tyfius

Legacy Member
Zij vermelden zelf al dat ze de huidige tijd gaan gebruiken als seed. Dan is het ergens logisch dat als je op dezelfde tijd een hoop random getallen wil genereren binnen deze kleine range je hier geen goed resultaat mee kan bereiken. Als je die range nu bijvoorbeeld groter maakt, van 1 tot 100 bijvoorbeeld, dan krijg je al betere random resultaten.
Code:
csharp> using System;
csharp> Random r = new Random();
csharp> for (int i = 0; i < 10; i++) {
      > Console.WriteLine(r.Next(1, 100));
      > }
29
28
36
86
24
44
88
47
2
41
csharp>

En die patch schrijven, .net is nog altijd closed source. Zelf al kun je makkelijk min of meer de achterliggende code achterhalen denk ik niet dat ze dat bij microsoft zomaar aanvaarden. :)

Hell

Legacy Member
Cycloon zei:
http://images.starcraftmazter.net/4chan/for_forums/irony.jpg

Er is totaal niks mis met de Random, het lijkt me toch duidelijk dat de TS gewoon een serieus design probleem heeft in zijn code (die hij blijkbaar niet wil inzien/accepteren na enkele posts die hem daar op wijzen).

try it: http://dl.dropbox.com/u/1235460/DobbelsteenControl.rar
en als het werkt, laat het aan iedereen hier weten hoe je het opgelost hebt.
Dan ben je een echte held.

De link van NeverWinterX (link)
Duidt aan dat dit een bekend situatie is. En op te lossen via die override.
Maar voor mij moet die override niet, dat is overkill in mijn programmaatje.

En natuurlijk is er niets mis met die Random() , de intellisense zegt het zelf al dat het de Time als Seed gebruikt dus :)

Cycloon

Legacy Member
http://webs.hogent.be/christopher/DobbelsteenControl.rar

Ik heb het maar vlug gedaan, mooier zou zijn dat je de controls codegewijs aanmaakt en het Random object doorgeeft via de constructor. Nu wordt er bv niet gekeken of random gezet is e.d. (moet je zelf maar doen). Het idee is duidelijk.

Maar ik heb eigenlijk geen idee waarom ik hier mijn tijd in gestoken heb want die code is qua ontwerp echt een ramp. Voel je niet persoonlijk aangevallen, maar het kan kwalitatief een stuk beter.

FrostByte

Legacy Member
Leren goed coderen gaat verder dan gewoon wat syntax enzo, hoor. Strakke code leer je pas schrijven na een paar jaar ervaring. Maar laat vooral de moed niet zakken, niet slecht bezig :)

Hell

Legacy Member
goed gedaan, is wel mooi bedacht van die random ook in form1 te genereren.
Gij zet een random op een random.
ik benoem je alvast tot held van de dag :)

helaas was de opdracht om alles (incl de random en andere fields) in de control te houden zodoende dat je alleen de method moest aanspreken in base class.
is maar een dom oefn om zelf eens een control te leren maken.

de control is ook zelf geschreven in code, weet niet echt wat je bedoelt met "codegewijs aanmaken"

Cycloon is Held van de dag!!
Je hebt me gehoord he, 9Lives! Respect him


@FrostByte
kheb voor t examen een pokemon spel geschreven, code is onoverzichtelijk en omslachtig, maar het spel werkt en had geen bugs.
Verder had ik me echt nix van strakke code aangetrokken. Dacht er zelfs niet aan om het te herschrijven. Het was boem patat, t is af, kzen klaar :D

en tzal hetzelfde zijn met dit Yahtzee spel hoor, kzen bekan klaar en verder trek ik mij nix van de code aan :p en ik krijg er extra punten voor want t is een extra oefn :)
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan