空手の形の試合の得点計算 ~マクロ⑤ 最終順位の決定~

昨日は、同じ順位の点数に最低点を加え、順位を求めることに挑戦した。
そこで今回は、それでも同じ順位の点数に最高点を加え、最終順位を求める方法を模索する。
f:id:Infoment:20181114222553p:plain

といっても、ロジックは昨晩完成している。作成前、あそこまでヤヤコシクなるとは思わなかったが、ヤヤコシクしたのは私だが、とにかく動いた。そこで今日は、サブプロシージャを4つに切り分けることにする。

  1. モジュール変数宣言
  2. メインのマクロ
  3. 最低点を加味した順位算出まで
  4. 最高点を加味した順位算出まで

本当は3と4で一つのユーザー定義関数にしたかったのだが、また脳みそが破裂しそうになったので、ちょっとズルをした。また、最初に準備したものの、作成の過程で使わなかった変数などの整理も行った。

標準モジュール

1.モジュール変数宣言

Option Explicit
    ' 各選手の成績を配列化。
    Dim Player() As KarateRankClass
    ' 最高点と最低点を除く合計点格納用配列。
    Dim TotalSeq_1st() As Variant
    ' 配列のソートなどに用いるクラスモジュール。
    Dim SQC As SeaquenceClass
    ' 同順位の人数確認用辞書。
    Dim RankDict As Dictionary
    ' ループカウンタ。
    Dim i As Long
    ' ループカウンタ。
    Dim j As Long
    ' 合計点の配列作成用コレクション。
    Dim col As Collection

2.メインのマクロ

Sub GetRank()
    Dim PointTable As ListObject
    Set PointTable = ActiveSheet.ListObjects("採点表")
    
    ' 順位のセルをリセット。
    PointTable.ListColumns("順位").DataBodyRange = ""

    ReDim Player(1 To PointTable.DataBodyRange.Rows.Count)
    ReDim TotalSeq_1st(1 To UBound(Player))
    
    ' 各選手のレコードから、各情報を取得。
        For i = 1 To UBound(Player)
            Set Player(i) = New KarateRankClass
            Player(i).myRecord = PointTable.DataBodyRange.Rows(i)
            TotalSeq_1st(i) = Player(i).Total_1st
        Next

    Set SQC = New SeaquenceClass
        
        TotalSeq_1st = SQC.SortSeq(TotalSeq_1st, myDescending)
        
        Call GetRank2
        Call GetRank3
    
    ' 順位をセット
    For i = 1 To UBound(Player)
        PointTable.ListColumns("順位").DataBodyRange.Item(i) = Player(i).Rank_3rd
    Next        
End Sub

3.最低点を加味した順位算出まで

Sub GetRank2()

    Set RankDict = New Dictionary
    
        For i = 1 To UBound(Player)
            Player(i).Rank_1st = SQC.RankSeq(Player(i).Total_1st, TotalSeq_1st)
            If RankDict.Exists(Player(i).Rank_1st) Then
                RankDict(Player(i).Rank_1st) = RankDict(Player(i).Rank_1st) + 1
            Else
                RankDict(Player(i).Rank_1st) = 1
            End If
        Next
    
        For i = 1 To UBound(Player)
            If RankDict.Exists(i) Then
                If RankDict(i) = 1 Then
                    For j = 1 To UBound(Player)
                        If Player(j).Rank_1st = i Then
                            Player(j).Rank_2nd = i
                            Exit For
                        End If
                    Next
                Else
                    Set col = New Collection
                    For j = 1 To UBound(Player)
                        If Player(j).Rank_1st = i Then
                            col.Add Player(j).Total_2nd
                        End If
                    Next
                    For j = 1 To UBound(Player)
                        If Player(j).Rank_1st = i Then
                            Player(j).Rank_2nd = Player(j).Rank_1st + SQC.RankSeq(Player(j).Total_2nd, SQC.ToArray(col)) - 1
                        End If
                    Next
                End If
            End If
        Next
End Sub

4.最高点を加味した順位算出まで

Sub GetRank3()

    Set RankDict = New Dictionary
    
        For i = 1 To UBound(Player)
            If RankDict.Exists(Player(i).Rank_2nd) Then
                RankDict(Player(i).Rank_2nd) = RankDict(Player(i).Rank_2nd) + 1
            Else
                RankDict(Player(i).Rank_2nd) = 1
            End If
        Next
    
        For i = 1 To UBound(Player)
            If RankDict.Exists(i) Then
                If RankDict(i) = 1 Then
                    For j = 1 To UBound(Player)
                        If Player(j).Rank_2nd = i Then
                            Player(j).Rank_3rd = i
                            Exit For
                        End If
                    Next
                Else
                    Set col = New Collection
                    For j = 1 To UBound(Player)
                        If Player(j).Rank_2nd = i Then
                            col.Add Player(j).Total_3rd
                        End If
                    Next
                    For j = 1 To UBound(Player)
                        If Player(j).Rank_2nd = i Then
                            Player(j).Rank_3rd = Player(j).Rank_2nd + SQC.RankSeq(Player(j).Total_3rd, SQC.ToArray(col)) - 1
                        End If
                    Next
                End If
            End If
        Next
End Sub

結果、以下のとおり順位をセットできるまでに至った。
f:id:Infoment:20181114224113p:plain

ちなみに、それでも順位が同じ場合は・・・再試合だったような気がする。

今回は非常に難産だった。しかし今日までの流れ的には、こんがらがっているほど都合がよい。なぜなら今までのそれは全て前振りであり、実はもっと簡単に求める方法があるからだ。

というわけで、次回(最終回)に続きます。

参考まで。