It isn't reliably reproducible, but usually comes up in a minute or two of play. I've tried to work around it using a select statement, and then using a mutex, but the problem still comes up. I'm new to programming in Go, so I'm hoping someone can point out where I'm going wrong.
I use a goroutine for the keyboard input and a goroutine for the timer that causes the block to drop every few ticks. The goroutes each communicate with the main program through a different channel. The ncurses object is passed to the keyboard goroutine. The timer goroutine just sleeps.
func main() {
// declare variables, etc
// mutex
var nlock struct {
sync.Mutex
}
// keyboard channel - keyboard input comes through here
ck := make(chan int)
go keys_in(stdscr, ck, nlock)
// timer channel - tetris timer to drop the block comes through here
ct := make(chan int)
go t_timer(ct, 1, nlock)
// main loop of the game
for keep_going := true; keep_going == true; {
// wait for either keyboard input or timer
select {
case somechar = <-ct:
action = "timeout"
case somechar = <-ck:
action = "keyboard"
}
nlock.Lock()
// game logic and drawing blocks comes here
// nothing until the end of the loop calls on the channels or the goroutines
nlock.Unlock()
switch {
case action == "timeout":
go t_timer(ct, speed, nlock)
case action == "keyboard":
go keys_in(stdscr, ck, nlock)
}
}
}
func keys_in(stdscr gc.Window, ck chan int, nlock struct{ sync.Mutex }) {
nlock.Lock()
somechar := int(stdscr.GetChar())
ck <- somechar
nlock.Unlock()
}
func t_timer(ct chan int, speed int, nlock struct{ sync.Mutex }) {
mseconds := time.Duration(1000 / speed)
time.Sleep(mseconds * time.Millisecond)
nlock.Lock()
ct <- 110 // drop the block
nlock.Unlock()
}
Thanks.