再びトーナメント表作成 ➈-5 特定名簿からの作成

特定名簿からのトーナメント作成ツールを、少しずつ紹介中。
本日も、昨日の続きから。

昨日は「前半と後半の二回に分ける」としたが、それでも長かった。
ということで、今日は中盤のご紹介。同一サブプロシージャの途中から始まるため分り難くなっているが、最後に改めてまとめて紹介するため、今はご勘弁。

        Do
            With New VBAProject.Tournament
                ' トーナメント作成の初期設定。
                ' 前回順位の最大値を取得し、それ以降をランダムに並び替える。
                .init Tb.ListColumns(列名.enNo).DataBodyRange, True, _
                      WorksheetFunction.Max(Tb.ListColumns(列名.en前回形順位).DataBodyRange) + 1
                      
                    ' トーナメントの配列取得。
                    arr = TournamentArray(.TournamentSortedOrderArray, match_type)
                    
                    ' 同所属対戦を不可とするブロック単位で、同所属の対戦が無いかを確認する。
                    For i = 1 To UBound(arr) Step DupTrial
                        
                        ' 重複の有無は辞書で行う。そのため、ループに入るたびに辞書を空にしている。
                        Dict.RemoveAll
                        
                        For j = 0 To DupTrial - 1
                            
                            ' 一回戦においては空欄=シードが存在するため、それ以外の場合で評価している。
                            ' keyの重複を不可とする仕様を利用しているため、itemは不問。今回はTrueとした。
                            If arr(i + j, 列名.en所属) <> vbNullString Then
                                If Not Dict.Exists(arr(i + j, 列名.en所属)) Then
                                    Dict(arr(i + j, 列名.en所属)) = True
                                Else
                                    ' 重複があった場合は、重複回数をカウントアップ。
                                    DuplicateTimes = DuplicateTimes + 1
                                End If
                            End If
                        Next
                    Next
                    
                    ' 重複回数が重複許容回数を下回る場合であって、且つ組手のトーナメントを作成している場合、
                    ' 一回戦で形トーナメントと同じ選手と対戦していないかを確認。対戦している場合は再組合せ。
                    If DuplicateTimes < AllowableDuplicateTimes And match_type = en組手 Then
                        For i = 1 To UBound(arr) Step 2
                            If DDict.Exists(arr(i, 列名.enNo)) Then
                                If DDict(arr(i, 列名.enNo)) = arr(i + 1, 列名.enNo) Then
                                    ' 同じ選手と対戦している場合、重複回数を強制的に重複許容回数とすることで
                                    ' 再抽選させる。
                                    DuplicateTimes = AllowableDuplicateTimes
                                    Exit For
                                End If
                            End If
                        Next
                    End If
                    
                    ' ループ回数が最大値を超えた場合の処理。
                    If LoopCount > LoopCountMax Then
                        MsgboxResult = MsgBox("組み合わせをランダムに" & LoopCountMax & "回作成しましたが、同所属の対戦を回避できませんでした。" & vbNewLine & _
                                                         "このままの組み合わせで継続しますか?", vbYesNo, "処理継続確認")
                        If MsgboxResult = vbNo Then
                            MsgBox "処理を中断しました。"
                            Exit Sub
                        Else
                            ' 同所属の対戦があるままトーナメント作成。人の手で最終調整。
                            .CreateTournament
                            Exit Do
                        End If
                    
                    ' 重複回数が許容重複回数を下回っている場合、トーナメント作成の条件達成。
                    ' トーナメントを作成してループを抜ける。
                    ElseIf DuplicateTimes < AllowableDuplicateTimes Then
                        .CreateTournament
                        Exit Do
                    End If
            End With
            LoopCount = LoopCount + 1
            
            ' 重複回数の初期化。
            DuplicateTimes = 0
        Loop

以下の条件においては、どうしても一回戦での同一所属対戦が増えてしまう。

  1. 選手数が多く、且つ、参加団体数が少ない場合。
  2. 2^nよりもほんの少しだけ、参加人数が多い場合。

例えば2^4=16人より一人多い17人の場合について考えてみる。この場合、一回戦は1組のみで、残りの対戦はすべてシードとなる。

そのため、一回戦だけ同所属対戦を回避しても、どうしても二回戦(実質一回戦)での同一所属対戦が発生してしまう。
例)一回戦シードのため、二回戦で長野県同士で対戦となる。

これを回避すべく、昨日紹介範囲になるが、4人一組で同一部門の人がいないことを条件としてみた。

次回に続きます。

参考まで。