“Simulate my opponent, and if it tries to simulate me, see what it will do if it simulates me outputting Cooperate.”
This has the problem that, since most strategies will eval twice (to check both the C and D cases) you can be reasonably sure that if both calls return the same result you are being simulated.
Edit: Although it doesn’t fully fix the problem, this is better: eval takes a function that takes the function the other agent will call eval with as its argument and returns C or D.
eval(function(fn) {
if(fn(function(ignore) { return C; }) == C) return C;
if(fn(function(ignore) { return D; }) == D) return D;
// etc
});
There are still detection problems here (you could add checks to see if the function you passed to the function eval passed to you was invoked), but the fact that some strategies wouldn’t do overly ambitious recursion at least downgrades the above approach from obvious information leak to ambiguous information leak
If you build your own eval, and it returns a different result than the built in eval, you would know you’re being simulated