How to use a u64 randomly and without repeating

Hello everyone please how i can set this "number: u64," to be randomly and without any repeat.

You could use rand::random and keep track of what you've seen.

#[derive(Default, Debug)]
struct Generator {
    seen: HashSet<u64>,
}

impl Generator {
    fn random(&mut self) -> u64 {
        let mut candidate = rand::random();
        while !self.seen.insert(candidate) {
            candidate = rand::random();
        }
        candidate
    }
}
5 Likes

Thanks for your quick reply, My bad i didn't put the code So with it i will be easy to understanding what i need. So this is the function and i need to target this "(number)" sorry but i'm new on rust and i can't handle this.

pub fn get_config_line(
    a: &Account<'_, Candy>,
    index: usize,
    number: u64,
) -> Result<ConfigLine> {
    if let Some(hs) = &a.data.hidden_settings {
        return Ok(ConfigLine {
            name: hs.name.clone() + &(number).to_string(),
            uri: hs.uri.clone() ,
        });
    }

From that code snippet I can infer that you don't really want a random u64. Can you further elaborate your requirement(s)?

2 Likes

When i use &(number).to_string() i got the number in order 1-2...., but i need them randomly 9-6.., without any repeat. This is the candy machine and i want to make some change .

If you want to have random numbers appended within the function, you can pass in random numbers when you call the function (e.g. line 548) instead of candy_machine.items_redeemed. (What that would mean semantically in the larger context of the library, I'm not going hazard a guess.)

2 Likes

I don't know how i can handle this, and i think is the function pub fn get_good_index (line 745) is for the random numbers because already the candy machine has this function but on the &a.data.hidden_settings take number from u64. And please if you can help me with provide a code to do this like I mentioned before I'm new in rust thanks again.

struct Rng(u64);
impl Rng {
    const A: u64 = 6364136223846793005;
    fn rand(&mut self) -> u64 {
        self.0 = self.0.wrapping_mul(Self::A).wrapping_add(1);
        self.0
    }
    fn from_seed(seed: u64) -> Self {
        Self(seed ^ 3141592653589793238)
    }
}

fn main() {
    let mut rng = Rng::from_seed(0);
    for _ in 0..10 {
        let number = rng.rand();
        println!("{:016x}", number);
    }
}
1 Like

Random without repetition is a permutation of the sequence over all numbers in that range. I.e. a block cipher in counter mode.

For 32bit numbers you can use skip32. For 64bit numbers... maybe something like cast5, 3des, xtea?
I wonder if there's a crate that provides a variable-block-size cipher construction for random permutations.

The advantage of this approach is that it only needs to store the counter and not the already-visited elements, i.e. it has O(1) memory complexity.

1 Like

Another way to generate a random permutation:

use rand::{Rng, rngs::ThreadRng};

struct RngPerm {
    remaining: Vec<u64>,
    rng: ThreadRng,
}

impl RngPerm {
    fn new(range_size: u64) -> Self {
        Self {
            remaining: (0..range_size).collect(),
            rng: rand::thread_rng(),
        }
    }
    
    fn next(&mut self) -> Option<u64> {
        if self.remaining.is_empty() {
            return None;
        }
        
        let idx = self.rng.gen_range(0..self.remaining.len());
        Some(self.remaining.swap_remove(idx))
    }
}

Of course, this requires the range to be relatively limited since the list must fit in memory.

1 Like

If very weak randomness is sufficient, you could use Fibonacci numbers:

fn weak_random_gen() -> impl FnMut() -> u64 {
    let mut state: u64 = 0;
    move || {
        state += 4660046610375530309; // 91st fibonacci number
        state %= 12200160415121876738; // 93rd fibonacci number
        state
    }
}

fn main() {
    let mut generator = weak_random_gen();
    for _ in 0..6 {
        println!("{}", generator());
    }
}

(Playground)

(Not sure if returning a closure is idiomatic here. You could also return a struct with a method.)

Those two numbers have no common divisors except 1, thus the sequence will not repeat until you call it for the 12200160415121876738th time (which is greater than 263).

Due to using Fibonacci numbers here, the difference between two successively generated numbers will be an approximation of the golden angle (in regard to the modulus). This isn't really random but might suffice depending on the application scenario.


For good random numbers, I would also recommend what @the8472 would do:

Basically you count up from 0 to 264−1, and you "encrypt" each number with a reversible block cipher (i.e. a function that will map two different inputs always to two different outputs, thus being a bijective function). If the function behaves sufficiently chaotic, you get good random values, and because of the bijectivity, they won't repeat as long as you don't reach 264 for the input.

Some block ciphers use Feistel networks to ensure bijectivity, e.g. Blowfish (which is a 64 bit cipher).

3 Likes

Feistel network is a good keyword. There's the permutation_iterator crate which uses a weak, variable width feistel network and rejection sampling to provide permutations for arbitrary ranges. This may be good enough if you don't need cryptographic-strength randomness.

1 Like

I have this function pub fn get_config_line from the candy machine and mint_number i need result to be randomly.

pub fn get_config_line(
    a: &Account<'_, Candy>,
    index: usize,
    mint_number: u64,
) -> Result<ConfigLine> {
    if let Some(hs) = &a.data.hidden_settings {
        return Ok(ConfigLine {
            name: hs.name.clone() + &(mint_number).to_string(),
            uri: hs.uri.clone() ,
        });
    }

metaplex-program-library/mint.rs at 58d10c46e66ca9d9c6288999ca9289c986587c7f · metaplex-foundation/metaplex-program-library · GitHub

mint_number here is a parameter to the function, which means that it is some specific number provided by the caller. As it’s not useful to choose randomly from a set of one, I’m having trouble understanding what you’re asking for. Do you want…

  1. To generate a random number outside this function and provide it as mint_number?
  2. To ignore or remove the mint_number parameter and replace it with a random number generator?
  3. To generate a random number that is somehow influenced by the mint_number parameter?
  4. Something else?
2 Likes

I think that is number 3, sorry if my requirements is not clear but i don't understand the rust lang that's why i can't explain better what exactly i need to do with this functionality, but the most important is this mint_number every time called give me a number start from 1 next call 2 etc..... until the item available is minted, so i need this mint_number to be randomly example is item available 10 every mint i get the random number 3-7-9-1-2-5-8-4, i hope that was helpful to understand my needs

I believe you are saying that you will have a known number of numbers. LIke maybe you will mint 1000 things so need 1000 random numbers. If you have a known number of objects to mint, and the number is not huge, try @alice answer.

But the problem this numbers is dynamic and depending on the collection size, and candy machine program already has randomly mint function but not on the hidden settings and i'm not able to determine this function and call it on place of mint_number, i tried before to use index on place of mint_number and i got randomly number but with some repetition numbers.

Could you show how you would write this using another programming language that you know better? That might help people understand.

1 Like

1-To generate a random number outside this function and provide it as mint_number? how i can do this please i'm still searching without finding a solution