java实现羽毛球比赛中的八人转玩法

一、八人转规则

  • 8个人参赛每人参赛7场,每个人分别和其余的人搭档一次,对手是随机配对。
  • 每个人不会和自己搭档过的人再搭。
  • 搭档不能是自己,对手不能是自己。

二、生成所有搭档列表

/**
     * 生成搭档列表
     * @param peopleList 参赛人列表
     * @param roundNum 每人场次 默认 人数-1
     * @return 所有搭档列表
     */
    public static<T> List<List<T>> getPartnerList(List<T> peopleList, int roundNum) {
        //总人数
        int totalNum = peopleList.size();
        // 所有有可能搭档的组
        List<List<T>> partnerGroupList = new ArrayList<>();
        // 出场的搭档数组
        List<List<T>> partnerGroupListReal = new ArrayList<>();
        // 记录每人上场的次数对象
        Map<T, Integer> pShouldRoundNum = new HashMap<>();
        int groundNum = 0;
        for (int i = 0; i < peopleList.size(); i++) {
            // 预先定下前面的搭档池数
            pShouldRoundNum.put(peopleList.get(i), peopleList.size() - 1);
        }
        // 整除
        if ((totalNum * roundNum) % 4 == 0) {
            groundNum = (int) Math.floor((double) (peopleList.size() * roundNum) / 2);
            for (int i = 0; i < peopleList.size(); i++) {
                T e = peopleList.get(i);
                for (int j = i + 1; j < peopleList.size(); j++) {
                    T e1 = peopleList.get(j);
                    List<T> partnerGroup = new ArrayList<>();
                    partnerGroup.add(e);
                    partnerGroup.add(e1);
                    // 将搭档添加到搭档组列表中
                    partnerGroupList.add(partnerGroup);
                }
            }
            // 将所有搭档组添加到实际搭档列表中
            partnerGroupListReal.addAll(partnerGroupList);
            // 必须每人多打几场
            if (roundNum > peopleList.size() - 1) {
            	// 创建临时搭档组列表,用于随机选择搭档组进行调整
                List<List<T>> tempPartnerGroupList = new ArrayList<>(partnerGroupList);
                boolean flag = true;
                Random rand = new Random();
                while (flag) {
                    // 从临时搭档组列表中随机选择一个搭档组的索引
                    int index = rand.nextInt(tempPartnerGroupList.size());
                    // 从临时搭档组列表中移除选中的搭档组
                    List<T> partnerGroupListRealOne = tempPartnerGroupList.remove(index);
                    // 获取第一个选手
                    T p1 = partnerGroupListRealOne.get(0);
                    // 获取第二个选手
                    T p2 = partnerGroupListRealOne.get(1);
                    // 如果两个选手还未达到指定场次,则将该搭档组加入实际搭档列表中,并更新他们的场次计数器
                    if (pShouldRoundNum.get(p1) < roundNum && pShouldRoundNum.get(p2) < roundNum) {
                        partnerGroupListReal.add(partnerGroupListRealOne);
                        pShouldRoundNum.put(p1, pShouldRoundNum.get(p1) + 1);
                        pShouldRoundNum.put(p2, pShouldRoundNum.get(p2) + 1);
                    }
                    if (partnerGroupListReal.size() == groundNum) {
                        flag = false;
                    }
                }
            }
            return partnerGroupListReal;
        } else {
            return new ArrayList<>();
        }
    }

二、生成对战表

/**
     * 生成对战表
     * @param peopleList 参赛人列表
     * @param roundNum 每人场次 默认 人数-1
     * @return 对战信息
     */
    public static <T> List<List<List<T>>> getBattleList(List<T> peopleList, int roundNum) {
        while ((peopleList.size() * roundNum) % 4 != 0) {
            roundNum++;
        }
        //生成搭档池子
        List<List<T>> matchListPoor = getPartnerList(peopleList, roundNum);
        //总场次
        int allRound = matchListPoor.size() / 2;
        List<List<List<T>>> res = new ArrayList<>();
        List<List<T>> rivalry = new ArrayList<>();
        int round = 0;
        while (matchListPoor.size() > 0) {
            List<T> per = matchListPoor.get(0);
            matchListPoor.remove(0);
            if (rivalry.size() == 0) {
                rivalry.add(per);
                round = 1;
            } else if (!rivalry.get(0).contains(per.get(0)) && !rivalry.get(0).contains(per.get(1))) {
                rivalry.add(per);
            } else {
                matchListPoor.add(per);
                round = 2;
            }
            if (rivalry.size() == 2) {
                res.add(Arrays.asList(rivalry.get(0), rivalry.get(1)));
                rivalry.clear();
            }
            if (matchListPoor.size() == 1 && round == 2) {
                matchListPoor.addAll(rivalry);
                for (int j = 0; j < res.size(); j++) {
                    if (!res.get(j).get(0).contains(matchListPoor.get(0).get(0)) && !res.get(j).get(0).contains(matchListPoor.get(0).get(0))) {
                        List<T> temp = res.get(j).get(1);
                        res.get(j).set(1, matchListPoor.get(0));
                        matchListPoor.set(0, temp);
                        if (!matchListPoor.get(0).contains(matchListPoor.get(1).get(0)) && !matchListPoor.get(0).contains(matchListPoor.get(1).get(1))) {
                            res.add(Arrays.asList(matchListPoor.get(0), matchListPoor.get(1)));
                            break;
                        }
                    }
                }
            }
            if (res.size() == allRound) {
                break;
            }
        }
        return sort(res);
    }

三、排序(避免有人连打多场)

生成的对战表是随机的,所以有可能会出现有人连打好几场

/**
     * 排序(避免有人连打多场)
     * @param oldMatchList 初始对战表
     * @return 排序后对战表
     */
    private static <T> List<List<List<T>>> sort(List<List<List<T>>> oldMatchList) {
        //排序后新对战表
        List<List<List<T>>> newMatchList = new ArrayList<>();
        newMatchList.add(oldMatchList.get(0));
        oldMatchList.remove(0);

        while (oldMatchList.size() >0){
            //新对战表最后一组
            List<List<T>> lastList = newMatchList.get(newMatchList.size() - 1);
            //最后一组的人
            List<T> lastMember = new ArrayList<>();
            for (List<T> list : lastList) {
                lastMember.addAll(list);
            }
            for (int i = oldMatchList.size()-1; i >=0; i--) {
                //旧对战表中每一局的人
                List<T> member = new ArrayList<>();
                for (List<T> list : oldMatchList.get(i)) {
                    member.addAll(list);
                }
                if (!member.contains(lastMember.get(0)) && !member.contains(lastMember.get(1)) && !member.contains(lastMember.get(2)) && !member.contains(lastMember.get(3))){
                    newMatchList.add(oldMatchList.get(i));
                    oldMatchList.remove(i);
                    break;
                }
                if (i == 0){
                    newMatchList.add(oldMatchList.get(i));
                    oldMatchList.remove(i);
                    break;
                }
            }
        }
        return newMatchList;
    }

四、测试

public static void main(String[] args) {
        List<String> peopleList = new ArrayList<>(Arrays.asList("李逍遥","张无忌","张三丰","杨不悔","周芷若","俞岱岩","宋远桥","常玉春"));
        List<List<List<String>>> battleList = getBattleList(peopleList, 7);
        List<String> battle = new ArrayList<>();
        for (int i = 0; i < battleList.size(); i++) {
            battle.add(String.format("第%s场: %s VS %s",i+1,String.join("/",battleList.get(i).get(0)),String.join("/",battleList.get(i).get(1))));
        }
        battle.forEach(System.out::println);
    }

运行结果
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值