forked from Tarif-dev/strike
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest-scorecard.js
More file actions
executable file
·259 lines (217 loc) · 8.77 KB
/
test-scorecard.js
File metadata and controls
executable file
·259 lines (217 loc) · 8.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#!/usr/bin/env node
// A CLI tool to test the fantasy points calculation system
// Usage: node test-scorecard.js [path-to-scorecard-json]
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import fs from 'fs';
// Define the scoring rules directly in this file since we're having import issues
const SCORING_RULES = {
// Batting points
RUN: 1, // 1 point per run
BOUNDARY_BONUS: 1, // 1 point for each boundary (4 runs)
SIX_BONUS: 2, // 2 points for each six
HALF_CENTURY_BONUS: 20, // Bonus points for 50+ runs
CENTURY_BONUS: 50, // Bonus points for 100+ runs
DUCK_PENALTY: -5, // Points for a duck (0 runs)
// Strike rate bonus/penalty
SR_BELOW_70_PENALTY: -6, // Points for SR below 70
SR_70_TO_80_PENALTY: -4, // Points for SR between 70-80
SR_80_TO_90_PENALTY: -2, // Points for SR between 80-90
SR_100_TO_120_BONUS: 2, // Points for SR between 100-120
SR_120_TO_140_BONUS: 4, // Points for SR between 120-140
SR_ABOVE_140_BONUS: 6, // Points for SR above 140
// Bowling points
WICKET: 25, // Points per wicket
LBW_BOWLED_BONUS: 8, // Bonus points for LBW or bowled wickets
MAIDEN_OVER: 12, // Points per maiden over
TWO_WICKET_HAUL: 10, // Bonus points for 2 wickets
THREE_WICKET_HAUL: 20, // Bonus points for 3 wickets
FOUR_WICKET_HAUL: 30, // Bonus points for 4 wickets
FIVE_WICKET_HAUL: 50, // Bonus points for 5 wickets
// Economy rate bonus/penalty
ER_BELOW_5_BONUS: 6, // +6 points for ER below 5
ER_5_TO_6_BONUS: 4, // +4 points for ER between 5-6
ER_6_TO_7_BONUS: 2, // +2 points for ER between 6-7
ER_8_TO_9_PENALTY: -2, // -2 points for ER between 8-9
ER_9_TO_10_PENALTY: -4, // -4 points for ER between 9-10
ER_ABOVE_10_PENALTY: -6, // -6 points for ER above 10
// Fielding points
CATCH: 8, // 8 points per catch
STUMPING: 12, // 12 points per stumping
RUN_OUT_DIRECT: 12, // 12 points for direct run out
RUN_OUT_INDIRECT: 6, // 6 points for indirect run out
// Captain and Vice-Captain multipliers
CAPTAIN_MULTIPLIER: 2, // Captain's points are doubled
VICE_CAPTAIN_MULTIPLIER: 1.5 // Vice-captain's points are multiplied by 1.5
};
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Get the scorecard file path from command line args or use the sample file
const scorecardPath = process.argv[2] || join(__dirname, 'src/samples/sample-scorecard.json');
console.log(`Testing fantasy points calculation with scorecard: ${scorecardPath}`);
// Read the sample scorecard file
const scorecardData = JSON.parse(fs.readFileSync(scorecardPath, 'utf8'));
console.log('Processing scorecard data...');
// Simple test to validate the structure
const innings = scorecardData.scorecard;
if (!innings || !Array.isArray(innings)) {
console.error('Invalid scorecard format');
process.exit(1);
}
// Count players
let batsmenCount = 0;
let bowlersCount = 0;
for (const inning of innings) {
batsmenCount += inning.batsman?.length || 0;
bowlersCount += inning.bowler?.length || 0;
}
console.log(`Scorecard contains ${innings.length} innings with ${batsmenCount} batsmen and ${bowlersCount} bowlers`);
// Process all players and calculate their fantasy points
const players = new Map();
// Process batsmen
for (const inning of innings) {
for (const batsman of inning.batsman) {
if (!players.has(batsman.id)) {
players.set(batsman.id, {
id: batsman.id,
name: batsman.name,
performance: {}
});
}
const player = players.get(batsman.id);
// Add batting stats
player.performance.runs = batsman.runs;
player.performance.balls = batsman.balls;
player.performance.fours = batsman.fours;
player.performance.sixes = batsman.sixes;
player.performance.strikeRate = batsman.strkRate ? parseFloat(batsman.strkRate) :
(batsman.runs && batsman.balls ? (batsman.runs / batsman.balls) * 100 : 0);
player.performance.outDec = batsman.outDec;
}
}
// Process bowlers
for (const inning of innings) {
for (const bowler of inning.bowler) {
if (!players.has(bowler.id)) {
players.set(bowler.id, {
id: bowler.id,
name: bowler.name,
performance: {}
});
}
const player = players.get(bowler.id);
// Add bowling stats
player.performance.wickets = bowler.wickets;
player.performance.overs = bowler.overs;
player.performance.maidens = bowler.maidens;
player.performance.bowlingRuns = bowler.runs;
player.performance.economy = bowler.economy ? parseFloat(bowler.economy) :
(bowler.runs && bowler.overs ? bowler.runs / parseFloat(bowler.overs) : 0);
}
}
// Process fielding stats
for (const inning of innings) {
for (const batsman of inning.batsman) {
if (!batsman.outDec) continue;
const dismissal = batsman.outDec.toLowerCase();
// Process catches (c Fielder b Bowler)
if (dismissal.includes("c ")) {
const match = dismissal.match(/c\s+([^b]+)\s+b/i);
if (match && match[1]) {
const fielderName = match[1].trim();
// Find fielder by name
let fielderId = null;
for (const player of players.values()) {
if (player.name.toLowerCase().includes(fielderName.toLowerCase())) {
fielderId = player.id;
break;
}
}
if (fielderId) {
const fielder = players.get(fielderId);
fielder.performance.catches = (fielder.performance.catches || 0) + 1;
}
}
}
// Process stumpings (st Keeper b Bowler)
if (dismissal.includes("st ")) {
const match = dismissal.match(/st\s+([^b]+)\s+b/i);
if (match && match[1]) {
const keeperName = match[1].trim();
// Find keeper by name
let keeperId = null;
for (const player of players.values()) {
if (player.name.toLowerCase().includes(keeperName.toLowerCase())) {
keeperId = player.id;
break;
}
}
if (keeperId) {
const keeper = players.get(keeperId);
keeper.performance.stumpings = (keeper.performance.stumpings || 0) + 1;
}
}
}
// Process run outs (run out Fielder) or (run out Fielder1/Fielder2)
if (dismissal.includes("run out")) {
const match = dismissal.match(/run out\s+\(?([^/)]+)(?:\/([^/)]+))?\)?/i);
if (match) {
// First fielder
if (match[1]) {
const fielderName = match[1].trim();
let fielderId = null;
for (const player of players.values()) {
if (player.name.toLowerCase().includes(fielderName.toLowerCase())) {
fielderId = player.id;
break;
}
}
if (fielderId) {
const fielder = players.get(fielderId);
// Direct run out if there's only one fielder
if (!match[2]) {
fielder.performance.runOutDirect = (fielder.performance.runOutDirect || 0) + 1;
} else {
fielder.performance.runOutIndirect = (fielder.performance.runOutIndirect || 0) + 1;
}
}
}
// Second fielder (indirect run out)
if (match[2]) {
const fielder2Name = match[2].trim();
let fielder2Id = null;
for (const player of players.values()) {
if (player.name.toLowerCase().includes(fielder2Name.toLowerCase())) {
fielder2Id = player.id;
break;
}
}
if (fielder2Id) {
const fielder2 = players.get(fielder2Id);
fielder2.performance.runOutIndirect = (fielder2.performance.runOutIndirect || 0) + 1;
}
}
}
}
}
}
// Calculate LBW/Bowled dismissals for each bowler
for (const inning of innings) {
for (const bowler of inning.bowler) {
const bowlerId = bowler.id;
let lbwBowledCount = 0;
for (const batsman of inning.batsman) {
if (batsman.outDec) {
const dismissal = batsman.outDec.toLowerCase();
if ((dismissal.includes("lbw b ") || dismissal.startsWith("b ")) &&
dismissal.includes(bowler.name.toLowerCase())) {
lbwBowledCount++;
}
}
}
if (lbwBowledCount > 0) {
const player = players.get(bowlerId);
player.performance.lbwBowledCount = (player.performance.lbwBowledCount || 0) + lbwBowledCount;
}
}
}