@@ -12,9 +12,18 @@ function mustGetElementById(id: string): HTMLElement {
12
12
return e ;
13
13
}
14
14
15
- type In1 = [ string , string ] [ ] ;
16
- type In2 = [ string ] [ ] ;
17
- type In3 = [ string , string , string ] [ ] ;
15
+ declare const nominalIdentifier : unique symbol ;
16
+ type Nominal < T , Identifier > = T & { [ nominalIdentifier ] : Identifier } ;
17
+
18
+ type StudentId = Nominal < string , "StudentId" > ;
19
+ type CourseId = Nominal < string , "CourseId" > ;
20
+ type Email = Nominal < string , "Email" > ;
21
+
22
+ type StudentContact = { schoolEmail : Email ; personalEmail : Email } ;
23
+
24
+ type In1 = Map < StudentId , CourseId > ;
25
+ type In2 = Map < StudentId , true > ;
26
+ type In3 = Map < StudentId , StudentContact > ;
18
27
19
28
function parseIn1 ( s : string ) : In1 | undefined {
20
29
const rows = parse ( s ) ;
@@ -33,7 +42,12 @@ function parseIn1(s: string): In1 | undefined {
33
42
return undefined ;
34
43
}
35
44
}
36
- return rows ;
45
+
46
+ const in1 : In1 = new Map ( ) ;
47
+ for ( const [ studentId , courseId ] of rows ) {
48
+ in1 . set ( studentId , courseId ) ;
49
+ }
50
+ return in1 ;
37
51
}
38
52
39
53
function parseIn2 ( s : string ) : In2 | undefined {
@@ -48,7 +62,12 @@ function parseIn2(s: string): In2 | undefined {
48
62
return undefined ;
49
63
}
50
64
}
51
- return rows ;
65
+
66
+ const in2 : In2 = new Map ( ) ;
67
+ for ( const [ studentId ] of rows ) {
68
+ in2 . set ( studentId , true ) ;
69
+ }
70
+ return in2 ;
52
71
}
53
72
54
73
function parseIn3 ( s : string ) : In3 | undefined {
@@ -69,23 +88,78 @@ function parseIn3(s: string): In3 | undefined {
69
88
return undefined ;
70
89
}
71
90
}
72
- return rows ;
91
+
92
+ const in3 : In3 = new Map ( ) ;
93
+ for ( const [ studentId , schoolEmail , personalEmail ] of rows ) {
94
+ in3 . set ( studentId , { schoolEmail, personalEmail } ) ;
95
+ }
96
+ return in3 ;
73
97
}
74
98
75
- function displayStudents (
76
- studentIds : string [ ] ,
77
- studentIdToEmail : Map < string , [ string , string ] > ,
78
- ) : string {
79
- return studentIds
80
- . map ( ( id ) => {
81
- const email = studentIdToEmail . get ( id ) ;
82
- if ( email === undefined ) {
83
- return `${ id } (email unknown)` ;
84
- } else {
85
- return `${ id } ${ email [ 0 ] } ${ email [ 1 ] } ` ;
86
- }
87
- } )
88
- . join ( "\n" ) ;
99
+ type MissingStudent = {
100
+ id : StudentId ;
101
+ contact : StudentContact | undefined ;
102
+ wrongCourseId : CourseId | undefined ;
103
+ } ;
104
+ type SuperfluousStudent = {
105
+ id : StudentId ;
106
+ contact : StudentContact | undefined ;
107
+ } ;
108
+ type VerifyResult = {
109
+ missingStudents : MissingStudent [ ] ;
110
+ superfluousStudents : SuperfluousStudent [ ] ;
111
+ } ;
112
+
113
+ function verify (
114
+ in1 : In1 ,
115
+ in2 : In2 ,
116
+ in3 : In3 ,
117
+ courseId : CourseId ,
118
+ ) : VerifyResult {
119
+ const missingStudents : MissingStudent [ ] = [ ] ;
120
+ const superfluousStudents : SuperfluousStudent [ ] = [ ] ;
121
+
122
+ for ( const studentId of in2 . keys ( ) ) {
123
+ const actualTakenCourseId = in1 . get ( studentId ) ;
124
+ if ( actualTakenCourseId === undefined ) {
125
+ // Student hasn't registered any course
126
+ missingStudents . push ( {
127
+ id : studentId ,
128
+ contact : in3 . get ( studentId ) ,
129
+ wrongCourseId : undefined ,
130
+ } ) ;
131
+ } else if ( actualTakenCourseId !== courseId ) {
132
+ // Student has registered the wrong course
133
+ missingStudents . push ( {
134
+ id : studentId ,
135
+ contact : in3 . get ( studentId ) ,
136
+ wrongCourseId : actualTakenCourseId ,
137
+ } ) ;
138
+ }
139
+ }
140
+
141
+ for ( const [ studentId , actualTakenCourseId ] of in1 . entries ( ) ) {
142
+ // Student took the `courseId` course even though they don't have to
143
+ if ( actualTakenCourseId === courseId && ! in2 . has ( studentId ) ) {
144
+ superfluousStudents . push ( {
145
+ id : studentId ,
146
+ contact : in3 . get ( studentId ) ,
147
+ } ) ;
148
+ }
149
+ }
150
+
151
+ return {
152
+ missingStudents,
153
+ superfluousStudents,
154
+ } ;
155
+ }
156
+
157
+ function displayMaybeStudentContact ( c : StudentContact | undefined ) : string {
158
+ if ( c === undefined ) {
159
+ return "(メアド不明)" ;
160
+ } else {
161
+ return `学校: ${ c . schoolEmail } 個人: ${ c . personalEmail } ` ;
162
+ }
89
163
}
90
164
91
165
function main ( ) {
@@ -112,53 +186,24 @@ function main() {
112
186
const courseId = courseIdElement . value ;
113
187
assert ( in1 !== undefined && in2 !== undefined && in3 !== undefined ) ;
114
188
115
- const studentIdToEmail = new Map < string , [ string , string ] > ( ) ;
116
- for ( const [ studentId , schoolEmail , personalEmail ] of in3 ) {
117
- studentIdToEmail . set ( studentId , [ schoolEmail , personalEmail ] ) ;
118
- }
119
-
120
- const studentIdToCourseId = new Map < string , string > ( ) ;
121
- for ( const [ studentId , courseId ] of in1 ) {
122
- studentIdToCourseId . set ( studentId , courseId ) ;
123
- }
124
-
125
- const shouldTakeCourseStudentIds = new Map < string , true > ( ) ;
126
- for ( const [ studentId ] of in2 ) {
127
- shouldTakeCourseStudentIds . set ( studentId , true ) ;
128
- }
129
-
130
- const mistakeIds : string [ ] = [ ] ;
131
- const unnecessaryIds : string [ ] = [ ] ;
132
-
133
- for ( const studentId of shouldTakeCourseStudentIds . keys ( ) ) {
134
- const actualTakenCourseId = studentIdToCourseId . get ( studentId ) ;
135
- if ( actualTakenCourseId === undefined ) {
136
- // NOTE: student hasn't registered a course
137
- mistakeIds . push ( studentId ) ;
138
- continue ;
139
- }
140
- if ( actualTakenCourseId !== courseId ) {
141
- mistakeIds . push ( studentId ) ;
142
- }
143
- }
144
-
145
- for ( const [
146
- studentId ,
147
- actualTakenCourseId ,
148
- ] of studentIdToCourseId . entries ( ) ) {
149
- if (
150
- actualTakenCourseId === courseId &&
151
- ! shouldTakeCourseStudentIds . has ( studentId )
152
- ) {
153
- unnecessaryIds . push ( studentId ) ;
154
- }
155
- }
156
-
189
+ const result = verify ( in1 , in2 , in3 , courseId as CourseId ) ;
157
190
outElement . innerHTML = `この授業を取らなくていいのに取っている学生:
158
- ${ displayStudents ( unnecessaryIds , studentIdToEmail ) }
191
+ ${ result . superfluousStudents
192
+ . map ( ( s ) => `${ s . id } ${ displayMaybeStudentContact ( s . contact ) } ` )
193
+ . join ( "\n" ) }
159
194
160
195
この授業を取らないといけないのに取っていない学生:
161
- ${ displayStudents ( mistakeIds , studentIdToEmail ) }
196
+ ${ result . missingStudents
197
+ . map ( ( s ) => {
198
+ let reason : string ;
199
+ if ( s . wrongCourseId === undefined ) {
200
+ reason = "履修登録なし" ;
201
+ } else {
202
+ reason = `${ s . wrongCourseId } を誤登録` ;
203
+ }
204
+ return `${ s . id } 理由: ${ reason } ${ displayMaybeStudentContact ( s . contact ) } ` ;
205
+ } )
206
+ . join ( "\n" ) }
162
207
` ;
163
208
} ) ;
164
209
}
0 commit comments