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
|
package bingo
import (
"iter"
"math/rand"
"slices"
)
type Tile struct {
Text string
Checked bool
Checkable bool
}
type TilePool map[string][]string
func (pool TilePool) All() iter.Seq[string] {
return func(yield func(string) bool) {
for _, list := range pool {
for _, tile := range list {
if !yield(tile) {
return
}
}
}
}
}
type TilePicker interface {
All() iter.Seq[string] // provides an iterator over an entire TilePool
Iter(int) iter.Seq2[string, Tile] // provides an iterator over n elements of a TilePool
Reset() // reset the internal state of a TilePicker
}
type RandomTilePicker struct {
ChosenTags []string
tilePool TilePool
rand rand.Rand
}
func NewRandomTilePicker(tiles TilePool, r rand.Rand) *RandomTilePicker {
tp := new(RandomTilePicker)
tp.tilePool = tiles
tp.rand = r
return tp
}
// Iterate over all elements of a TilePool in a random order
func (tp RandomTilePicker) All() iter.Seq[string] {
return func(yield func(string) bool) {
tiles := slices.Collect(tp.tilePool.All())
if len(tiles) == 0 {
return
}
tp.rand.Shuffle(len(tiles), func(i int, j int) {
tiles[i], tiles[j] = tiles[j], tiles[i]
})
for _, tile := range tiles {
if !yield(tile) {
return
}
}
}
}
// Iterator over a TilePool by choosing one tile per tag until pool is exhausted or size tiles have been yielded
func (tp RandomTilePicker) Iter(size int) iter.Seq2[string, Tile] {
return func(yield func(string, Tile) bool) {
if len(tp.tilePool) == 0 {
return
}
tags := make([]string, len(tp.tilePool))
for tag := range tp.tilePool {
tags = append(tags, tag)
}
tp.rand.Shuffle(len(tags), func(i int, j int) {
tags[i], tags[j] = tags[j], tags[i]
})
yielded := 0
for _, tag := range tags {
if yielded == size {
return
}
list := tp.tilePool[tag]
if len(list) == 0 {
continue
}
text := list[tp.rand.Intn(len(list))]
tile := Tile{Text: text}
if !yield(tag, tile) {
return
}
yielded++
}
}
}
func (tp RandomTilePicker) Reset() {
tp.ChosenTags = make([]string, len(tp.ChosenTags))
}
|