91 lines
1.5 KiB
Go
91 lines
1.5 KiB
Go
package pwgen
|
|
|
|
func runeFor(alphabet []rune, prng Int32n) rune {
|
|
return alphabet[prng.Int31n(int32(len(alphabet)))]
|
|
}
|
|
|
|
func alphabet(start, end rune) (result []rune) {
|
|
length := end - start + 1
|
|
result = make([]rune, length)
|
|
for i := int32(0); i < length; i++ {
|
|
result[i] = start + i
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func merge[T any](slices ...[]T) []T {
|
|
var totalLength int
|
|
for i := range slices {
|
|
totalLength += len(slices[i])
|
|
}
|
|
|
|
result := make([]T, totalLength)
|
|
|
|
var offset int
|
|
for i := range slices {
|
|
copy(result[offset:], slices[i])
|
|
offset += len(slices[i])
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func shuffle[T comparable](in []T, prng Int32n) (result []T) {
|
|
if !canShuffle(in) {
|
|
return in
|
|
}
|
|
|
|
for {
|
|
result = make([]T, 0, len(in))
|
|
temp := make([]T, len(in))
|
|
copy(temp, in)
|
|
|
|
for len(temp) > 0 {
|
|
var i int32
|
|
for {
|
|
i = prng.Int31n(int32(len(temp)))
|
|
if i != int32(len(result)) {
|
|
break
|
|
}
|
|
}
|
|
result = append(result, temp[i])
|
|
copy(temp[i:], temp[i+1:])
|
|
temp = temp[:len(temp)-1]
|
|
}
|
|
|
|
if !sequenceEqual(in, result) {
|
|
return result
|
|
}
|
|
}
|
|
}
|
|
|
|
func canShuffle[T comparable](in []T) bool {
|
|
if len(in) < 2 {
|
|
return false
|
|
}
|
|
|
|
uniq := make(map[T]bool)
|
|
for _, r := range in {
|
|
uniq[r] = true
|
|
if len(uniq) > 1 {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func sequenceEqual[T comparable](first, second []T) bool {
|
|
if len(first) != len(second) {
|
|
return false
|
|
}
|
|
|
|
for i := range first {
|
|
if first[i] != second[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|