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  }