I'd think that unless you were playing a very large number of rounds such that you could infer the opponent's PRNG function and seed, or unless the opponent PRNG was REALLY bad, this would not work.

Actually, supposing the seed state is 32 bits in size, it really doesn't take that many rounds. Each round, one of three outcomes is produced. This yields roughly 1.6 bits of information about the generator's internal state. After 20 rounds, you have, in theory, enough information to infer the PRNG seed. If you can predict the opponent's move for 30 straight rounds, you can be pretty confident that you've determined both the seed and the function precisely. This works for arbitrary seeds.

Maybe if the seed were the time to the nearest hour you might be OK. However, if it used time to a millisecond then you'd have almost no chance of success. Any decent PRNG will show what would appear to be completely different behavior with even a slightly different seed.

With regards to the timestamp: srand(time(NULL)) isn't a random seed. If you can guess when the process called this function (hint: it's at least after the process was started!), you can then bruteforce over a very small number of possibilities. If the process was started, say, at 7:00pm for the contest start, and you run at 8:30pm, you've got a search space of just 5000000 milliseconds, which is trivial. My implementation worked for this contest (as evidenced by its extremely high win rate against rand()-using bots).

Now, if the PRNG were really lousy maybe you'd have a shot. It just seems unlikely that such a function would exist in any well-used library since the 60s. Sure, lots of functions are inadequate for cryptography, but even defeating these poor algorithms usually requires lots of data collection and a huge search. A PRNG that takes 5 years of supercomputer time would be considered broken, since a brute force keysearch might require the age of the universe. That doesn't mean that you're going to defeat it with a few rounds of RPS to figure out what it is doing.

This PRNG-breaking approach would work equally well for a crappy linear-congruential generator as for a modern Mersenne Twister, since it relies only on being able to guess the seed (not the entire internal state).

Most libc implementations of rand() really suck. They were originally implemented for memory economy and speed, and there was no concern about security. Now, such implementations are largely retained for compatibility, so that older programs can still produce the same results using fixed seeds. The various libcs are, arguably, the most-used libraries in existence. To beat many of these generators requires just one (or two) observations of the full 32-bit output, plus a trivial amount of computation.