go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/kana-server/pkg/kana/helpers.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package kana 9 10 import ( 11 "math/rand" 12 "sort" 13 ) 14 15 // CreateWeights creates weights for a given set of kana. 16 func CreateWeights(values map[string]string) map[string]float64 { 17 output := make(map[string]float64) 18 for key := range values { 19 output[key] = WeightDefault 20 } 21 return output 22 } 23 24 // IncreaseWeight increases the weight for a given value. 25 func IncreaseWeight(weights map[string]float64, key string) { 26 if weight, ok := weights[key]; ok { 27 if weight < WeightMax { 28 weights[key] = weight * WeightIncreaseFactor 29 } 30 } 31 } 32 33 // DecreaseWeight decreases the weight for a given value. 34 func DecreaseWeight(weights map[string]float64, key string) { 35 if weight, ok := weights[key]; ok { 36 if weight <= WeightMin { 37 return 38 } 39 weights[key] = weight / WeightDecreaseFactor 40 } 41 } 42 43 // SelectCount returns the first N elements from a given combined values set. 44 // 45 // The selection is mostly random, and predicated on map ordering being random. 46 // If this ever changes (map ordering being random) we will need to use 47 // random bag pulls. 48 func SelectCount(values map[string]string, count int) map[string]string { 49 if count == 0 || len(values) <= count { 50 return values 51 } 52 output := make(map[string]string) 53 for key, value := range values { 54 output[key] = value 55 if len(output) == count { 56 break 57 } 58 } 59 return output 60 } 61 62 // SelectWeighted selects a kana and a roman from a given set of values and weights. 63 func SelectWeighted(values map[string]string, weights map[string]float64) (kana, roman string) { 64 // collect "weighted" choices 65 type weightedChoice struct { 66 Key string 67 Weight float64 68 } 69 var keys []weightedChoice 70 for key := range values { 71 keys = append(keys, weightedChoice{ 72 Key: key, 73 Weight: weights[key], 74 }) 75 } 76 77 // sort by weight ascending 78 sort.Slice(keys, func(i, j int) bool { 79 return keys[i].Weight < keys[j].Weight 80 }) 81 82 // sum all the weights, assign to indexes 83 totals := make([]float64, len(keys)) 84 var runningTotal float64 85 for index, wc := range keys { 86 runningTotal += wc.Weight 87 totals[index] = runningTotal 88 } 89 randomValue := rand.Float64() * runningTotal 90 randomIndex := sort.SearchFloat64s(totals, randomValue) 91 92 kana = keys[randomIndex].Key 93 roman = values[kana] 94 return 95 } 96 97 // Merge merges variadic sets of values. 98 func Merge(sets ...map[string]string) map[string]string { 99 output := make(map[string]string) 100 for _, set := range sets { 101 for key, value := range set { 102 output[key] = value 103 } 104 } 105 return output 106 } 107 108 // ListHas returns if a value is present in a list 109 func ListHas(list []string, value string) bool { 110 for _, listValue := range list { 111 if listValue == value { 112 return true 113 } 114 } 115 return false 116 } 117 118 // ListAddFixedLength adds a value to a given list 119 func ListAddFixedLength(list []string, value string, max int) []string { 120 list = append(list, value) 121 if len(list) < max { 122 return list 123 } 124 return list[1:] 125 }