Files
BABA_YAGA/Assets/Scripts/Elo_System_Spec.txt

98 lines
5.6 KiB
Plaintext
Raw Normal View History

2026-04-29 02:31:15 +07:00
Elo Rating System
AI Handoff Specification <20> Hallucinate Game
1. B?i c?nh & M?c ti<74>u
Game Hallucinate l<> game PvP online 1v1 (real-time), d<>ng Photon Fusion / Unity Relay l<>m backend m?ng. H? th?ng Elo ???c y<>u c?u ?? x?p h?ng ng??i ch?i sau m?i tr?n solo, hi?n th? tr<74>n m<>n h<>nh Profile v<> ?i?u ph?i matchmaking.
Y<EFBFBD>u c?u c?t l<>i:
<EFBFBD> T<>nh to<74>n Elo sau m?i tr?n 1v1 ho<68>n th<74>nh
<EFBFBD> K-factor ??ng theo s? tr?n v<> rating hi?n t?i
<EFBFBD> Persist rating l<>n server (kh<6B>ng ?? client t? t<>nh)
<EFBFBD> Tr? v? rating m?i cho c? 2 ng??i ch?i sau tr?n
<EFBFBD> Hi?n th? l<>n ProfileController.cs qua data binding
2. C<>ng th?c Elo
2.1. Expected Score
E(A) = 1 / (1 + 10 ^ ((RatingB - RatingA) / 400))
E(B) = 1 - E(A)
2.2. Rating m?i
NewRating(A) = OldRating(A) + K * (Result - E(A))
Trong ?<3F> Result: Th?ng = 1.0 | Thua = 0.0 | H<>a = 0.5
2.3. K-Factor ??ng
?i?u ki?n K Value L<> do D??i 30 tr?n (Placement) 40 Rating ch?a ?n ??nh, c?n h?i t? nhanh Rating < 1200 32 Tier th?p <20> thay ??i nhi?u h?n 1200 ? Rating < 2000 24 Tier trung b<>nh <20> c<>n b?ng Rating ? 2000 16 Tier cao <20> ?n ??nh, thay ??i ch?m
2.4. V<> d? t<>nh to<74>n
A (1500) vs B (1200), A th?ng:
E(A) = 1 / (1 + 10^((1200-1500)/400)) = 0.849
E(B) = 0.151
NewRating(A) = 1500 + 24*(1 - 0.849) = 1500 + 3.6 ? 1504
NewRating(B) = 1200 + 32*(0 - 0.151) = 1200 - 4.8 ? 1195
3. Rank Tiers
Rank Rating Range M<>u g?i <20> (UI) Iron < 800 #8A8A8A Bronze 800 <20> 999 #CD7F32 Silver 1000 <20> 1199 #C0C0C0 Gold 1200 <20> 1499 #FFD700 Platinum 1500 <20> 1799 #4DC8A0 Diamond 1800 <20> 2099 #7B6EE8 Master ? 2100 #E84D8A
Rating kh?i ??u (m?c ??nh): 1000. Rating s<>n (floor): 100 <20> kh<6B>ng xu?ng d??i gi<67> tr? n<>y.
4. Placement Matches
<EFBFBD> 30 tr?n ??u ti<74>n l<> Placement Period (gamesPlayed < 30)
<EFBFBD> K = 40 trong giai ?o?n n<>y ?? rating h?i t? nhanh v? ?<3F>ng v? tr<74>
<EFBFBD> T<>y ch?n: kh<6B>ng hi?n th? rank badge trong 30 tr?n ??u, ch? hi?n th? '?' ho?c 'Unranked'
<EFBFBD> Sau tr?n 30, K-factor chuy?n sang b?ng ??ng ? m?c 2.3
5. Ki?n tr<74>c & Lu?ng d? li?u
5.1. Nguy<75>n t?c quan tr?ng
KH<EFBFBD>NG ?? client t? t<>nh Elo r?i g?i l<>n. Ph?i t<>nh tr<74>n Host/Server ?? tr<74>nh cheat.
5.2. Lu?ng x? l<>
B??c Th?c hi?n b?i M<> t? 1 Client A & B Tr?n k?t th<74>c, g?i k?t qu? l<>n Host qua RPC 2 Host (Photon Fusion) Nh?n k?t qu?, x<>c minh h?p l? 3 Host G?i EloSystem.Calculate() v?i rating c?a 2 ng??i 4 Host ? Backend G?i rating m?i l<>n server (UGS / Photon Cloud / custom) 5 Backend Persist v<>o database, tr? v? k?t qu? 6 Host ? Client Broadcast rating m?i v? cho c? 2 client qua RPC 7 Client ProfileController c?p nh?t UI v?i rating m?i
5.3. File c?n t?o
File V? tr<74> Tr<54>ch nhi?m EloSystem.cs /Assets/Scripts/Game/ Pure static class <20> c<>ng th?c Elo, kh<6B>ng dependency EloData.cs /Assets/Scripts/Game/ Struct/class l?u RatingResult (newRatingA, newRatingB, delta) MatchResultRPC.cs /Assets/Scripts/Network/ Photon RPC g?i/nh?n k?t qu? tr?n ProfileController.cs /Assets/Scripts/UI/ ?<3F> c<> <20> th<74>m h<>m UpdateEloDisplay(int newRating, int delta)
6. C# Implementation Spec
6.1. EloSystem.cs
public static class EloSystem {
public static EloResult Calculate(
int ratingA, int ratingB,
int gamesPlayedA, int gamesPlayedB,
float resultA) // 1=win, 0=lose, 0.5=draw
{
float eA = 1f / (1f + Mathf.Pow(10f, (ratingB - ratingA) / 400f));
int kA = GetK(ratingA, gamesPlayedA);
int kB = GetK(ratingB, gamesPlayedB);
int nA = Mathf.Max(100, Mathf.RoundToInt(ratingA + kA * (resultA - eA)));
int nB = Mathf.Max(100, Mathf.RoundToInt(ratingB + kB * ((1-resultA) - (1-eA))));
return new EloResult(nA, nB, nA - ratingA, nB - ratingB);
}
private static int GetK(int r, int g) =>
g < 30 ? 40 : r < 1200 ? 32 : r < 2000 ? 24 : 16;
}
6.2. EloResult struct
public readonly struct EloResult {
public int NewRatingA, NewRatingB, DeltaA, DeltaB;
// Constructor...
}
6.3. ProfileController <20> th<74>m h<>m
public void UpdateEloDisplay(int newRating, int delta) {
root.Q<Label>("EloLabel").text = newRating.ToString();
root.Q<Label>("EloDelta").text = (delta >= 0 ? "+" : "") + delta;
root.Q<Label>("RankLabel").text = EloSystem.GetRank(newRating);
}
7. T<>ch h?p v<>o Profile UI
C<EFBFBD>c element UXML c?n c<> trong Profile.uxml:
Element Name Type Hi?n th? EloLabel Label Rating hi?n t?i, VD: 1504 EloDelta Label Thay ??i sau tr?n, VD: +12 ho?c -8 (m<>u xanh/??) RankLabel Label T<>n rank, VD: Gold WinRateBar ProgressBar value = winRate (0.0 - 1.0) WinRateText Label VD: 58.3% GamesPlayed Label T?ng s? tr?n
CSS class g?i <20> cho EloDelta:
.elo-delta-positive { color: #4DC8A0; } /* teal <20> th?ng */
.elo-delta-negative { color: #E84D8A; } /* h?ng <20> thua */
8. Checklist tri?n khai
# Task File li<6C>n quan Done? 1 T?o EloSystem.cs v?i Calculate() v<> GetRank() EloSystem.cs [ ] 2 T?o EloResult struct EloData.cs [ ] 3 Th<54>m RPC g?i k?t qu? tr?n l<>n Host MatchResultRPC.cs [ ] 4 Host g?i EloSystem.Calculate() sau khi nh?n RPC MatchResultRPC.cs [ ] 5 Persist rating l<>n backend Backend / Cloud Save [ ] 6 Host broadcast EloResult v? client qua RPC MatchResultRPC.cs [ ] 7 ProfileController.UpdateEloDisplay() nh?n data m?i ProfileController.cs [ ] 8 Th<54>m c<>c UXML element v<>o Profile.uxml Profile.uxml [ ] 9 Style EloDelta (xanh/??) trong Global.uss Global.uss [ ] 10 Unit test EloSystem v?i c<>c tr??ng h?p bi<62>n Test/ [ ]
9. L?u <20> & Edge Cases
<EFBFBD> Tr?n b? disconnect gi?a ch?ng: kh<6B>ng t<>nh Elo, ho?c t<>nh thua cho b<>n disconnect (quy?t ??nh t<>y game design)
<EFBFBD> Tr?n qu<71> ng?n (< X gi<67>y): c<> th? b? qua ?? tr<74>nh farming/griefing
<EFBFBD> Rating floor = 100: Mathf.Max(100, newRating) <20> ?<3F> c<> trong spec
<EFBFBD> Kh<4B>ng c<> rating cap (ceiling) <20> Master+ ti?p t?c t?ng v<> h?n
<EFBFBD> H<>a (draw): resultA = 0.5f <20> game c?n quy?t ??nh c<> h? tr? kh<6B>ng
<EFBFBD> Backend sync: l?u c? gamesPlayed c<>ng v?i rating ?? K-factor t<>nh ?<3F>ng