Ok, here is the big question... -norand?

HA!

You actually don’t need to depend on the turn counter. You can implement a normal RNG. Since you will be storing the state of it in an object, and every object is non-transient unless you explicitly make it transient, your random numbers will be deterministic even with UNDO and SAVE/RESTORE. (When the RNG spits out a number and you UNDO, it will give you the same number again next time.)

Here’s a working RNG object:

simpleRand: object {
    seed = 1; // Use whatever value you want as initial seed.

    // Returns a number between 0 and lim-1. This is "Gerhard's generator", an extremely
    // simple algorithm that generates low-quality pseudorandom numbers.
    getRand(lim)
    {
        seed = (seed * 32719 + 3) % 32749;
        return seed % lim;
        // If you instead want numbers between 1 and lim,
        // then use this instead: return (seed % lim) + 1
    }
}

simpleRand.getRant(lim) will return a value between 0 and lim-1. Since ‘seed’ is also the current state, it is saved and restored accordingly when you UNDO/SAVE/RESTORE.

RealNC, that works as advertised. And it’s a heck of a lot more random than any of the efforts I’ve been able to work out so far (including making the Yahoo answer a non-iterative function).

Many thanks! – I’ll proceed with this write-around unless the TADS gurus come up with a deep solution.

Conrad.

ps - I confirmed correct behavior with UNDO and with save and restore – as you say, it’s storing the new seed value as a variable, which persists like any other game state. Very cool.

No, it’s not recursive since it doesn’t call itself. It’s also not iterative since there’s no loop in it. Translating C to TADS is fairly simple; usually dropping the types (since TADS is dynamically typed) is enough. The TADS version of the above is:

get_random()
{
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w; /* 32-bit result */
}

Of course ‘m_z’ and ‘m_z’, just like in C, have to be defined somewhere. I would stick to the code I wrote previously though, since this one doesn’t give you control over the range of values you want. It just spits out a signed 32-bit number.

Hopefully in the next TADS version the state of the RNG used by rand() will be accessible by the game and can therefore be part of the VM’s save-state functionality. That’s the plan right now. That means that you should be able to have fully reproducible behavior throughout the library without needing any custom code at all.

:mrgreen:

What I was talking about was that m_z is defined in reference to itself. The output becomes the new seed value. I was trying to avoid that, using instead the game turn as the seed value.

I got the operators working for that one, but swapped in the game turn for the right-hand m_z and m_w. The results were pretty unrandom.

Yes, I will do that.

Ok, cool… is this a major release that’ll be a while, or a smaller one that’ll be sooner? – I’m not asking to rush, but to figure out how to plan my efforts on this project.

Conrad.

A seed, as the word implies, is only an initial value. It’s a one-time thing. From a single seed you then get a sequence of numbers. You do not re-seed the RNG every time, since that destroys the sequence. (How big that sequence is, is called the “period” of the RNG. If you’re interested in more details, you can always consult the Wikipedia article about it. Depending on your interests, it might be worth a read: en.wikipedia.org/wiki/Pseudorand … _generator.)

It’s a minor change, so it’s a candidate for 3.1.1, not 3.2. TADS does not have a release schedule though, so I don’t know when 3.1.1 will come out.

No, I understand seed values being fed back in. In my understanding, this is iterative and recursive. The code itself may not be, technically, because it uses a variable and waits for an external control to call it a second time.

However, to get Random Number n, you must first get RN n-1, to get which you must first get RN n-2… all the way back to Random Number n-n, which is your seed value. You’re iterating through a recursive structure, as I understand the terms.

I had been looking for a way to avoid that, and was fearing I’d have to resort to a lookup table, in order to tether the pseudo-random number to the turn counter. Many thanks for the better solution, and I’ll writearound until 3.1.1.

Conrad.

Ah, now I get what you mean. Yes, that looks recursive indeed. I had the problem itself in mind though. The problem itself does not imply recursion or iteration. For example, if the problem states “what’s the Nth Fibonacci number”, then you have an N there. But in an RNG, your problem is not “what’s the Nth random number”. It’s just “give me a random number”.

(Not that calculating Fibonacci numbers actually requires iteration or recursion. It’s only the definition of the numbers that’s recursive.)

Another problem with this approach is that you get the same number if you need more then one during the same turn (which is not unlikely at all).

That’s true!

Conrad.

The change made it in Tads 3.1.1. The RNG state can now be saved and restored, giving the exact same random numbers every time:

Thanks, RealNC, for the heads up! – And thanks, TADS development team!