Time control

There are six time control systems on OGS, a start clock system, multiple ways to pause games, and latency compensation considerations when dealing with real-time games. While all of this may seem daunting at first, once you wrap your head around it it's not so bad - this document will help guide you through that process.

Applicable fields within the game object.

There are three fields of interest within a game data object. time_control, clock, and pause_control (which won't exist unless the game has been paused at least once).

time_control

The time_control field is used to describe the time control system being used in the game and does not change. This field takes on one of six structures, depending on what time control system is used

{
  "time_control"  : "fischer",
  "initial_time"  : 86400, /* in seconds */
  "time_increment": 3600,  /* in seconds */
  "max_time"      : 86400  /* in seconds */
}
{
  "time_control": "byoyomi",
  "main_time"   : 86400, /* seconds */
  "period_time" : 3600,  /* seconds */
  "periods"     : 5      /* count */
}
{
  "time_control": "simple",
  "per_move"    : 86400  /* seconds */
}
{
  "time_control"     : "canadian",
  "main_time"        : 86400, /* seconds */
  "period_time"      : 86400, /* seconds */
  "stones_per_period": 10     /* count */
}
{
  "time_control": "absolute",
  "total_time"  : 86400  /* seconds */
}
{
  "time_control": "none"
}

Fischer: Clock begins with the initial_time, after each move time_increment is added up to a maximum of max_time. Displays only need to show the current amount of time remaining, and optionally how much time will be added after each move.

Byo-Yomi: Clock begins with main_time, after the main time is exhausted the clock is set to period_time and the number of periods is decreased. If the player makes a move before the period is up, the clock is reset to period_time. If the player exhausts the clock again and there are periods remaining, the clock is set to the period_time again and the period counter is decreased. This continues until all periods have been used up, at which time a player loses on time.

DIsplays should show the base time, and the number of periods left, and optionally how long each period is.

Simple: Clocks begin with per_move time. After each move the clock is reset to per_move.

Canadian: Clocks being with main_time and use this time until it is exhausted, at which point the clock is set to period_time. Once in overtime, after each move the stones_per_period counter is decreased until it reaches zero. Once this happens the clock is reset to period_time and the stones_per_period counter is reset. Displays should show the time remaining, and if the user is in overtime then the stones_per_move counter should also be shown.

Absolute: The clock is set to total_time and only decreases.

None: The simplest time control system, no clock is used or displayed.

clock

The clock field contains the current state of the game clock and changes once per move.

{
    
    black_time: {
        period_time: 30, /* seconds */
        periods: 5,
        thinking_time: 1200 /* seconds */
    },
    white_time: {
        period_time: 30, /* seconds */
        periods: 5,
        thinking_time: 360.90599999999995   /* seconds */
    },
    current_player: 12751,
    last_move: 1416172879750, /* milliseconds since epoch */
    now: 1416093910807,       /* milliseconds since epoch */
    
    start_mode: false, /* removed after a game begins */
    
  	/* These fields are used by the server, but are not
     * necessary for clients to display clock information */
    game_id: 989449,
    black_player_id: 12751,
    white_player_id: 1,  
    title: "friendly match",
    paused_since: 1416093910,   /* seconds since epoch */
    expiration_delta: 1350000,  /* milliseconds */
    expiration: 1416174229750,  /* milliseconds since epoch */
}

The black_time and white_time fields take on different forms depending on what time control system is being used

{
	thinking_time: 12345, /* seconds */
  
  /* Used by the server, unnecessary for the client */
  skip_bonus: false
}
{
  thinking_time: 12345, /* seconds */
  periods      : 3,     /* periods left */
  period_time  : 30,    /* seconds */
}
123455  /* this field is simply a number of seconds on the clock, will be 0 for the player not playing (this is subject to change, and may become number of seconds left on the clock for the last move instead of simply 0 in the future.) */
{
  thinking_time : 12345, /* seconds */
  
  /* applicable only when thinking_time == 0, however 
   * the fields will always exist */
  moves_left    : 20,    /* moves left in this period  */
  block_time    : 3600   /* seconds left in this period  */
}
{
  thinking_time: 12345  /* seconds */
}
# The `black_time` and `white_time` fields do not exist for the `none` time control.

Which is an ugly mess, and we apologize. If we had to do it over again, it'd be a lot different and notably cleaner (or at least that's what we'd like to think.)

Details on how to make use of these fields to turn the clock into something you can show to your users will follow after the section on pause_control

pause_control

Games can be paused for several reasons, such as a player having clicked the pause button, the game has been paused for a system event, the game has been paused on the weekend (a correspondence game feature), users are on vacation, or because the game is in the stone removal phase.

If the game is paused the game object will contain the pause_control field as an object and will contain one or more entries describing what is currently pausing the game. Note: if a game has been paused and unpaused, the pause_control field may still be present in the game data object, but it will contain no fields.

{
  "paused": {
    "pauses_left": 4,
    "pausing_player_id": 1
  },
  "weekend": true,
  "system": true,
  "vacation-{{player id}}": true,
  "stone-removal": true
}

Putting it all together

Ultimately the goal of understanding the OGS time control system is so you can display a clock showing how much time is left before either a timeout or the start of your next byo-yomi / canadian period. Additionally you have to handle the start clock (which just tells the user how much time is left before the first move must be made), and when to display whether the game is paused or not. The following pseudo-code should help illustrate how to do this - at the end you'll be left with left which is intended to be the number of milliseconds left before a timeout / period rollover.

if clock.start_mode:
	Display time until clock.expiration
elif `pause_control` exists and is non-empty:
  Display "Paused"
else:
  let player_time be black_time or white_time appropriately
  let now_delta = NOW() - clock.now
  let base_time = clock.last_move + now_delta
  if player_time is number:
  	# simple time
    let time_left = player_time - NOW()
  if player_time is object:
    let left = base_time + player_time.thinking_time*1000 - now
    if moves_left is a field in player_time: # canadian
    	if left < 0 or player_time.thinking_time == 0:
      	left = base_time + (player_time.thinking_time + \
               player_time.block_time) * 1000 - now
    if periods is a field in player_time: # byo yomi
      if left < 0 or player_time.thinking_time == 0:
        let period_offset = floor((-left / 1000) / player_time.period_time)
        period_offset = max(0, period_offset)
        
        while left < 0:
        	left += player_time.period_time * 1000
        
        
        let periods_left = (player_time.periods - period_offset) - 1
        if (player_time.periods - period_offset) - 1 < 0:
        	left = 0
        

# left now contains the number of milliseconds left 
# on the clock before either a timeout or the start 
# of the next byo-yomi or canadian period
# The number of milliseconds since Jan. 1, 1970 (Epoch)