Thread overview
srand in D
Oct 31, 2021
pascal111
Oct 31, 2021
Ali Çehreli
Oct 31, 2021
pascal111
Jan 08, 2022
kdevel
Jan 08, 2022
Ali Çehreli
Jan 09, 2022
kdevel
Jan 09, 2022
Ali Çehreli
Jan 09, 2022
kdevel
Oct 31, 2021
Paul Backus
October 31, 2021

Hi! I'm C learner and found the high similarity between C and D, and was converting C code into D but couldn't get the equivalent of this C statement "srand(time(NULL));".

October 31, 2021
On 10/31/21 9:54 AM, pascal111 wrote:
> Hi! I'm C learner and found the high similarity between C and D, and was converting C code into D

Welcome! :) In case it makes to your use cases, check out -betterC as well:

  https://dlang.org/spec/betterc.html

> but couldn't get the equivalent of this C
> statement "srand(time(NULL));".

Just comment that line out. :) D's pseudo-random generators start randomized by default:

import std.stdio;
import std.random;

void main() {
  // Pick a number between [0,10)
  writeln(uniform(0, 10));
}

The documentation is at

  https://dlang.org/phobos/std_random.html

Ali
October 31, 2021

On Sunday, 31 October 2021 at 16:54:35 UTC, pascal111 wrote:

>

Hi! I'm C learner and found the high similarity between C and D, and was converting C code into D but couldn't get the equivalent of this C statement "srand(time(NULL));".

Since D gives you access to the C standard library, you can use pretty much exactly the same code in D:

import core.stdc.stdlib; // bindings for <stdlib.h>
import core.stdc.time; // bindings for <time.h>

srand(time(null)); // null is lower-case in D

If you want to use D's standard library, you can instead use std.random.rndGen, the default random number generator. Its documentation says:

>

It is allocated per-thread and initialized to an unpredictable value for each thread.

In other words, it is seeded for you automatically. So when you are converting C code that uses rand to D code that uses rndGen, you can simply delete the line srand(time(NULL));, and it will work ask expected.

If you wanted to seed it yourself, however, you would do it using the .seed method, and generate the seed using std.random.unpredictableSeed.

import std.random;

rndGen.seed(unpredictableSeed());

This is mainly useful when you are using a custom RNG instead of the default rndGen, since custom RNGs are not automatically seeded.

October 31, 2021
On Sunday, 31 October 2021 at 17:02:00 UTC, Ali Çehreli wrote:
> On 10/31/21 9:54 AM, pascal111 wrote:
>> Hi! I'm C learner and found the high similarity between C and D, and was converting C code into D
>
> Welcome! :) In case it makes to your use cases, check out -betterC as well:
>
>   https://dlang.org/spec/betterc.html
>
> > but couldn't get the equivalent of this C
>> statement "srand(time(NULL));".
>
> Just comment that line out. :) D's pseudo-random generators start randomized by default:
>
> import std.stdio;
> import std.random;
>
> void main() {
>   // Pick a number between [0,10)
>   writeln(uniform(0, 10));
> }
>
> The documentation is at
>
>   https://dlang.org/phobos/std_random.html
>
> Ali


Thanks! the code works now:

/* Acey Ducey game,
originally programmed in
BASIC */


// D programming language

import std.stdio;
import core.stdc.stdlib;
import std.ascii;
import core.stdc.string;
import core.stdc.stdio;
import core.time;
import std.conv;
import std.random;



/*
char* card_name(int); // turning cards valuse into strings function

void no_money_test(ref int); // money = 0 test
*/



// turning cards valuse into strings function
void card_name(int x, ref string c)
{

/* char* c=cast(char*) malloc((strlen("queen")+1)*(char.sizeof));

if(!c){
 writeln("A memory allocation failed!");
 exit(EXIT_FAILURE);} */

switch (x)
{

case 11:
	c="Jack";
	break;

case 12:
	c="Queen";
	break;
	
case 13:
	c="King";
	break;
	
case 14:
	c="Ace";
	break;
	
default:
        c=to!string(x);


}


}



// money = 0 test
void no_money_test(ref int your_money)
{

char q;

if (your_money == 0)

{


do
{
writeln("Oops! you have no money to bet with,");
write("do you want playing again (y/n)? ");

readf(" %c", &q);

} while ((toLower(q)!='y') &&
           (toLower(q)!='n'));

if (toLower(q)=='y') // nasted in 'if money = 0'
{

your_money = 100;

}

else
   exit(EXIT_SUCCESS);

} // if money = 0

}




int main()
{

int your_money=100;
int card_A,
    card_B, card_C;

string card_A_name,
	card_B_name,
	card_C_name;

char q;

int bet_much;

//srand(time(NULL));



do // 1st do
{


writeln("You've ", your_money, "$");


// Generating the two cards:

do
{

card_A = uniform(0, 13)+2; //(rand()%13)+2;
card_B = uniform(0, 13)+2;

} while (!((card_B - card_A) > 2) &&
           !((card_A==2)&&(card_B==14)));


card_name(card_A, card_A_name);
card_name(card_B, card_B_name);

writeln("Here are your two cards: ", card_A_name, " ", card_B_name);



// Betting query:


card_C = uniform(0, 13)+2;

do
{

write("Do you'll bet (y/n/e = (exit))? ");
readf(" %c", &q);

} while ((toLower(q)!='y') &&
           (toLower(q)!='n') &&
           (toLower(q)!='e'));


// agreeing betting

if (toLower(q)=='y')

{


do
{
write("With how much? ");
readf(" %d", &bet_much);

if (bet_much>your_money)
   {

     writeln("You don't have this much to bet with,");
     writeln("you have ", your_money, "$");

   }
	
} while (!(bet_much<=your_money));


if ((card_C>=card_A) && (card_C<=card_B)) // following agreeing betting 'if'
   {

	
    card_name(card_C, card_C_name);
    writeln("You are right! ");
    writeln("3rd card is: ", card_C_name);

    your_money+=bet_much;

   }

else
    {

     card_name(card_C, card_C_name);
     writeln("Oops! you are wrong!");
     writeln("3rd card is: ", card_C_name);
     your_money-=bet_much;

    }

}

else // 'else if' of agreeing betting 'if'
 if(toLower(q)=='e')
    exit(0);
else // considered final 'else' of agreeing betting 'if'
 writeln("CHICKEN!!!");



// Your money = 0 test

no_money_test(your_money);



} while (true); // 1st do




return 0;
}




// C version of the same game

/* Acey Ducey game,
originally programmed in
BASIC */


#include <iostream>
#include <cstdlib>
#include <string>
#include <cctype>
#include <cstring>
#include <cstdio>

using namespace std;



char *card_name(int); // turning cards valuse into strings function

void no_money_test(int&); // money = 0 test


int main(void)
{

int your_money=100;
int card_A,
    card_B, card_C;

char q;

int bet_much;

srand(time(NULL));



do // 1st do
{


cout << "You've "
     << your_money
     << "$" << endl;


// Generating the two cards:

do
{

card_A = (rand()%13)+2;
card_B = (rand()%13)+2;

} while (!((card_B - card_A) > 2) &&
           !((card_A==2)&&(card_B==14)));


cout << "Here are your two cards: "
     << card_name(card_A) << " "
     << card_name(card_B) << endl;



// Betting query:


card_C = (rand()%13)+2;

do
{

cout << "Do you'll bet (y/n/e = (exit))? ";
cin >> q;

} while ((tolower(q)!='y') &&
           (tolower(q)!='n') &&
           (tolower(q)!='e'));


// agreeing betting

if (tolower(q)=='y')

{


do
{
cout << "With how much? ";
cin >> bet_much;

if (bet_much>your_money)
   {

     cout << "You don't have this much to bet with,"
          << endl << "you have " << your_money << "$"
          << endl;

   }
	
} while (!(bet_much<=your_money));


if ((card_C>=card_A) && (card_C<=card_B)) // following agreeing betting 'if'
   {

    cout << "You are right! " << endl
         << "3rd card is: "
         << card_name(card_C) << endl;

    your_money+=bet_much;

   }

else
    {

     cout << "Oops! you are wrong!" << endl
          << "3rd card is: "
          << card_name(card_C) << endl;
     your_money-=bet_much;

    }

}

else // 'else if' of agreeing betting 'if'
 if(tolower(q)=='e')
    exit(0);
else // considered final 'else' of agreeing betting 'if'
 cout << "CHICKEN!!!" << endl;



// Your money = 0 test

no_money_test(your_money);



} while (true); // 1st do




return 0;
}


// turning cards valuse into strings function
char *card_name(int x)
{

char *c=(char *) malloc((strlen("queen")+1)*sizeof(char));

if(!c){
 cerr << "A memory allocation failed!"
      << endl;
 exit(EXIT_FAILURE);}

switch (x)
{

case 11:
	strcpy(c,"Jack");
	break;

case 12:
	strcpy(c,"Queen");
	break;
	
case 13:
	strcpy(c,"King");
	break;
	
case 14:
	strcpy(c,"Ace");
	break;
	
default:
        sprintf(c,"%d",x);


}

return c;
}


// money = 0 test
void no_money_test(int& your_money)
{

char q;

if (your_money == 0)

{


do
{
cout << "Oops! you have no money to bet with,"
     << endl << "do you want playing again (y/n)? ";

cin >> q;

} while ((tolower(q)!='y') &&
           (tolower(q)!='n'));

if (tolower(q)=='y') // nasted in 'if money = 0'
{

your_money = 100;

}

else
   exit(EXIT_SUCCESS);

} // if money = 0

}
January 08, 2022
On Sunday, 31 October 2021 at 17:02:00 UTC, Ali Çehreli wrote:
> Just comment that line out. :) D's pseudo-random generators start randomized by default:

[...]

>   https://dlang.org/phobos/std_random.html

Klicking at "Run" always delivers "mango":

https://dlang.org/phobos/std_random.html#uniform

A very unbalanced diet.
January 08, 2022
On 1/8/22 12:27 PM, kdevel wrote:
> On Sunday, 31 October 2021 at 17:02:00 UTC, Ali Çehreli wrote:
>> Just comment that line out. :) D's pseudo-random generators start randomized by default:
> 
> [...]
> 
>>   https://dlang.org/phobos/std_random.html
> 
> Klicking at "Run" always delivers "mango":
> 
> https://dlang.org/phobos/std_random.html#uniform
> 
> A very unbalanced die

That example wrapped in a program is the following:

import std.stdio;
import std.random;

void main() {
    auto rnd = MinstdRand0(42);

    writeln(rnd.uniform!ubyte); // 102
    writeln(rnd.uniform!ulong); // 4838462006927449017

    enum Fruit { apple, mango, pear }
    version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147
        writeln(rnd.uniform!Fruit); // Fruit.mango
}

Apparently, the programmer wanted uniformly distributed randomness that is reproducible. That's why they use a generator that is seeded with 42 there.

It does produce random results but the first Fruit happens to be "mango" with that seed.

TIL, I can use uniform with a type as in uniform!Fruit. Pretty cool. :)

Ali

January 09, 2022
On Saturday, 8 January 2022 at 23:34:17 UTC, Ali Çehreli wrote:
[...]
> Apparently, the programmer wanted uniformly distributed randomness that is reproducible. That's why they use a generator that is seeded with 42 there.
>
> It does produce random results but the first Fruit happens to be "mango" with that seed.


enum Fruit { apple, mango, pear }
version (X86_64)
writeln(uniform!Fruit);
```

This modified program delivers a fruit mix. Alas not in the online version, where one is supposed to have a preference for apples.

> TIL, I can use uniform with a type as in uniform!Fruit. Pretty cool. :)

nice. But

   enum immutable (char) [] allowed_chars = [
      'c', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 't', 'v',
      'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9'
   ];

   char q = uniform!allowed_chars;
   writeln (q);

complains with

uni2.d(11): Error: template instance `uniform!(['c', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 't', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9'])` has no value

January 08, 2022
On 1/8/22 4:17 PM, kdevel wrote:

>     enum immutable (char) [] allowed_chars = [
>        'c', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 't', 'v',
>        'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9'
>     ];
>
>     char q = uniform!allowed_chars;
>     writeln (q);
>
> complains with
>
> uni2.d(11): Error: template instance `uniform!(['c', 'f', 'g', 'h', 'j',
> 'k', 'l', 'm', 'n', 'p', 'r', 't', 'v', 'w', 'x', 'y', 'z', '1', '2',
> '3', '4', '5', '6', '7', '8', '9'])` has no value

That's because uniform's first template parameter is expected to be a type. (There are two uses of 'enum' in D and the one above is not a type, rather "this is a manifest constant".)

One might think that uniform should work with a string like "hello" but in that case what are the choices? The single string or its individual characters?

What would work in the code above is 'choice':

  char q = choice(allowed_chars);

But that hits another fact of D: arrays of chars are strings, which cannot be RandomAccessRange because individual chars must be decoded to form dchars.

Keeping the 'choice' line above and replacing two 'char's with 'dchar's in your code makes it work.

Ali

January 09, 2022
On Sunday, 9 January 2022 at 03:15:02 UTC, Ali Çehreli wrote:
> What would work in the code above is 'choice':
>
>   char q = choice(allowed_chars);
>
> But that hits another fact of D: arrays of chars are strings, which cannot be RandomAccessRange because individual chars must be decoded to form dchars.

One can use explicit index notation which is nearly as compact as the template parameter form:

   string salt = iota (0, 16)
      .map!(i => saltchars [uniform(0, $)])
      .array;


January 10, 2022

On 1/8/22 7:17 PM, kdevel wrote:

>

On Saturday, 8 January 2022 at 23:34:17 UTC, Ali Çehreli wrote:
[...]

>

Apparently, the programmer wanted uniformly distributed randomness that is reproducible. That's why they use a generator that is seeded with 42 there.

It does produce random results but the first Fruit happens to be "mango" with that seed.

enum Fruit { apple, mango, pear }
version (X86_64)
writeln(uniform!Fruit);


This modified program delivers a fruit mix. Alas not in the online version, where one is supposed to have a preference for apples.

The online compiler caches results to save on computational resources. So if you don't change the code, you will get the same result.

Just add spacing to get it to rebuild.

-Steve