training.js (3156B)
1 function unixtime() { 2 return (new Date).getTime(); 3 } 4 5 function getData() { 6 let ls = localStorage.getItem("progress"); 7 if (ls) { 8 return JSON.parse(ls); 9 } 10 11 /* sorted by frequency */ 12 let chars = " -.etaonihsrlducmwyfgpbvkjxqz0123456789"; 13 let hints = { 14 " ": "G7", 15 "-": "G8", 16 ".": "G9" 17 }; 18 for (let i = 0; i < 36; i++) { 19 let hint = "G" + Math.floor(i / 6 + 1) + " G" + (i % 6 + 1); 20 let ch = i < 26 ? 21 String.fromCharCode("a".charCodeAt() + i) : 22 (i - 26) + ""; 23 hints[ch] = hint; 24 } 25 let data = chars.split("").map(c => ({ 26 c: c, 27 hint: hints[c], 28 numt: 0, /* how often this character was tested */ 29 score: 0, 30 lastt: 0, /* timestamp of the last test */ 31 })); 32 return data; 33 } 34 35 function setData(data) { 36 localStorage.setItem("progress", JSON.stringify(data)); 37 } 38 39 40 function getMaxIndex(valueFn, list) { 41 let max; 42 let maxValue = 0; 43 for (let i = 0; i < list.length; i++) { 44 let v = valueFn(list[i]); 45 if (v != 0 && (!max || v > maxValue)) { 46 max = i; 47 maxValue = v; 48 } 49 } 50 return max; 51 } 52 53 // returns a list index, probabilities are weighted by the elements of the list 54 function randomIndex(list) { 55 let sum = list.reduce((a,b) => a + b, 0); 56 let hit = Math.random() * sum; 57 let currSum = 0; 58 for (let i = 0; i < list.length; i++) { 59 currSum += list[i]; 60 if (hit <= currSum) return i; 61 } 62 } 63 64 /* basic idea: 65 * - remove previously tested character from the list of possible ones (so 66 * that no character is tested twice) 67 * - if there are chars older than a week, test the oldest 68 * - if all known chars have a score greater than 20 test a new one 69 * - if all chars are known or some char has a score smaller than 20 test a 70 * char randomly with weighted probability according to the score 71 * 72 * score: 73 * - starts at 0 74 * - test correct? +5 75 * - test incorrect? /2 76 * - showing hints counts as incorrect (maybe also set a time limit?) 77 * 78 * return value consists of the character and a hint 79 */ 80 function getTest() { 81 let data = getData(); 82 83 let prev = getMaxIndex(e => e.lastt, data); 84 if (prev) { 85 data.splice(prev, 1); 86 } 87 88 let old = getMaxIndex(e => -e.lastt, data); 89 if (old && data[old].lastt < unixtime() - 1000 * 60 * 60 * 24 * 7) { 90 return [data[old].c, data[old].hint]; 91 } 92 93 let known = data.filter(e => e.numt > 0).sort( 94 (a, b) => (a.score - b.score) 95 ); 96 let unknown = data.filter(e => e.numt == 0); 97 98 if ((known.length != 0 && known[0].score < 20) || unknown.length == 0) { 99 let index = randomIndex(known.map(e => 1 / e.score || 1)); 100 return [known[index].c, known[index].hint]; 101 } 102 return [unknown[0].c, unknown[0].hint]; 103 } 104 105 function saveTest(c, success) { 106 let data = getData(); 107 let elem = data.find(e => e.c == c); 108 elem.numt++; 109 elem.lastt = unixtime(); 110 if (success) elem.score += 5; 111 else elem.score = Math.floor(elem.score / 2); 112 setData(data); 113 } 114 115 module.exports = { 116 getTest, 117 saveTest 118 }