Redesign the algorithm to choose wrongly sorted elements

- When checking the order the first time, elements above are preferred marked as wrong.
- When the user corrects his solution, the newest inserted elements are preferred marked as wrong.

This affects only cases, where there are multiple options for the same number of correct elements.
In general, the algorithm minimizes the number of elements it needs to mark as wrong.

Closes #5
This commit is contained in:
Lukas Fürderer 2020-09-04 15:55:46 +02:00
parent fc7f630001
commit 099cc72429

95
quiz.js
View File

@ -133,47 +133,52 @@ function shuffle_cards(section) {
return a;
}
function choose_incorrects(idx_vals) {
function choose_incorrects(elems) {
let options = {
0: [],
"-1": [],
};
function find_longest_chain(maxkey) {
let longest = null;
for (let key in options) {
if (
(
maxkey == null
|| key <= maxkey
)
&& (
longest == null
|| options[key].length > options[longest].length
|| (
options[key].length == options[longest].length
&& Number.parseInt(key) < Number.parseInt(longest)
)
)
) {
longest = key;
function chain_is_better(old_chain, new_chain) {
if (old_chain == null) {
return true;
} else if (new_chain.length > old_chain.length) {
return true;
} else if (new_chain.length < old_chain.length) {
return false;
}
let old_nums = old_chain.map(elem => elem[1]).sort((a, b) => a - b).reverse();
let new_nums = new_chain.map(elem => elem[1]).sort((a, b) => a - b).reverse();
for (let i=0; i<old_nums.length; i++) {
if (new_nums[i] < old_nums[i]) {
return true;
} else if (new_nums[i] > old_nums[i]) {
return false;
}
}
return longest;
}
idx_vals.forEach((val) => {
let longest = find_longest_chain(val);
let mychain = options[longest].slice();
mychain.push(val);
options[val + 1] = mychain;
function build_chain(elem) {
let best = null;
for (let chain_end in options) {
let chain = options[chain_end];
chain_end = Number.parseInt(chain_end);
if (elem == null || chain_end < elem[0]) {
let newchain = chain.slice();
if (elem != null) {
newchain.push(elem);
}
if (chain_is_better(best, newchain)) {
best = newchain;
}
}
}
return best;
}
elems.forEach(elem => {
let chain = build_chain(elem);
options[chain[chain.length - 1][0]] = chain;
});
let result_chain = find_longest_chain(null);
let a = [];
for (let i=0; i<cards_content[0].length; i++) {
a.push(true);
}
options[result_chain].forEach((elem) => {
a[elem] = false;
});
return idx_vals.map(idx => a[idx]);
let result_chain = build_chain(null);
let corrects = result_chain.map(elem => elem[0]);
return elems.map(elem => !corrects.includes(elem[0]));
}
var app = new Vue({
@ -185,6 +190,7 @@ var app = new Vue({
selected: null,
items: shuffle_cards(0),
},
next_insert_num: null,
solution: [],
correction_visible: false,
},
@ -274,8 +280,8 @@ var app = new Vue({
return this.solution.map(elem => false);
}
if (this.store.section == 0) {
let idx_vals = this.solution.map(elem => elem.idx[0]);
return choose_incorrects(idx_vals);
let elems = this.solution.map(elem => [elem.idx[0], elem.insert_num]);
return choose_incorrects(elems);
} else {
return this.solution.map((elem, i) => {
return elem.idx.length > this.store.section
@ -316,11 +322,18 @@ var app = new Vue({
store_card_visible: function(idx) {
return !this.solution.some(solution => solution.idx[this.store.section] == idx);
},
calculate_insert_num: function() {
if (this.next_insert_num == null) {
return null;
}
return this.next_insert_num++;
},
store_select: function(i) {
if (this.solution.length == 0) {
this.solution.push({
idx: [i],
got_revealed: false,
insert_num: this.calculate_insert_num(),
});
} else if (i == this.store.selected) {
this.store.selected = null;
@ -335,6 +348,7 @@ var app = new Vue({
this.solution.splice(0, 0, {
idx: [this.store.selected],
got_revealed: false,
insert_num: this.calculate_insert_num(),
});
this.store.selected = null;
},
@ -349,6 +363,7 @@ var app = new Vue({
this.solution.splice(this.find_solution(elem)+1, 0, {
idx: [this.store.selected],
got_revealed: false,
insert_num: this.calculate_insert_num(),
});
this.store.selected = null;
},
@ -360,6 +375,12 @@ var app = new Vue({
}
},
show_correction: function() {
if (this.store.section == 0) {
this.solution.forEach((elem, i) => {
elem.insert_num = -i;
});
this.next_insert_num = 1;
}
this.correction_visible = true;
},
open_next_column: function() {