背景
公司年会举办活动,我来组织乒乓球赛,由于人数不是很多而且时间比较紧迫。第一轮采用分组积分赛制,组内人人都会对战一次,程序实现了一下对战顺序。
go
的随机数 rand
go
的 math/rand
包实现了伪随机数生成器。
如下示例,生成 10
以内的随机数 rand.Intn
:
func tMathRand() {
for i := 0; i < 100; i++ {
fmt.Println(rand.Intn(10))
}
}
不管运行几次,生成结果都如下:
1
7
7
9
1
8
5
0
6
0
这里是因为没有设置随机数种子,一般来说,可以使用当前时间戳来作为随机数种子,如下 rand.Seed
:
func tMathRand() {
rand.Seed(time.Now().Unix())
for i := 0; i < 100; i++ {
fmt.Println(rand.Intn(10))
}
}
程序实现积分赛程安排
package main
import (
"errors"
"fmt"
"math/rand"
"strings"
"time"
)
func main() {
fmt.Println("请输入需要参赛的队伍,用英文逗号 ',' 分隔")
var peopleStr string
for {
_, err := fmt.Scanf("%s", &peopleStr)
if err != nil {
fmt.Println("输入有误,请重新输入:", err)
continue
}
break
}
p := strings.Split(peopleStr, ",")
res, err := pingpongRand(p)
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(res)
}
fmt.Println()
fmt.Println("请输入任意值退出...")
fmt.Scan(&peopleStr)
//fmt.Scanln(&peopleStr)
}
type peopleRand struct {
Count int // 已出现的次数
MatchedIndex []int // 匹配过的人 下标
}
func (p *peopleRand) Matched(index int) bool {
for _, v := range p.MatchedIndex {
if v == index {
return true
}
}
return false
}
// 输入参赛选手,输出对战信息
func pingpongRand(people []string) ([][]string, error) {
rand.Seed(time.Now().Unix())
peopleLength := len(people)
if peopleLength <2 {
return [][]string{}, errors.New("参赛至少为 2 组")
}
resLength := (peopleLength - 1) * peopleLength / 2
res := make([][]string, 0, resLength)
peopleCount := peopleLength - 1 // 1 个人最多出现的次数
var displayCount = make(map[int]*peopleRand) // 每个人出现的次数
for {
i1 := rand.Intn(peopleLength) // 人员下标
_, ok := displayCount[i1]
if !ok {
p := new(peopleRand)
p.Count = 1
displayCount[i1] = p
}
if displayCount[i1].Count > peopleCount {
continue
}
displayCount[i1].Count++
couple := make([]string, 2) // 存放对战人名单
// 判断 i1 已出现的次数
couple[0] = people[i1]
for {
i2 := rand.Intn(peopleLength)
if i2 == i1 { // 剔除自己
continue
}
_, ok := displayCount[i2]
if !ok {
p2 := new(peopleRand)
p2.Count = 1
displayCount[i2] = p2
}
if displayCount[i2].Count > peopleCount {
continue
}
// 剔除已匹配过的
if displayCount[i1].Matched(i2) {
continue
}
displayCount[i2].Count++
displayCount[i2].MatchedIndex = append(displayCount[i2].MatchedIndex, i1)
displayCount[i1].MatchedIndex = append(displayCount[i1].MatchedIndex, i2)
couple[1] = people[i2]
break
}
res = append(res, couple)
if len(res) == resLength {
break
}
}
return res, nil
}
输出如下:
总结
刚开始进行赛程分配的时候,是自己列表格来排的,感觉有点蠢。。。 还是代码方便些。