Last active
April 24, 2025 06:40
-
-
Save owais/019ad4baa71246d7dd0bcd99ece05230 to your computer and use it in GitHub Desktop.
Preference based number allocator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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