-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
178 lines (150 loc) · 3.74 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package main
import (
"flag"
"fmt"
"log"
"os"
"strconv"
"time"
"github.com/eiannone/keyboard"
"github.com/pterm/pterm"
)
const (
// Players, identified by color.
White = iota
Black
GameActive
GamePaused
GameReset
GameOver
)
// Hold clock time in seconds.
type ClockTime time.Duration
type GameState time.Duration
type ChessClock struct {
whiteTime ClockTime
blackTime ClockTime
// Active players time.
active uint64
// State of game (over, paused, active, etc)
gameState uint64
}
func NewChessClock(gameTime ClockTime) *ChessClock {
// Create new clock with corresponding times. White activtes first as
// in chess white always makes the first move.
clk := &ChessClock{whiteTime: gameTime, blackTime: gameTime, active: White}
return clk
}
// toggleActive toggles between the time left for the two players.
func (c *ChessClock) toggleActive() {
switch c.active {
case White:
c.active = Black
case Black:
c.active = White
}
}
// decrementCurrentTimer will decrement the current active players
// time by one (in this case one second).
func (c *ChessClock) decrementCurrentTimer() {
// NOTE: Add logic for timer running out (White Lose) and draws
switch c.active {
case White:
if c.whiteTime > 0 {
c.whiteTime--
} else {
log.Println("White is out of time..")
}
case Black:
if c.blackTime > 0 {
c.blackTime--
} else {
log.Println("Black is out of time")
}
}
}
// Take ClockTime type (seconds), return mins and secs values.
func secToMins(t ClockTime) (mins, secs uint) {
mins = uint(t) / 60
secs = uint(t) % 60
return mins, secs
}
func main() {
var gameTime ClockTime = 0
// flags for the different game modes, and a custom time
gameMode := flag.String("m", "rapid", "Game modes: \n- \"rapid\" (15 min)\n- \"blitz\" (3 min)\n- \"classical\" (120 min)\n- Define a custom time (in secs): \"-m time 60\"\n")
flag.Parse()
switch *gameMode {
case "blitz":
gameTime = ClockTime(180)
case "classical":
gameTime = ClockTime(7200)
case "time":
secs, err := strconv.Atoi(flag.Args()[0])
if err != nil {
pterm.Warning.Println("[+] Invalid time given")
os.Exit(1)
}
gameTime = ClockTime(secs)
default:
gameTime = ClockTime(900)
}
// Make sure our clock isn't set to a useless zero.
if gameTime == 0 {
pterm.Warning.Println("[+] No time set on game clock.")
os.Exit(1)
}
// Grab user keyboard input, (cbreak is 0) replace with termbox
userInput := make(chan string)
go func() {
err := keyboard.Open()
if err != nil {
panic(err)
}
defer keyboard.Close()
for {
c, _, err := keyboard.GetKey()
if err != nil {
panic(err)
}
userInput <- string(c)
}
}()
// Create our chess clock.
clk := NewChessClock(gameTime)
tick := time.Tick(1 * time.Second)
fmt.Println("")
// Start area for our TUI output
area, _ := pterm.DefaultArea.Start()
Loopend:
for {
select {
case in := <-userInput:
switch in {
// Spacebar toggles the timer
case "\x00":
clk.toggleActive()
case "q":
break Loopend
}
case <-tick:
// Stop the chess clock application. Someone won, lost, or quit..
if (clk.whiteTime == 0) || (clk.blackTime == 0) {
fmt.Println("\nClock stopping...")
break Loopend
}
clk.decrementCurrentTimer()
wMins, wSecs := secToMins(clk.whiteTime)
bMins, bSecs := secToMins(clk.blackTime)
// Display current clock times for each player.
// Aside: Formatting needs refactor. Four spaces seperate the respective times for each player.
clksStr, _ := pterm.DefaultBigText.
WithLetters(pterm.NewLettersFromString(fmt.Sprintf("%02d:%02d ", wMins, wSecs) +
fmt.Sprintf("%02d:%02d", bMins, bSecs))).Srender()
clksStr = pterm.DefaultCenter.Sprint(clksStr)
area.Update(clksStr)
}
}
area.Stop()
fmt.Println("\nQuitting...")
}