1
1
import * as React from 'react' ;
2
- import { Col , Input , Label , Row } from 'reactstrap' ;
2
+ import { Col , Input , Label , Row , Table } from 'reactstrap' ;
3
3
import ReactTable from 'react-table'
4
4
import qualityResultList from "../../../auto_generated/qualityResultList.js"
5
5
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
@@ -8,18 +8,45 @@ import "./Summary.scss";
8
8
import Detail from "./Detail" ;
9
9
import ProblemLink from "./ProblemLink" ;
10
10
import Scrollable from "../../../common/Scrollable" ;
11
+ import qualityResultDefinition from 'src/auto_generated/qualityResultDefinition.js' ;
12
+ import Hidable from "../../../common/Hidable" ;
13
+ import Code from "./Code" ;
14
+
15
+
16
+ const filteredQualityResultList = ( filterMethod ) => {
17
+ return qualityResultList . filter ( filterMethod ) ;
18
+ } ;
19
+
20
+
21
+ const isSomethingBad = ( r ) => r . statement_parse . error || r . format_prediction . error ;
22
+
23
+ const getAccuracyData = ( contestNameRe : string ) => {
24
+ const contestFilter = ( r ) => r . contest . contest_id . match ( contestNameRe ) ;
25
+ const allContestCount = filteredQualityResultList ( contestFilter ) . length ;
26
+ const correctContestCount = filteredQualityResultList ( ( r ) => ! isSomethingBad ( r ) && contestFilter ( r ) ) . length ;
27
+ return [ allContestCount , correctContestCount ]
28
+ } ;
29
+
30
+ const [ allRegularContestCount , correctRegularContestCount ] = getAccuracyData ( "(abc|arc|agc)" ) ;
31
+ const [ allAGC , correctAGC ] = getAccuracyData ( "^agc" ) ;
32
+ const [ allARC , correctARC ] = getAccuracyData ( "^arc" ) ;
33
+ const [ allABC , correctABC ] = getAccuracyData ( "^abc" ) ;
11
34
12
35
export default class Summary extends React . Component < { } , {
13
36
showingCode : boolean ,
14
37
detailedSearchMode : boolean ,
38
+ analysisMode : boolean ,
15
39
activeQualityResult : QualityResult | null ,
40
+ analysisQuery : string ,
16
41
} > {
17
42
constructor ( props : any ) {
18
43
super ( props ) ;
19
44
this . state = {
20
45
activeQualityResult : null ,
21
46
detailedSearchMode : false ,
47
+ analysisMode : false ,
22
48
showingCode : false ,
49
+ analysisQuery : 'r.contest.contest_id.match("(abc|agc|arc)")' ,
23
50
}
24
51
}
25
52
@@ -34,6 +61,9 @@ export default class Summary extends React.Component<{}, {
34
61
return this . state . activeQualityResult && problemId === this . state . activeQualityResult . problem . problem_id
35
62
} ;
36
63
64
+ onQueryUpdated = ( query : string ) => {
65
+ this . setState ( { analysisQuery : query } ) ;
66
+ } ;
37
67
38
68
render ( ) {
39
69
const { detailedSearchMode} = this . state ;
@@ -129,23 +159,103 @@ export default class Summary extends React.Component<{}, {
129
159
}
130
160
} ;
131
161
162
+ const analysisFilterMethod = ( r ) => {
163
+ return eval ( this . state . analysisQuery ) ;
164
+ } ;
165
+
166
+ let failedToParse = false ;
167
+
168
+ let resultsForTable ;
169
+ if ( this . state . analysisMode && this . state . analysisQuery . length > 0 ) {
170
+ try {
171
+ resultsForTable = filteredQualityResultList ( analysisFilterMethod ) ;
172
+ } catch {
173
+ resultsForTable = qualityResultList ;
174
+ failedToParse = true ;
175
+ }
176
+ } else {
177
+ resultsForTable = qualityResultList ;
178
+ }
179
+
132
180
133
181
return < React . Fragment >
134
182
< Row >
135
- < h3 > 各問題毎の解析結果</ h3 >
136
183
< Col sm = { 12 } >
184
+ < Row >
185
+ < Col sm = { 6 } >
186
+ < Hidable
187
+ showButtonText = { "入力フォーマット解析成功率を表示" }
188
+ hideButtonText = { "入力フォーマット解析成功率を隠す" }
189
+ visibleByDefault
190
+ >
191
+ < h3 style = { { display : "inline-block" } } > 入力フォーマット解析成功率</ h3 >
192
+ < Table >
193
+ < tbody >
194
+ {
195
+ [
196
+ [ "AGC" , correctAGC , allAGC ] ,
197
+ [ "ARC" , correctARC , allARC ] ,
198
+ [ "ABC" , correctABC , allABC ] ,
199
+ [ "レギュラーコンテスト全体(AGC,ABC,ARC)" , correctRegularContestCount , allRegularContestCount ] ,
200
+ ] . map ( ( [ text , correct , all ] : [ string , number , number ] ) => {
201
+ return < tr key = { text } >
202
+ < th scope = "row" > { text } </ th >
203
+ < td > { correct } / { all } </ td >
204
+ < td > { Math . round ( 100 * correct / all ) } %</ td >
205
+ </ tr >
206
+ } )
207
+ }
208
+ </ tbody >
209
+ </ Table >
210
+ </ Hidable >
211
+
212
+ </ Col >
213
+ </ Row >
214
+ </ Col >
215
+ < Col sm = { 12 } >
216
+ < h3 > 各問題毎の解析結果</ h3 >
217
+ </ Col >
218
+ < Col sm = { 1 } >
137
219
< Label >
138
220
< Input type = "checkbox" checked = { this . state . detailedSearchMode }
139
221
onChange = { ( ) => this . setState ( { detailedSearchMode : ! this . state . detailedSearchMode } ) } />
140
222
詳細検索モード
141
223
</ Label >
142
224
</ Col >
225
+ < Col sm = { 11 } >
226
+ < Label >
227
+ < Input type = "checkbox" checked = { this . state . analysisMode }
228
+ onChange = { ( ) => {
229
+ this . setState ( { analysisMode : ! this . state . analysisMode } )
230
+ } } />
231
+ 解析モード (開発者向け)
232
+ </ Label >
233
+ </ Col >
234
+ { this . state . analysisMode && < Col sm = { 6 } >
235
+ < Hidable
236
+ showButtonText = { "QualityResultの定義を表示" }
237
+ hideButtonText = { "QualityResultの定義を隠す" }
238
+ >
239
+ < Scrollable height = { 300 } >
240
+ < Code code = { qualityResultDefinition } language = { "typescript" } />
241
+ </ Scrollable >
242
+ </ Hidable >
243
+ function filter(r: QualityResult) => { "{ return " }
244
+ < Input style = { { display : "inline-block" } }
245
+ value = { this . state . analysisQuery }
246
+ onChange = { ( e ) => this . onQueryUpdated ( e . target . value ) }
247
+ placeholder = { "javascript condition expression" }
248
+ invalid = { failedToParse }
249
+ />
250
+ { "; }" }
251
+ < p > { resultsForTable . length } 件マッチしました。</ p >
252
+ </ Col > }
143
253
</ Row >
144
254
< Row className = "page-content" >
145
255
< Col sm = { this . state . detailedSearchMode ? 12 : 6 } >
146
256
< ReactTable
147
257
filterable
148
- data = { qualityResultList }
258
+ data = { resultsForTable }
149
259
columns = { columns }
150
260
defaultFilterMethod = { defaultFilterMethod }
151
261
pageSize = { 20 }
0 commit comments