This is what I currently have: A singleton class GameManager
which mostly consists of a ConcurrentDictionary
that contains all ongoing games (binds the game board and nicks of both players to the game's ID). I also have a SignalR hub, GameHub
with a method MakeAMove(ulong gameId, Move move)
that retrieves the relevant gameId
game from the dictionary, lock
s on it, checks if the player who has invoked the method is the player who is now supposed to make a move and if yes, makes appropriate changes to the game's board, broadcasts this move to all observers of this game and if necessary, concludes the game, declaring it to be a victory of player X or a draw and removing it from the dictionary.
What I don't have is the timer. I think the timer is necessary, because without it many games may never conclude and forever linger in this dict. The timer should work in such a way that if a player fails to make a move within the allocated time, the game is automatically concluded and such a player is declared to be the loser.
I don't know how should such a timer be implemented. I have a few ideas, but I'm not sure which one is correct, if any.
The only idea I have to solve this task that doesn't seem to be horrible to me would look like this: ConcurrentDictionary
binds gameId
s to instances of Game
class. Then each such instance has a method that await
s until the timer for the player who is supposed to make a move runs out or until GameHub
notifies this method that a move order has been made, whichever happens first. However, I am ignorant how to implement this.
Is this the right way to go? If yes, then how am I supposed to make this method wait until the timer runs out or until a move order comes to GameHub
?
EDIT: I SUPPOSE I should write something like this:
await Task.WhenAny(
Task.Delay(players_available_time_left),
??something_to_mean_a_move_order_has_arrived??
);
You can simply use a timer that you start every turn and stop after move is done :
private System.Timers.Timer Timer = null;
private double TimerDelay = 30d * 1000d; // 30 seconds
private void StartTimer()
{
Timer = new System.Timers.Timer() { Interval = TimerDelay , AutoReset = false};
Timer.Elapsed += Timer_Elapsed;
Timer.Start();
}
private void StopTimer()
{
Timer.Stop();
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// stop the timer
StopTimer();
// call the method to make the player lose and end the game
EndGame();
}
When you start the player turn call the StartTimer()
and let it go. When the player ends it's turn call the StopTimer()
and it will stop the timer from calling the end of the game. If the timer runs out it will automatically call your end of game.