sleeb

an experimental input method
git clone https://tongong.net/git/sleeb.git
Log | Files | Refs | README

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 }