split src/devices/input into src/devices/input/{raw,wrap}
This commit is contained in:
92
src/device/input/raw/random.go
Normal file
92
src/device/input/raw/random.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package raw
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/go-yaml/yaml"
|
||||
)
|
||||
|
||||
type Random struct {
|
||||
generator func() byte
|
||||
down []byte
|
||||
}
|
||||
|
||||
func NewRandom(generator func() byte) *Random {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return &Random{generator: generator}
|
||||
}
|
||||
|
||||
func (r *Random) Close() {
|
||||
}
|
||||
|
||||
func (r *Random) Read() []byte {
|
||||
return []byte{r.generator()}
|
||||
}
|
||||
|
||||
func randomCharFromRange(start, stop byte) func() byte {
|
||||
return func() byte {
|
||||
return start + byte(rand.Int()%int(1+stop-start))
|
||||
}
|
||||
}
|
||||
|
||||
func randomCharFromWeightFile(p string) func() byte {
|
||||
b, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return randomCharFromWeightReader(bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func randomCharFromWeightReader(r io.Reader) func() byte {
|
||||
var m map[string]int
|
||||
if err := yaml.NewDecoder(r).Decode(&m); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
byted := map[byte]int{}
|
||||
for k, v := range m {
|
||||
if len(k) != 1 {
|
||||
panic(fmt.Sprintf("keys must be 1 character but got %q", k))
|
||||
}
|
||||
byted[k[0]] = v
|
||||
}
|
||||
return randomCharFromWeights(byted)
|
||||
}
|
||||
|
||||
func randomCharFromWeights(m map[byte]int) func() byte {
|
||||
type pair struct {
|
||||
b byte
|
||||
i int
|
||||
}
|
||||
result := make([]pair, 0, len(m))
|
||||
sum := 0
|
||||
for k, v := range m {
|
||||
result = append(result, pair{b: k, i: v})
|
||||
if v < 0 {
|
||||
panic("each weight must each be natural")
|
||||
}
|
||||
sum += v
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
return result[i].i < result[j].i
|
||||
})
|
||||
if sum <= 0 {
|
||||
panic("weights must total nonzero")
|
||||
}
|
||||
return func() byte {
|
||||
r := rand.Int()
|
||||
n := r % (sum + 1)
|
||||
for _, v := range result {
|
||||
n -= v.i
|
||||
if n <= 0 {
|
||||
return v.b
|
||||
}
|
||||
}
|
||||
panic("how")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user