Skip to content

Instantly share code, notes, and snippets.

@gitschaub
Created October 30, 2018 18:56
Show Gist options
  • Save gitschaub/a561b79127d9da2e7d5641f6735a78ba to your computer and use it in GitHub Desktop.
Save gitschaub/a561b79127d9da2e7d5641f6735a78ba to your computer and use it in GitHub Desktop.
package main
import (
"encoding/json"
"fmt"
"math/rand"
"os"
"sort"
"time"
)
type Members struct {
Members []string `json:"members"`
}
type Group struct {
Groups []Members `json:"groups"`
}
type Assignments struct {
To string `json:"to"`
From string `json:"from"`
}
type GroupRecord struct {
Idx int
Len int
Members []string
}
type RecordsByLen []GroupRecord
func (a RecordsByLen) Len() int { return len(a) }
func (a RecordsByLen) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a RecordsByLen) Less(i, j int) bool { return a[i].Len < a[j].Len }
func main() {
// defer profile.Start().Stop()
// defer track(time.Now())
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
var group Group
err := json.NewDecoder(os.Stdin).Decode(&group)
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
groupIDs := make([]GroupRecord, len(group.Groups), len(group.Groups))
total := 0
for i, members := range group.Groups {
groupIDs[i] = GroupRecord{
Idx: i,
Len: len(members.Members),
Members: members.Members,
}
total += groupIDs[i].Len
}
sort.Sort(sort.Reverse(RecordsByLen(groupIDs)))
mixer := make([]int, total, total)
ptr := 0
for i, g := range groupIDs {
for j := 0; j < g.Len; j++ {
mixer[ptr] = i
ptr++
}
}
// fmt.Println(mixer)
h1, h2 := mixer[:len(mixer)/2], mixer[len(mixer)/2:]
ptr = 0
var out1, out2, out []int
out1 = Interleave(h1, h2)
if len(h1) == len(h2) {
out2 = Interleave(h2, h1)
}
out = out1
if !valid(out1) {
// fmt.Printf("Out1 was invalid: %v\n", out1)
if !valid(out2) {
fmt.Println("IT DIDN'T PAN OUT")
os.Exit(1)
}
out = out2
}
// fmt.Println(h1, h2, out)
// transform out to strings
names := make([]string, len(out), len(out))
for i, v := range out {
record := groupIDs[v]
n := r1.Intn(record.Len)
names[i] = record.Members[n]
groupIDs[v].Len--
groupIDs[v].Members = append(groupIDs[v].Members[:n], groupIDs[v].Members[n+1:]...)
}
assignments := make([]Assignments, 0, len(out))
for i, _ := range names {
a, b := i, (i+1)%len(names)
assignments = append(assignments, Assignments{From: names[a], To: names[b]})
}
json.NewEncoder(os.Stdout).Encode(assignments)
}
func Interleave(h1, h2 []int) []int {
out := make([]int, len(h1)+len(h2), len(h1)+len(h2))
ptr := 0
for i, _ := range h2 {
if i == len(h1) {
out[ptr] = h2[i]
} else {
out[ptr], out[ptr+1] = h2[i], h1[i]
}
ptr += 2
}
return out
}
func valid(out []int) bool {
return out[0] != out[len(out)-1]
}
func track(startTime time.Time) {
endTime := time.Now()
fmt.Println("took", endTime.Sub(startTime))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment