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}