実現したいこと
Glicko2 Rating Systemを実装しようとプログラムを組む過程で、値の2乗が様々なところで必要になったため、
Pow2という、各値の2乗を格納するための構造体を作って
private Pow2 power = new Pow2();
と宣言しました。
以降power.v2のように値を取り出せるようにし、
最後の方に記述してあるupDatePow2()関数を呼び出すことで計算に必要なdeltaやfaiといったfloat型の変数を二乗した値を格納する機能をもたせました。
発生している問題・分からないこと
コードが長いので中略していますが、upDatePow2を他の関数内(自作、Start()などなど)でも呼び出したのですが値が代入されていませんでした。
インスペクターで監視していましたがずっと0のままでした。
エラーメッセージ
error
1----------------
該当のソースコード
C#
1using System.Collections; 2using System.Collections.Generic; 3using Unity.VisualScripting; 4using UnityEngine; 5 6public class Glicko2Rating : MonoBehaviour 7{ 8 [SerializeField] private float TAU = 0.5f; //レーティング変動率 9 [SerializeField] private int INITIAL_RATE = 1500; 10 [SerializeField] private int MAX_RD = 350; 11 [SerializeField] private int MIN_RD = 50; 12 private const float CONST = 173.7178f; 13 14 [System.Serializable] 15 public struct Rating 16 { 17 public float rate; //現在のレート 18 public float RD; //レーティング偏差 19 } 20 21 /// <summary> 22 /// 2乗の値を格納 23 /// </summary> 24 [System.Serializable] 25 public struct Pow2 26 { 27 public float d2; //delta 28 public float f2; //fai 29 public float t2; //TAU 30 public float v2; //Vol 31 public float v22; //vol2 32 } 33 34 [SerializeField] private Pow2 power = new Pow2(); 35 36 public float Vol, vol2; //volatility 37 public Rating pG = new Rating(); //player grade 38 public Rating[] eG; //enemy grade 39 public int[] vicDef; //win = 1 / lose = 0 40 41 //計算用 42 [SerializeField] private float mue, fai, delta, v, a; 43 private float ipu = 0.000001f; 44 45///~~~中略~~~/// 46 47 private void upDatePow2(Pow2 p) 48 { 49 p.d2 = Mathf.Pow(delta, 2); 50 p.f2 = Mathf.Pow(fai, 2); 51 p.t2 = Mathf.Pow(TAU, 2); 52 p.v2 = Mathf.Pow(Vol, 2); 53 p.v22 = Mathf.Pow(vol2, 2); 54 55 //Debug.Log("updated pow2"); 56 } 57}
C#
1using System.Collections; 2using System.Collections.Generic; 3using Unity.VisualScripting; 4using UnityEngine; 5 6public class Glicko2Rating : MonoBehaviour 7{ 8 [SerializeField] private float TAU = 0.5f; //レーティング変動率 9 [SerializeField] private int INITIAL_RATE = 1500; 10 [SerializeField] private int MAX_RD = 350; 11 [SerializeField] private int MIN_RD = 50; 12 private const float CONST = 173.7178f; 13 14 [System.Serializable] 15 public struct Rating 16 { 17 public float rate; //現在のレート 18 public float RD; //レーティング偏差 19 } 20 21 /// <summary> 22 /// 2乗の値を格納 23 /// </summary> 24 [System.Serializable] 25 public struct Pow2 26 { 27 public float d2; //delta 28 public float f2; //fai 29 public float t2; //TAU 30 public float v2; //Vol 31 public float v22; //vol2 32 } 33 34 [SerializeField] private Pow2 power = new Pow2(); 35 36 public float Vol, vol2; //volatility 37 public Rating pG = new Rating(); //player grade 38 public Rating[] eG; //enemy grade 39 public int[] vicDef; //win = 1 / lose = 0 40 41 //計算用 42 [SerializeField] private float mue, fai, delta, v, a; 43 private float ipu = 0.000001f; 44 45 private void Start() 46 { 47 upDatePow2(power); 48 49 //スケール変換 50 mue = ConvertRateScale(pG.rate, true); 51 fai = ConvertRDScale(pG.RD, true); 52 53 Debug.Log("μ = " + mue); 54 Debug.Log("φ = " + fai); 55 56 //敵のスケール変換 57 for (int i = 0; i < eG.Length; i++) 58 { 59 eG[i].rate = ConvertRateScale(eG[i].rate, true); 60 eG[i].RD = ConvertRDScale(eG[i].RD, true); 61 } 62 63 ///Test用 64 CalculateV(); 65 CalculateDelta(); 66 upDateSigma(); 67 upDateRating(); 68 } 69 70 71 private float ConvertRateScale(float r, bool b) 72 { 73 //trueで変換 falseで復元 74 float i; 75 if (b) i = (r - INITIAL_RATE) / CONST; 76 else i = CONST * r + INITIAL_RATE; 77 78 return i; 79 } 80 81 private float ConvertRDScale(float rd, bool b) 82 { 83 //trueで変換 falseで復元 84 float i; 85 if (b) i = rd / CONST; 86 else i = CONST * rd; 87 88 return i; 89 } 90 91 private float Gfai(float f) 92 { 93 float i = Mathf.Sqrt(1 + 3 * (f * f) / 9.8696044f); 94 return (1/i); 95 } 96 97 private float E(float m, float mj, float fj) 98 { 99 float i = 1 + Mathf.Exp(-1 * Gfai(fj) * (m - mj)); 100 return (1/i); 101 } 102 103 private float F(float x) 104 { 105 upDatePow2(power); 106 float e = Mathf.Exp(x); 107 108 float o = e * (power.d2 - power.f2 - v - e); 109 float p = 2 * Mathf.Pow((power.f2 + v + e), 2); 110 float q = (x - a) / power.t2; 111 112 return (o / p) - q; 113 } 114 115 private void CalculateV() 116 { 117 v = 0; 118 119 for (int i = 0; i < eG.Length; i++) 120 { 121 float g = Mathf.Pow(Gfai(eG[i].RD), 2); 122 float e = E(mue, eG[i].rate, eG[i].RD); 123 124 v += g * e * (1 - e); 125 } 126 127 v = 1 / v; 128 Debug.Log("v = " + v); 129 } 130 131 private void CalculateDelta() 132 { 133 delta = 0; 134 135 for (int i = 0; i < eG.Length; i++) 136 { 137 delta += Gfai(eG[i].RD) * (vicDef[i] - E(mue, eG[i].rate, eG[i].RD)); 138 } 139 140 delta *= v; 141 Debug.Log("Δ = " + delta); 142 } 143 144 private void upDateSigma() 145 { 146 float A = a; //log(Vol^2) 147 upDatePow2(power); 148 149 float B, C, fa, fb, fc; 150 151 if(power.d2 > (power.f2 + v)) 152 { 153 B = Mathf.Log(power.d2 - power.f2 - v); 154 } 155 else 156 { 157 int k = 1; 158 while(F(a - k*TAU) < 0) 159 { 160 k = k + 1; 161 } 162 163 B = a - k*TAU; 164 } 165 166 fa = F(A); 167 fb = F(B); 168 169 while(Mathf.Abs(B - A) > ipu) 170 { 171 C = A + (A - B) * fa / (fb - fa); 172 fc = F(C); 173 174 if(fc*fb < 0) 175 { 176 A = B; 177 fa = fb; 178 } 179 else fa /= 2; 180 181 B = C; 182 fb = fc; 183 } 184 185 vol2 = Mathf.Exp(A / 2); 186 } 187 188 private void upDateRating() 189 { 190 upDatePow2(power); 191 192 Debug.Log("v22 = " + power.v22 + ", f2 = " + power.f2); 193 194 float faia = Mathf.Sqrt(power.f2 + power.v22); 195 float faid = 1 / Mathf.Sqrt((1 / Mathf.Pow(faia, 2)) + (1 / v)); 196 Debug.Log("φ' = " + faid); 197 Debug.Log("φ* = " + faia); 198 199 float mue2 = 0; 200 for(int i = 0; i < eG.Length; i++) 201 { 202 float g = Gfai(eG[i].RD); 203 float e = E(mue, eG[i].rate, eG[i].RD); 204 205 mue2 += g * (vicDef[i] - e); 206 207 //Debug.Log("μ' = " + mue2); 208 } 209 mue2 *= Mathf.Pow(faid, 2); 210 mue2 += mue; 211 212 Debug.Log("μ' = " + mue2); 213 214 pG.rate = ConvertRateScale(mue2, false); 215 pG.RD = ConvertRDScale(faid, false); 216 } 217 218 private void upDatePow2(Pow2 p) 219 { 220 p.d2 = Mathf.Pow(delta, 2); 221 p.f2 = Mathf.Pow(fai, 2); 222 p.t2 = Mathf.Pow(TAU, 2); 223 p.v2 = Mathf.Pow(Vol, 2); 224 p.v22 = Mathf.Pow(vol2, 2); 225 226 //Debug.Log("updated pow2"); 227 } 228}
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
http://www.glicko.net/glicko/glicko2.pdf
この論文に記載のある計算例と、数式をそのままプログラムにしています。
プログラムが長いので省略版と、完全版を乗せておきます。
補足
特になし
回答2件
あなたの回答
tips
プレビュー