func TestReadGuests(t *testing.T) { g, err := saseat.ReadGuests(strings.NewReader(guestsFile)) if err != nil { t.Error(err) } if !reflect.DeepEqual(g, expectedGuests) { t.Errorf("got: %q\nwant: %q\n", g, expectedGuests) } }
func main() { rand.Seed(time.Now().UnixNano()) flag.Parse() if *guestFlag == "" || *prefFlag == "" || *tableFlag == "" { fmt.Fprintln(os.Stderr, "all flags are required") os.Exit(2) } // Load guests file. f, err := os.Open(*guestFlag) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } guests, err := saseat.ReadGuests(f) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // Load prefs file. f, err = os.Open(*prefFlag) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } prefs, err := saseat.ReadPrefs(f) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err = prefs.CheckGuests(guests); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // Create tables, packing the guests to them in random order. var tables []saseat.Table perm := rand.Perm(len(guests)) seated := 0 for _, s := range strings.Split(*tableFlag, ",") { capacity, err := strconv.ParseInt(s, 0, 10) if err != nil { fmt.Fprintln(os.Stderr, "bad table capacity %q: %v", s, err) os.Exit(1) } if capacity <= 0 || capacity%2 != 0 { fmt.Fprintln(os.Stderr, "only positive even table sizes supported") os.Exit(1) } t := saseat.NewTable(int(capacity)) for i := 0; i < int(capacity/2) && seated < len(guests); i++ { t.Left[i] = guests[perm[seated]] seated++ } for i := 0; i < int(capacity/2) && seated < len(guests); i++ { t.Right[i] = guests[perm[seated]] seated++ } t.Rescore(prefs) tables = append(tables, t) } if seated != len(guests) { fmt.Fprintf(os.Stderr, "seats for only %v of %v guests", seated, len(guests)) os.Exit(1) } // Let's anneal! temp := 250.0 reported := time.Now() iter := 1 for ; ; iter++ { // Cooling. if iter%1000000 == 0 { temp *= 0.98 } if time.Now().Sub(reported) > 1*time.Second { report(tables) fmt.Printf("Iteration %d, temperature %.1f\n\n\n", iter, temp) reported = time.Now() } // Spend more time trying to optimize within tables instead of // swapping people around the room. if rand.Float64() > 0.1 { i := rand.Intn(len(tables)) t := copyTable(&tables[i]) t.Swap(&t, 2) t.Rescore(prefs) if accept(t.Score, tables[i].Score, temp) { tables[i] = t } } else { i1 := rand.Intn(len(tables)) i2 := rand.Intn(len(tables)) if i1 == i2 { continue } t1 := copyTable(&tables[i1]) t2 := copyTable(&tables[i2]) t1.Swap(&t2, -1) t1.Rescore(prefs) t2.Rescore(prefs) if accept(t1.Score+t2.Score, tables[i1].Score+tables[i2].Score, temp) { tables[i1] = t1 tables[i2] = t2 } } } report(tables) }