darwins-challenge / moonlander-ast-rust

Code to create, manipulate and evaluate abstract syntax tree for the moonlander control code in Rust

Home Page:http://darwins-challenge.github.io/moonlander-ast-rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Reduce probability of stack overflowing when generating random programs

dvberkel opened this issue · comments

As seen in random.rs, it is possible to generate a random program. The strategy for generating a random program is to take the Program enum and choose, with equal probability, one of the options, and generating a random random element for that option.

Because the Program can generate abstract syntax trees of unbounded depth, it is possible, and in fact very likely, that the call to generate a random program overflows the stack.

We should change the probabilities of the options so that it becomes less likely that we will generate very deep abstract syntax trees

The current strategy is to randomly return a enum option is by the following code

impl rand::Rand for Command {
    fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        match rng.gen_range(0, 4) {
            i @ 0...1 if i < 1 => Command::Skip,
            i @ 1...2 if i < 2 => Command::Left,
            i @ 2...3 if i < 3 => Command::Right,
            i @ 3...4 if i < 4 => Command::Up,
            _ => panic!(),
        }
    }
}

It is easy to change the probability of the different options by changing the numbers of the match. I am working on a (series of) macros that can create the rust code above.

Ideally it would look like

pickOneOf![10, Command::Skip, 5, Command::Left, 5, Command::Right, 8, Command::Up]

Where the numbers are the weights with which the options are chosen. E.g. the above code should expand to

match rng.gen_range(0, 28) {
    i @  0...10 if i < 10 => Command::Skip,
    i @ 10...15 if i < 15 => Command::Left,
    i @ 15...20 if i < 20 => Command::Right,
    i @ 20...28 if i < 28 => Command::Up,
    _ => panic!(),
}

I am partway to the example. I have a macro that when given the correct total and correct ranges expands to the last example. I am now in the process of creating a macro that calculates the total and the ranges.

I am hesitant to do this with one bigger macro, but I will see what the future will bring.

Couldn't pickOneOf take a list of tuples? Then it wouldn't need to be a macro.

Mmm, good suggestion. It is always wise to check if you are solving a problem with the wrong tool.

The reason I am still convinced a macro is the way to go is user experience. (That would be us :-) ) It is far easier to just write the macro then to create the list with tuples. But maybe I have been sitting in my ivory nursery for too long.

Agreed, totally depends on what the syntax would be. I don't know enough Rust yet to predict :)

I managed to create a macro that adheres to the wanted contract. It landed in commit 8234401.

Although I really like the match operator, I could not make it happen due. The most problematic part was updating the bounds for each iteration round the provided expressions. I ended up expanding into a if ... else if ... else structure.

We now only have to use it.