Skip to content

Instantly share code, notes, and snippets.

@owais
Last active April 24, 2025 06:40
Show Gist options
  • Save owais/019ad4baa71246d7dd0bcd99ece05230 to your computer and use it in GitHub Desktop.
Save owais/019ad4baa71246d7dd0bcd99ece05230 to your computer and use it in GitHub Desktop.
Preference based number allocator
package main
import (
"fmt"
"math/rand"
"slices"
"strconv"
"time"
)
const numPrefs int = 3
type User struct {
prefs []int
allotted *Number
}
func (u User) String() string {
var prefs string
for i := 0; i < numPrefs; i++ {
prefs += strconv.Itoa(u.prefs[i]) + ","
}
return fmt.Sprintf("prefs: %s allotted: %v", prefs, u.allotted)
}
type Number struct {
value int
assignedTo *User
}
func (n Number) String() string {
return fmt.Sprintf("%d", n.value)
}
func main() {
rand.Seed(time.Now().UnixNano())
numUsers := 11
numNumbers := 11
// prep users
users := make([]*User, numUsers)
for i := 0; i < numUsers; i++ {
users[i] = &User{
prefs: randomPrefs(1, numNumbers),
}
}
// prep numbers
numbers := make([]*Number, numNumbers)
for i := 0; i < numNumbers; i++ {
numbers[i] = &Number{
value: i + 1,
}
}
// randomize order of numbers and users
shuffle(numbers)
shuffle(users)
// run allocations
allocateNumbers(numbers, users, numPrefs)
for _, user := range users {
fmt.Println("User: ", user)
}
}
func allocateNumbers(numbers []*Number, users []*User, passes int) {
// if no more passes (preferences) left, assign numbers to users randomly
if passes == 0 {
for _, number := range numbers {
for _, user := range users {
if user.allotted == nil {
user.allotted = number
break
}
}
}
return
}
// get current preference index
pref := (numPrefs - passes)
remaining := []*Number{}
OUTER:
// for each number...
for _, number := range numbers {
// ..check if any user...
for _, user := range users {
if user.allotted != nil {
continue
}
// ..prefers the number in the current preference order
if user.prefs[pref] == number.value {
user.allotted = number
continue OUTER
}
}
// number not claimed by any user
remaining = append(remaining, number)
}
// if numbers left, do another pass with next preference
if len(remaining) > 0 {
allocateNumbers(remaining, users, passes-1)
}
}
func randomPrefs(min, max int) []int {
prefs := []int{}
for i := 0; i < numPrefs; i++ {
choice := rand.Intn(max-min+1) + min
for slices.Contains(prefs, choice) {
choice = rand.Intn(max-min+1) + min
}
prefs = append(prefs, choice)
}
return prefs
}
func shuffle[T any](slice []T) {
rand.Shuffle(len(slice), func(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment