qb-answer-checker 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -3
- package/check-answer.d.ts +4 -0
- package/lib/check-answer.js +27 -15
- package/package.json +1 -1
- package/test/script.js +1 -1
- package/test/tests.json +14 -0
package/README.md
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
# QB Answer Checker
|
|
2
|
+
|
|
3
|
+
A package to automatically check/judge answers against quizbowl answerlines.
|
|
4
|
+
Mostly used in conjunction with [qbreader](https://www.qbreader.org/) to automatically check answers.
|
|
5
|
+
|
|
6
|
+
## Answerline Specification
|
|
7
|
+
|
|
8
|
+
This section specifies the kind of (quizbowl) answerlines that the program is designed to parse.
|
|
2
9
|
|
|
3
10
|
**Answerlines** should be formatted as follows:
|
|
4
11
|
|
|
@@ -30,7 +37,7 @@ Each **directive** should be one of:
|
|
|
30
37
|
|
|
31
38
|
and "on" and "by asking/with" are optional and indicate that there should be a directed prompt.
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
### Special Directives
|
|
34
41
|
|
|
35
42
|
**Special directives** should be one of the following and affect the main answerline only:
|
|
36
43
|
|
|
@@ -41,7 +48,7 @@ and "on" and "by asking/with" are optional and indicate that there should be a d
|
|
|
41
48
|
|
|
42
49
|
**Note:** special directives should be the first phrase in the sub-answerline, but this program will recognize them anywhere in the sub-answerline.
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
### Additional Info
|
|
45
52
|
|
|
46
53
|
For more information about how answerlines should be formatted, see <https://minkowski.space/quizbowl/manuals/style/answerlines.html>.
|
|
47
54
|
Note that the linked guide is more useful for explaining how answerlines should be formatted from a sylistic/quizbowl sense, while this specification only describes how they should be formatted in a way that computers can understand.
|
package/lib/check-answer.js
CHANGED
|
@@ -158,7 +158,12 @@ function parseAnswerline(answerline) {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Generates standardized tokens from a string.
|
|
163
|
+
* @param {string} string
|
|
164
|
+
* @returns {string[]} the tokens generated from the string
|
|
165
|
+
*/
|
|
166
|
+
function generateTokens(string) {
|
|
162
167
|
const tokens = string.split(' ')
|
|
163
168
|
.filter(token => token.length > 0)
|
|
164
169
|
.map(string => standardizeTokens(string));
|
|
@@ -200,7 +205,7 @@ const generateTokens = (string) => {
|
|
|
200
205
|
* @param {boolean} acceptSubstring
|
|
201
206
|
* @param {number} strictness
|
|
202
207
|
* @param {boolean} useStemmer
|
|
203
|
-
* @returns
|
|
208
|
+
* @returns {boolean}
|
|
204
209
|
*/
|
|
205
210
|
function tokenListsMatch(given, reference, acceptSubstring, strictness, useStemmer) {
|
|
206
211
|
let j = 0;
|
|
@@ -216,7 +221,7 @@ function tokenListsMatch(given, reference, acceptSubstring, strictness, useStemm
|
|
|
216
221
|
errors = distance(given[i], reference[j]);
|
|
217
222
|
}
|
|
218
223
|
|
|
219
|
-
if (strictness * errors <= reference[j].length) {
|
|
224
|
+
if (strictness > 0 && strictness * errors <= reference[j].length) {
|
|
220
225
|
matches = true;
|
|
221
226
|
}
|
|
222
227
|
|
|
@@ -224,6 +229,10 @@ function tokenListsMatch(given, reference, acceptSubstring, strictness, useStemm
|
|
|
224
229
|
matches = true;
|
|
225
230
|
}
|
|
226
231
|
|
|
232
|
+
if (errors === 0) {
|
|
233
|
+
matches = true;
|
|
234
|
+
}
|
|
235
|
+
|
|
227
236
|
j++;
|
|
228
237
|
}
|
|
229
238
|
|
|
@@ -237,20 +246,23 @@ function tokenListsMatch(given, reference, acceptSubstring, strictness, useStemm
|
|
|
237
246
|
|
|
238
247
|
/**
|
|
239
248
|
* Returns true if and only if every token in `string` is present in `reference`.
|
|
240
|
-
* @param {
|
|
241
|
-
* @param {
|
|
242
|
-
* @param {
|
|
243
|
-
* @param {
|
|
244
|
-
* @param {
|
|
245
|
-
* @param {
|
|
246
|
-
* @
|
|
249
|
+
* @param {object} options
|
|
250
|
+
* @param {string} options.string
|
|
251
|
+
* @param {string} options.reference
|
|
252
|
+
* @param {number} [options.strictness=7] - the number of characters per error allowed for two tokens to match. If set to a negative number or 0, then no errors are allowed.
|
|
253
|
+
* @param {boolean} [options.acceptSubstring=false] - whether or not to accept substrings.
|
|
254
|
+
* @param {boolean} [options.useStemmer=true] - whether or not to use a stemmer.
|
|
255
|
+
* @param {boolean} [options.respectOrder=false] - whether or not to respect the order of the tokens (i.e. "a b" is not the same as "b a").
|
|
256
|
+
* @returns {boolean}
|
|
247
257
|
*/
|
|
248
|
-
function stringMatchesReference({ string, reference, strictness =
|
|
249
|
-
if (string === null || string === undefined || reference === null || reference === undefined)
|
|
258
|
+
function stringMatchesReference({ string, reference, strictness = 7, acceptSubstring = false, useStemmer = true, respectOrder = false }) {
|
|
259
|
+
if (string === null || string === undefined || reference === null || reference === undefined) {
|
|
250
260
|
return false;
|
|
261
|
+
}
|
|
251
262
|
|
|
252
|
-
if (string.length === 0)
|
|
263
|
+
if (string.length === 0) {
|
|
253
264
|
return false;
|
|
265
|
+
}
|
|
254
266
|
|
|
255
267
|
string = utils.removePunctuation(string).trim();
|
|
256
268
|
reference = utils.removePunctuation(reference).trim();
|
|
@@ -319,10 +331,10 @@ function checkAnswer(answerline, givenAnswer) {
|
|
|
319
331
|
for (const answer of parsedAnswerline.reject) {
|
|
320
332
|
const useStemmer = (stemmer(answer) !== stemmer(parsedAnswerline.accept[0]));
|
|
321
333
|
|
|
322
|
-
if (!stringMatchesReference({ string: answer, reference: givenAnswer, strictness:
|
|
334
|
+
if (!stringMatchesReference({ string: answer, reference: givenAnswer, strictness: -1, useStemmer }))
|
|
323
335
|
continue;
|
|
324
336
|
|
|
325
|
-
if (!stringMatchesReference({ string: givenAnswer, reference: answer, strictness:
|
|
337
|
+
if (!stringMatchesReference({ string: givenAnswer, reference: answer, strictness: -1, useStemmer }))
|
|
326
338
|
continue;
|
|
327
339
|
|
|
328
340
|
return { directive: 'reject', directedPrompt: null };
|
package/package.json
CHANGED
package/test/script.js
CHANGED
package/test/tests.json
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"formatted": [
|
|
3
|
+
{
|
|
4
|
+
"answerline": "<b><u>realignments</u></b> [reject \"dealignments\"]",
|
|
5
|
+
"tests": [
|
|
6
|
+
{ "directive": "accept", "given": "realignments" },
|
|
7
|
+
{ "directive": "reject", "given": "dealignments" }
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"answerline": "<b><u>dihydroxylation</u></b> [prompt on <b><u>hydroxylation</u></b>]",
|
|
12
|
+
"tests": [
|
|
13
|
+
{ "directive": "accept", "given": "dihydroxylation" },
|
|
14
|
+
{ "directive": "prompt", "given": "hydroxylation" }
|
|
15
|
+
]
|
|
16
|
+
},
|
|
3
17
|
{
|
|
4
18
|
"answerline": "<b><u>Major Major Major</u></b>",
|
|
5
19
|
"tests": [
|