One nice thing about turn-based games is that the logic for the game usually runs so fast that you can run it 'in-between' user events, so using a coroutine approach makes it pretty easy to write the game engine in a direct style with the rules explicitly coded in a straightforward fashion:
for turn in game:
for player in players:
action = await player.get_action()
engine.dispatch(action)
The nice thing is this approach supports remote proxy players - when you get an action from the local player you can send it out to all connected clients.