|
package main |
|
|
|
import ( |
|
"fmt" |
|
"strconv" |
|
) |
|
|
|
// An alternative to "Synchronization queues in Golang" (https://medium.com/golangspec/synchronization-queues-in-golang-554f8e3a31a4) |
|
// See goplayground () |
|
func main() { |
|
testersMax := 1000 |
|
progrmsMax := 1000 |
|
testers := make(chan play, testersMax+100) |
|
progrms := make(chan play, progrmsMax+100) |
|
table := make(chan play) |
|
|
|
go playerGen("Tester", testers, testersMax) |
|
go playerGen("Programmer", progrms, progrmsMax) |
|
go playersPair(testers, progrms, table) |
|
term := make(chan bool) |
|
go pingPong(table, 1000, term) |
|
<-term |
|
} |
|
|
|
func playerGen(role string, plyq chan<- play, max int) { |
|
for i := 1; i < max+1; i++ { |
|
plr := new(player) |
|
plr.mePlay(role+"_"+strconv.Itoa(i), plyq) |
|
} |
|
} |
|
|
|
type play interface { |
|
play() (term chan bool) |
|
} |
|
|
|
func pingPong(table <-chan play, maxGames int, term chan<- bool) { |
|
defer func() { term <- true }() |
|
var gameTotal int |
|
fmt.Println() |
|
for { |
|
if gameTotal >= maxGames { |
|
return |
|
} |
|
p1, p1ok := <-table |
|
p2, p2ok := <-table |
|
if !(p1ok && p2ok) { |
|
return |
|
} |
|
p1t := p1.play() |
|
p2t := p2.play() |
|
<-p1t |
|
<-p2t |
|
p1t <- false |
|
p2t <- false |
|
// time.Sleep(100 * time.Millisecond) |
|
gameTotal++ |
|
fmt.Println() |
|
} |
|
} |
|
|
|
func playersPair(pque1 <-chan play, pque2 <-chan play, table chan<- play) { |
|
pque1sel := pque1 |
|
pque2sel := pque2 |
|
players := make([]play, 2) |
|
var plyIx int |
|
var ok bool |
|
for { |
|
if plyIx > 1 { |
|
table <- players[0] |
|
table <- players[1] |
|
plyIx = 0 |
|
pque1sel = pque1 |
|
pque2sel = pque2 |
|
} |
|
select { |
|
case players[plyIx], ok = <-pque1sel: |
|
if !ok { |
|
return |
|
} |
|
plyIx++ |
|
pque1sel = nil |
|
case players[plyIx], ok = <-pque2sel: |
|
if !ok { |
|
return |
|
} |
|
plyIx++ |
|
pque2sel = nil |
|
} |
|
} |
|
} |
|
|
|
type player struct { |
|
name string |
|
term chan bool |
|
plyc chan bool |
|
} |
|
|
|
func (p *player) mePlay(name string, plyq chan<- play) { |
|
p.name = name |
|
p.term = make(chan bool) |
|
p.plyc = make(chan bool) |
|
start := make(chan bool) |
|
go playerAgent(p, plyq, start) |
|
<-start |
|
close(start) |
|
} |
|
|
|
func (p *player) play() (term chan bool) { |
|
fmt.Printf("%s starts\n", p.name) |
|
p.plyc <- true |
|
return p.term |
|
} |
|
|
|
func playerAgent(p *player, que chan<- play, start chan bool) { |
|
que <- p |
|
start <- true |
|
for { |
|
// time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond) |
|
<-p.plyc |
|
// time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) |
|
fmt.Printf("%s ends\n", p.name) |
|
p.term <- true |
|
que <- p |
|
<-p.term |
|
} |
|
} |