98 lines
5.6 KiB
Plaintext
98 lines
5.6 KiB
Plaintext
Elo Rating System
|
||
AI Handoff Specification — Hallucinate Game
|
||
|
||
1. B?i c?nh & M?c tiê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ên màn hình Profile và ?i?u ph?i matchmaking.
|
||
|
||
Yêu c?u c?t lõi:
|
||
• Tính toán Elo sau m?i tr?n 1v1 hoàn thành
|
||
• K-factor ??ng theo s? tr?n và rating hi?n t?i
|
||
• Persist rating lên server (không ?? client t? tính)
|
||
• Tr? v? rating m?i cho c? 2 ng??i ch?i sau tr?n
|
||
• 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 ?ó 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 — thay ??i nhi?u h?n
|
||
1200 ? Rating < 2000
|
||
24
|
||
Tier trung bình — cân b?ng
|
||
Rating ? 2000
|
||
16
|
||
Tier cao — ?n ??nh, thay ??i ch?m
|
||
|
||
2.4. Ví d? tính toá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 ý (UI)
|
||
Iron
|
||
< 800
|
||
#8A8A8A
|
||
Bronze
|
||
800 – 999
|
||
#CD7F32
|
||
Silver
|
||
1000 – 1199
|
||
#C0C0C0
|
||
Gold
|
||
1200 – 1499
|
||
#FFD700
|
||
Platinum
|
||
1500 – 1799
|
||
#4DC8A0
|
||
Diamond
|
||
1800 – 2099
|
||
#7B6EE8
|
||
Master
|
||
? 2100
|
||
#E84D8A
|
||
|
||
Rating kh?i ??u (m?c ??nh): 1000. Rating sàn (floor): 100 — không xu?ng d??i giá tr? này.
|
||
|
||
4. Placement Matches
|
||
• 30 tr?n ??u tiên là Placement Period (gamesPlayed < 30)
|
||
• K = 40 trong giai ?o?n này ?? rating h?i t? nhanh v? ?úng v? trí
|
||
• Tùy ch?n: không hi?n th? rank badge trong 30 tr?n ??u, ch? hi?n th? '?' ho?c 'Unranked'
|
||
• Sau tr?n 30, K-factor chuy?n sang b?ng ??ng ? m?c 2.3
|
||
|
||
5. Ki?n trúc & Lu?ng d? li?u
|
||
5.1. Nguyên t?c quan tr?ng
|
||
KHÔNG ?? client t? tính Elo r?i g?i lên. Ph?i tính trên Host/Server ?? trá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ú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í
|
||
Trách nhi?m
|
||
EloSystem.cs
|
||
/Assets/Scripts/Game/
|
||
Pure static class — công th?c Elo, khô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/
|
||
?ã có — thê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 — thê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á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 ý cho EloDelta:
|
||
.elo-delta-positive { color: #4DC8A0; } /* teal — th?ng */
|
||
.elo-delta-negative { color: #E84D8A; } /* h?ng — thua */
|
||
|
||
8. Checklist tri?n khai
|
||
#
|
||
Task
|
||
File liên quan
|
||
Done?
|
||
1
|
||
T?o EloSystem.cs v?i Calculate() và GetRank()
|
||
EloSystem.cs
|
||
[ ]
|
||
2
|
||
T?o EloResult struct
|
||
EloData.cs
|
||
[ ]
|
||
3
|
||
Thê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ê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ên
|
||
Test/
|
||
[ ]
|
||
|
||
9. L?u ý & Edge Cases
|
||
• Tr?n b? disconnect gi?a ch?ng: không tính Elo, ho?c tính thua cho bên disconnect (quy?t ??nh tùy game design)
|
||
• Tr?n quá ng?n (< X giây): có th? b? qua ?? tránh farming/griefing
|
||
• Rating floor = 100: Mathf.Max(100, newRating) — ?ã có trong spec
|
||
• Không có rating cap (ceiling) — Master+ ti?p t?c t?ng vô h?n
|
||
• Hòa (draw): resultA = 0.5f — game c?n quy?t ??nh có h? tr? không
|
||
• Backend sync: l?u c? gamesPlayed cùng v?i rating ?? K-factor tính ?úng
|