コード例 #1
0
ファイル: table_test.go プロジェクト: shields/saseat
func TestScoring(t *testing.T) {
	table := saseat.NewTable(8)
	table.Left[0] = saseat.Guest{"Abe", "male"}
	table.Left[1] = saseat.Guest{"Mary", "female"}
	table.Left[2] = saseat.Guest{"Jane", "female"}
	table.Right[0] = saseat.Guest{"Alexander", "male"}
	table.Right[1] = saseat.Guest{"Kang", ""}
	expectedTableScore := saseat.CapacityPref*math.Expm1(1) + saseat.ImbalancePref*math.Expm1(1)

	prefs := saseat.Prefs{}
	prefs.Set("Abe", "Mary", 1000)
	prefs.Set("Kang", "Jane", -80)
	prefs.Set("Alexander", "Jane", 50)
	expectedLeft := []float64{
		1000 * saseat.AdjacentWeight,
		1000*saseat.AdjacentWeight + saseat.SameGenderPref,
		-80*saseat.DiagonalWeight + 50*saseat.SameTableWeight + saseat.SameGenderPref,
		0,
	}
	expectedRight := []float64{
		50 * saseat.SameTableWeight,
		-80 * saseat.DiagonalWeight,
		0,
		0,
	}

	table.Rescore(prefs)
	if table.TableScore != expectedTableScore {
		t.Errorf("got table score %v, want %v", table.TableScore, expectedTableScore)
	}
	if !reflect.DeepEqual(table.LeftScores, expectedLeft) {
		t.Errorf("got left prefs %v, want %v", table.LeftScores, expectedLeft)
	}
	if !reflect.DeepEqual(table.RightScores, expectedRight) {
		t.Errorf("got right prefs %v, want %v", table.RightScores, expectedRight)
	}
}
コード例 #2
0
ファイル: main.go プロジェクト: shields/saseat
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)
}