Skip to content

Commit 345f7ed

Browse files
Refine hints - only re-show for free if it's the SAME button
Refine the hint button further: * If there are no hints, say so immediately (without delay or penalty). * If the answers for *this* form are all correct, have the hint button always say so (instead of looking at *all* answers). * If you re-ask for a hint, reshow it without penalty only *if* it's the same hint button (while continuing to also require that the inputs haven't changed). In general there's still a timer for each hint, but we want to ignore the timer in a few cases and those cases are more complicated to express. Signed-off-by: David A. Wheeler <[email protected]>
1 parent 2e808bb commit 345f7ed

File tree

1 file changed

+33
-25
lines changed

1 file changed

+33
-25
lines changed

docs/labs/checker.js

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ let user_gave_up = false; // True if user ever gave up before user solved it
1818

1919
let startTime = Date.now(); // Time this lab started.
2020
let lastHintTime = null; // Last time we showed a hint.
21+
let lastHintTarget = null; // Last hint button user used.
2122

2223
// Has the input changed since we showed a hint?
2324
// We track this so people can re-see a hint they've already seen.
@@ -356,15 +357,20 @@ function calcOneMatch(attempt, index = 0, correct = correctRe) {
356357
* Return true iff all of attempt matches all of correct.
357358
* @attempt - Array of strings that might be correct
358359
* @correct - Array of compiled regexes describing correct answer
360+
* @validIndexes - Array of indexes to check (default: all indexes)
359361
*/
360-
function calcMatch(attempt, correct = correctRe) {
362+
function calcMatch(attempt, correct = correctRe, validIndexes = null) {
361363
if (!correct) { // Defensive test, should never happen.
362364
alert('Error: Internal failure, correct value not defined or empty.');
363365
return false;
364366
}
365367
for (let i = 0; i < correct.length; i++) {
366-
// If we find a failure, return false immediately (short circuit)
367-
if (!calcOneMatch(attempt, i, correctRe)) return false;
368+
if (validIndexes == null || validIndexes.includes(i)) {
369+
// If we find a failure, return false immediately (short circuit)
370+
if (!calcOneMatch(attempt, i, correctRe)) {
371+
return false;
372+
}
373+
}
368374
}
369375
// Everything passed.
370376
return true;
@@ -557,23 +563,10 @@ function findHint(attempt, validIndexes = undefined) {
557563
}
558564

559565
/** Show a hint to the user. */
560-
function showHint(e) {
561-
// Get data-indexes value using e.target.dataset.indexes
562-
// alert(`Form id = ${e.target.form.id}`);
563-
let attempt = retrieveAttempt();
564-
565-
// Check if the answer's already correct. This shouldn't happen, since
566-
// it was already checked. This is just a little defensive programming.
567-
if (calcMatch(attempt, correctRe)) {
568-
alert(t('already_correct'));
569-
} else if (!hints) {
570-
alert(t('no_hints'));
571-
} else {
572-
// Use *precalculated* input field indexes to work around
573-
// problem in Chrome translator.
574-
let validIndexes = e.target.dataset.inputIndexes;
575-
alert(findHint(attempt, validIndexes));
576-
}
566+
function showHint(e, attempt, validIndexes) {
567+
// Use *precalculated* input field indexes to work around
568+
// problem in Chrome translator.
569+
alert(findHint(attempt, validIndexes));
577570
}
578571

579572
/** Show the answer to the user */
@@ -628,27 +621,42 @@ function maybeShowAnswer(e) {
628621
}
629622
}
630623

624+
// Return true iff target is the same hint button as last time, without edits.
625+
function sameHint(target) {
626+
return (target == lastHintTarget) && !changedInputSinceHint;
627+
}
628+
631629
/** Maybe show a hint to the user (depending on timer). */
632630
function maybeShowHint(e) {
633-
// If answer is correct, confirm it and don't cause a penalty.
631+
// If there are no hints, just say so without delay.
632+
if (!hints || hints.length === 0) {
633+
alert(t('no_hints'));
634+
return;
635+
}
636+
637+
// Confirm correct answer if it is, and don't cause a penalty or delay.
638+
// For "hint" we only consider the answers for THIS form.
634639
let attempt = retrieveAttempt();
635-
if (calcMatch(attempt, correctRe)) {
640+
let formIndexes = JSON.parse(e.target.dataset.inputIndexes);
641+
if (calcMatch(attempt, correctRe, formIndexes)) {
636642
alert(t('already_correct'));
637643
return;
638644
}
639645

640-
// Answer is not correct. Determine if delay time has passed.
646+
// Answer is not correct. Determine how much time has passed.
641647
let elapsedTime = elapsedTimeSinceClue();
642648

649+
// Reply if the minimum delay time has passed.
643650
// Only enforce delay timer if changedInputSinceHint is true. That way,
644651
// people can re-see a previously-seen hint as long as they
645652
// have not changed anything since seeing the hint.
646-
if (changedInputSinceHint && (elapsedTime < HINT_DELAY_TIME)) {
653+
if ((elapsedTime < HINT_DELAY_TIME) && !sameHint(e.target)) {
647654
alert(myFormat(t('try_harder_hint'), [HINT_DELAY_TIME.toString()]));
648655
} else {
649656
lastHintTime = Date.now(); // Set new delay time start
657+
lastHintTarget = e.target; // Set last hint button used
650658
changedInputSinceHint = false; // Allow redisplay of hint
651-
showHint(e);
659+
showHint(e, attempt, formIndexes);
652660
}
653661
}
654662

0 commit comments

Comments
 (0)