I am implementing a game engine. Most of my code currently resides in a StateT Game IO () monad. I use IO to get user input, and in fact all IO channels through one function,
getChoice :: Show a => [ a ] -> IO a
which prompts the user with all presented options, reads in a response, and returns it. For a particular flow of user responses (and initial state), the game proceeds deterministically, and I'd like to factor out these user responses to help with testing.
When I try to convert this to use Pipes, what feels most similar is to change all my code which is currently in StateT Game IO (), and make it run in Proxy p, Monad m => Client p [String] String m (). This way I can still 'request' choices from the user, which allows me to write the engine code in a blocking style, assuming that user choices will be provided as I need them.
However, this seems wrong - surely the user should be the Client, and the game engine the Server? What principles can I use to make this distinction correctly?