Search code examples
c#asp.net-coretimeoutmultiplayer

How to implement timer in a multiplayerchess game? Asp .NET Core


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, locks 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 gameIds to instances of Game class. Then each such instance has a method that awaits 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??
);
  • is this correct? If yes, what should I write instead of the question marks?

Solution

  • 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.