word/quiz: filter preset category and empty subcategories
[sheet.git] / word / quiz.js
1 Array.prototype.shuffle = function () {
2         for (let i = this.length - 1; i > 0; i--) {
3                 const j = Math.floor(Math.random() * (i + 1)); // random index 0..i
4                 [this[i], this[j]] = [this[j], this[i]]; // swap elements
5         }
6         return this;
7 };
8
9 class WordQuiz {
10         dataselect(json) {
11                 // find viable rows from json data
12                 let rows = Object.values(json);
13                 if (this.preset.cat !== undefined) {
14                         let cats = {}; // category lookup
15                         for (let i in json) {
16                                 let cat = json[i][3];
17                                 if (!cats[cat]) cats[cat] = [];
18                                 cats[cat].push(i)
19                         }
20
21                         rows = [];
22                         let children = cats[this.preset.cat];
23                         for (let loop = 0; children.length && loop < 20; loop++) {
24                                 rows.push(...children);
25                                 children = children.map(cat => cats[cat]).filter(is => is).flat();
26                         }
27                         rows = rows.map(row => json[row]).filter(row => row[2]);
28                 }
29                 if (this.preset.level !== undefined) {
30                         rows = rows.filter(row => row[1] <= this.preset.level);
31                 }
32
33                 {
34                         let cats = new Set();
35                         let subcats = rows.map(row => row[3]); // direct parents
36                         for (let loop = 0; subcats.length && loop < 20; loop++) {
37                                 subcats.forEach(cat => cats.add(cat));
38                                 subcats = subcats.map(row => json[row] && json[row][3]).filter(val => val); // recurse grandparents
39                         }
40                         rows = rows.filter(row => !cats.has(row[2])); // remove referenced categories
41                 }
42                 return rows.shuffle();
43         }
44
45         load(dataurl) {
46                 this.preset = {};
47                 fetch(dataurl).then(res => res.json()).then(json => {
48                         this.words = this.dataselect(json)
49                         this.setup();
50                 });
51         }
52
53         constructor(dataurl) {
54                 this.load(dataurl);
55         }
56 }