1
+ import { useMemo } from "react" ;
2
+ import useSWR from "swr" ;
1
3
import { fetchSubmissionsFromDatabaseAndServer } from "../database/SubmissionsDB" ;
2
4
import Contest , { isContest } from "../interfaces/Contest" ;
3
5
import { isContestParticipation } from "../interfaces/ContestParticipation" ;
@@ -15,9 +17,9 @@ import { isSubmission } from "../interfaces/Submission";
15
17
import { isUserRankEntry , UserRankEntry } from "../interfaces/UserRankEntry" ;
16
18
import { clipDifficulty , isValidResult } from "../utils" ;
17
19
import { toChunks } from "../utils/Chunk" ;
20
+ import { classifyContest } from "../utils/ContestClassifier" ;
18
21
import { ratingInfoOf } from "../utils/RatingInfo" ;
19
22
import { hasPropertyAsType , isString } from "../utils/TypeUtils" ;
20
- import { useSWRData } from "./index" ;
21
23
22
24
const STATIC_API_BASE_URL = "https://kenkoooo.com/atcoder/resources" ;
23
25
const PROXY_API_URL = "https://kenkoooo.com/atcoder/proxy" ;
@@ -65,9 +67,7 @@ function fetchTypedArray<T>(
65
67
}
66
68
67
69
const useRankingV3 = ( url : string ) => {
68
- return useSWRData ( url , ( u ) =>
69
- fetchTypedArray < RankingEntry > ( u , isRankingEntry )
70
- ) ;
70
+ return useSWR ( url , ( u ) => fetchTypedArray < RankingEntry > ( u , isRankingEntry ) ) ;
71
71
} ;
72
72
73
73
export const useACRanking = ( from : number , to : number ) => {
@@ -79,7 +79,7 @@ export const useUserACRank = (user: string) => {
79
79
const url = `${ ATCODER_API_URL } /v3/user/ac_rank?user=${ encodeURIComponent (
80
80
user
81
81
) } `;
82
- return useSWRData ( url , ( url ) =>
82
+ return useSWR ( url , ( url ) =>
83
83
fetchTypedValue < UserRankEntry > ( url , isUserRankEntry )
84
84
) ;
85
85
} ;
@@ -93,7 +93,7 @@ export const useUserStreakRank = (user: string) => {
93
93
const url = `${ ATCODER_API_URL } /v3/user/streak_rank?user=${ encodeURIComponent (
94
94
user
95
95
) } `;
96
- return useSWRData ( url , ( url ) =>
96
+ return useSWR ( url , ( url ) =>
97
97
fetchTypedValue < UserRankEntry > ( url , isUserRankEntry )
98
98
) ;
99
99
} ;
@@ -107,26 +107,40 @@ export const useUserSumRank = (user: string) => {
107
107
const url = `${ ATCODER_API_URL } /v3/user/rated_point_sum_rank?user=${ encodeURIComponent (
108
108
user
109
109
) } `;
110
- return useSWRData ( url , ( url ) =>
110
+ return useSWR ( url , ( url ) =>
111
111
fetchTypedValue < UserRankEntry > ( url , isUserRankEntry )
112
112
) ;
113
113
} ;
114
114
115
115
export const useMergedProblemMap = ( ) => {
116
+ const fetcher = ( url : string ) => fetchTypedArray ( url , isMergedProblem ) ;
116
117
const url = STATIC_API_BASE_URL + "/merged-problems.json" ;
117
- return useSWRData ( url , ( url ) =>
118
- fetchTypedArray ( url , isMergedProblem ) . then ( ( problems ) =>
119
- problems . reduce ( ( map , problem ) => {
118
+ const problems = useSWR ( url , fetcher ) ;
119
+ const contests = useContestMap ( ) ;
120
+
121
+ const map = useMemo ( ( ) => {
122
+ const map = new Map < ProblemId , MergedProblem > ( ) ;
123
+ problems . data ?. forEach ( ( problem ) => {
124
+ const contest = contests ?. get ( problem . contest_id ) ;
125
+ if ( ! contest ) {
126
+ return ;
127
+ }
128
+
129
+ const contestType = classifyContest ( contest ) ;
130
+ if ( contestType === "AHC" ) {
131
+ map . set ( problem . id , { ...problem , point : undefined } ) ;
132
+ } else {
120
133
map . set ( problem . id , problem ) ;
121
- return map ;
122
- } , new Map < ProblemId , MergedProblem > ( ) )
123
- )
124
- ) ;
134
+ }
135
+ } ) ;
136
+ return map ;
137
+ } , [ contests , problems ] ) ;
138
+ return { data : map } ;
125
139
} ;
126
140
127
141
export const useLangList = ( ) => {
128
142
const url = `${ ATCODER_API_URL } /v3/language_list` ;
129
- return useSWRData ( url , ( url ) => fetchTypedArray ( url , isString ) ) ;
143
+ return useSWR ( url , ( url ) => fetchTypedArray ( url , isString ) ) ;
130
144
} ;
131
145
132
146
export const useOneLangRanking = (
@@ -156,8 +170,8 @@ export const useFirstRanking = () => {
156
170
export const useRatingInfo = ( user : string ) => {
157
171
const url = `${ PROXY_API_URL } /users/${ user } /history/json` ;
158
172
const history =
159
- useSWRData ( url , ( url ) => fetchTypedArray ( url , isContestParticipation ) )
160
- ?. data ?? [ ] ;
173
+ useSWR ( url , ( url ) => fetchTypedArray ( url , isContestParticipation ) ) ?. data ??
174
+ [ ] ;
161
175
return ratingInfoOf ( history ) ;
162
176
} ;
163
177
@@ -171,26 +185,24 @@ export const useMultipleUserSubmissions = (userIds: UserId[]) => {
171
185
const arrays = await Promise . all ( promises ) ;
172
186
return arrays . flat ( ) ;
173
187
} ;
174
- const users = userIds . join ( "," ) ;
175
- return useSWRData ( `multiple-user-submission ${ users } ` , ( s ) => {
176
- const users = s . split ( " " ) [ 1 ] ;
177
- return fetcher ( users . split ( "," ) ) ;
178
- } ) ;
188
+ return useSWR ( { key : "multiple-user-submission" , userIds } , ( { userIds } ) =>
189
+ fetcher ( userIds )
190
+ ) ;
179
191
} ;
180
192
181
193
export const useContests = ( ) => {
182
194
const url = STATIC_API_BASE_URL + "/contests.json" ;
183
- return useSWRData ( url , ( url ) => fetchTypedArray ( url , isContest ) ) ;
195
+ return useSWR ( url , ( url ) => fetchTypedArray ( url , isContest ) ) ;
184
196
} ;
185
197
186
198
export const useProblems = ( ) => {
187
199
const url = STATIC_API_BASE_URL + "/problems.json" ;
188
- return useSWRData ( url , ( url ) => fetchTypedArray ( url , isProblem ) ) . data ;
200
+ return useSWR ( url , ( url ) => fetchTypedArray ( url , isProblem ) ) . data ;
189
201
} ;
190
202
191
203
const useContestProblemList = ( ) => {
192
204
const url = STATIC_API_BASE_URL + "/contest-problem.json" ;
193
- return useSWRData ( url , ( url ) =>
205
+ return useSWR ( url , ( url ) =>
194
206
fetchTypedArray (
195
207
url ,
196
208
(
@@ -258,29 +270,58 @@ export const useProblemMap = () => {
258
270
} ;
259
271
260
272
export const useProblemModelMap = ( ) => {
261
- const fetcher = ( url : string ) =>
262
- fetch ( url )
263
- . then ( ( r ) => r . json ( ) )
264
- . then ( ( obj : { [ p : string ] : unknown } ) =>
265
- Object . entries ( obj )
266
- . filter ( ( entry ) : entry is [ string , ProblemModel ] =>
267
- isProblemModel ( entry [ 1 ] )
268
- )
269
- . reduce ( ( map , [ problemId , problemModel ] ) => {
270
- if ( problemModel . difficulty === undefined ) {
271
- map . set ( problemId , problemModel ) ;
272
- } else {
273
- map . set ( problemId , {
274
- ...problemModel ,
275
- difficulty : clipDifficulty ( problemModel . difficulty ) ,
276
- rawDifficulty : problemModel . difficulty ,
277
- } ) ;
278
- }
279
- return map ;
280
- } , new Map < ProblemId , ProblemModel > ( ) )
281
- ) ;
273
+ const fetcher = async ( url : string ) => {
274
+ const response = await fetch ( url ) ;
275
+ const result : unknown = await response . json ( ) ;
276
+ if ( typeof result !== "object" || ! result ) {
277
+ return [ ] as { problemId : ProblemId ; model : ProblemModel } [ ] ;
278
+ }
279
+
280
+ const models = [ ] as { problemId : ProblemId ; model : ProblemModel } [ ] ;
281
+ Object . entries ( result ) . forEach ( ( [ key , value ] ) => {
282
+ if ( isProblemModel ( value ) ) {
283
+ models . push ( { problemId : key , model : value } ) ;
284
+ }
285
+ } ) ;
286
+ return models ;
287
+ } ;
288
+
282
289
const url = STATIC_API_BASE_URL + "/problem-models.json" ;
283
- return useSWRData ( url , fetcher ) . data ;
290
+ const problemModels = useSWR ( url , fetcher ) ;
291
+ const contests = useContestMap ( ) ;
292
+ const problems = useProblemMap ( ) ;
293
+
294
+ const modelMap = useMemo ( ( ) => {
295
+ const map = new Map < ProblemId , ProblemModel > ( ) ;
296
+ problemModels . data ?. forEach ( ( { problemId, model } ) => {
297
+ const problem = problems ?. get ( problemId ) ;
298
+ if ( ! problem ) {
299
+ return ;
300
+ }
301
+ const contest = contests ?. get ( problem . contest_id ) ;
302
+ if ( ! contest ) {
303
+ return ;
304
+ }
305
+ const contestType = classifyContest ( contest ) ;
306
+ if ( contestType === "AHC" ) {
307
+ return ;
308
+ }
309
+
310
+ if ( model . difficulty === undefined ) {
311
+ map . set ( problemId , model ) ;
312
+ } else {
313
+ map . set ( problemId , {
314
+ ...model ,
315
+ difficulty : clipDifficulty ( model . difficulty ) ,
316
+ rawDifficulty : model . difficulty ,
317
+ } ) ;
318
+ }
319
+ } ) ;
320
+
321
+ return map ;
322
+ } , [ problemModels , problems , contests ] ) ;
323
+
324
+ return modelMap ;
284
325
} ;
285
326
286
327
export const useVirtualContestSubmissions = (
@@ -348,10 +389,10 @@ export const useVirtualContestSubmissions = (
348
389
: 1_000_000_000 ;
349
390
350
391
const customKey = serialize ( users , problems ) ;
351
- return useSWRData ( customKey , fetcher , { refreshInterval } ) ;
392
+ return useSWR ( customKey , fetcher , { refreshInterval } ) ;
352
393
} ;
353
394
354
395
export const useRecentSubmissions = ( ) => {
355
396
const url = `${ ATCODER_API_URL } /v3/recent` ;
356
- return useSWRData ( url , ( url ) => fetchTypedArray ( url , isSubmission ) ) ;
397
+ return useSWR ( url , ( url ) => fetchTypedArray ( url , isSubmission ) ) ;
357
398
} ;
0 commit comments