time.gno
1.85 Kb ยท 82 lines
1package chess
2
3import (
4 "time"
5)
6
7// TimeControl keeps track of time control information for the game.
8type TimeControl struct {
9 Seconds int
10 Increment int
11
12 StartedAt time.Time
13 MoveTimestamps []time.Time
14 WhiteTime time.Duration
15 BlackTime time.Duration
16}
17
18func NewTimeControl(seconds, incr int) *TimeControl {
19 if seconds <= 0 {
20 return nil
21 }
22 return &TimeControl{
23 Seconds: seconds,
24 Increment: incr,
25
26 StartedAt: time.Now(),
27 WhiteTime: time.Duration(seconds) * time.Second,
28 BlackTime: time.Duration(seconds) * time.Second,
29 }
30}
31
32// AddMove records that at the current time, a new move was added.
33func (tc *TimeControl) AddMove() (valid bool) {
34 nd, v := tc.timedOut()
35 if v {
36 return false
37 }
38 if len(tc.MoveTimestamps)&1 == 0 {
39 tc.WhiteTime = nd
40 } else {
41 tc.BlackTime = nd
42 }
43 tc.MoveTimestamps = append(tc.MoveTimestamps, time.Now())
44 return true
45}
46
47func (tc *TimeControl) TimedOut() bool {
48 _, v := tc.timedOut()
49 return v
50}
51
52func (tc *TimeControl) timedOut() (time.Duration, bool) {
53 mts := tc.MoveTimestamps
54
55 // First move for each player: they both have up to 30 seconds.
56 switch len(mts) {
57 case 0:
58 delta := time.Since(tc.StartedAt)
59 return tc.WhiteTime, delta > time.Second*30
60 case 1:
61 delta := time.Since(mts[0])
62 return tc.BlackTime, delta > time.Second*30
63 }
64
65 // Determine color. Determine time since last move. Try subtracting from
66 // color's time. If >= 0, good. If < 0, timeout.
67 delta := time.Since(mts[len(mts)-1])
68
69 if len(mts)&1 == 0 { // white
70 nt := tc.WhiteTime - delta
71 return nt + tc.incr(), nt < 0
72 }
73
74 nt := tc.BlackTime - delta
75 return nt + tc.incr(), nt < 0
76}
77
78func (tc *TimeControl) incr() time.Duration {
79 // there is always at least a one second increment, to account for
80 // block time and the delay between user making a move and tx happening
81 return time.Second + time.Duration(tc.Increment)*time.Second
82}