go 随机数 rand 的简单使用,年会活动积分赛程设置,小组赛对战顺序

背景

公司年会举办活动,我来组织乒乓球赛,由于人数不是很多而且时间比较紧迫。第一轮采用分组积分赛制,组内人人都会对战一次,程序实现了一下对战顺序。

go 的随机数 rand

gomath/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
}

输出如下:
在这里插入图片描述

总结

刚开始进行赛程分配的时候,是自己列表格来排的,感觉有点蠢。。。 还是代码方便些。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/DisMisPres/article/details/122350348