Computing a value, but with a timeout


#1

I’d like to do something that looks like

while (it's been less than N seconds) {
  u = computeSomethingComplicated(...)
}
but if N seconds elapse before the computation is complete {
  u = someDefaultValue
}

I’m pretty sure I don’t know how to do this in OCaml, which makes it even less likely that I can do it in Reason. BTW, the second clause might be replaced by “evaluate some other expression” rather than “set u to some value”.

The context here is playing a game: when it’s your move, I want you to choose a move within 3 seconds, and if you don’t, I’ll make a default move for you (or perhaps declare the game over and say that you lose).

So if I call your “nextMove” procedure, and you chase way down the game tree, and take 30 seconds to make a decision…that’s bad for you.

Any pointers on how to do this in ReasonML?


#2

Are you targeting native or BuckleScript? In JS, that sounds like a job for Promise.race, for native, I think you can use something like Lwt.pick.


#3

I guess that because I’m using “reprocessing”, which seems to require “native”, Im targetting “native”. I’ll try to read up on Lwt.pick


#4

Hey @jfh Thanks for the question. In a general sense, this isn’t quite possible unless you use several different threads because any synchronous code in a main thread will just run, without any possible interruption. Since you mentioned this is in the context of reprocessing, I’d recommend simply storing a timer in your state that you increment by Env.deltaTime(env) each frame, and check when you’re also checking if the user has chosen a move (whatever it means to you to chose a move).
Basically in reprocessing you don’t think in terms of events that trigger, you think about what you need to do at every single frame. In this case you need to increment a timer, check if the user has made a move, then if the user has not AND the timer is beyond a certain value, you make a move for them, all in 1 frame.

I hope this makes sense.


#5

This is certainly a model of animation that I’m familiar with; I’m not so clear on how it looks in reprocessing, since I’ve never learned to use Processing itself. Hence when I look at reprocessing, it’s not as if I’m seeing familiar stuff wrapped up in a new module – it’s all new to me. But I’ll work it out one way or another.

I take it that the reprocessing code and the other code (like my move-making-ai-player code) somehow run in different threads? Otherwise, when reprocessing checks to see if the player’s made a move, the answer’s gonna be “the player’s done nothing, because all the cycles in the thread were taken up by reprocessing,” and surely that can’t be right.


#6

Oh here’s how reprocessing works:

  1. it sets up a window and an event queue and all the GL stuff
  2. calls your setup function
  3. then starts a while(true) loop where it
    a) checks the event queue, pops all of them and sets some global state for you (like last seen mouse position, mouseState if it’s clicked or not etc…). You might say that if the user clicks faster than 16ms, then we will not detect the click as the mouseDown/mouseUp will happen within the same frame. That’s true, which is why we also allow you to register mouse callbacks which will get called each time an event happened, and you can track your own state if you’d like. Otherwise, the chances of that happening are low enough that we’re ok with providing the other API (the one where you just check inside your render function), which happens to be super convenient.
    b) calls your newState := render(previousState, env) effectively
    c) “sleeps” if it’s been less than 1/60th of a second

And that’s all. So there are no threads. We use SDL to handle events, which implements its own event queue. I’m not sure how that’s implemented, and it’s possible that on MacOS it uses a thread to push onto the shared queue.


#7

Thanks. We did eventually manage to cobble together a working program, and reprocessing did all that we could have hoped for. :slight_smile: