keyboard-genetics/src/index.js

154 lines
3.9 KiB
JavaScript

const co = require("co");
const ui = require("./ui");
const { text, trigrams, code } = require("./data");
const Stats = require("./stats");
const Cluster = require("./cluster");
const Population = require("./population");
const {
JCUKEN,
Diktor,
Diktor_VoronovMod,
Redaktor,
JUIYAF,
Zubachev,
Ruhal,
} = require("./presets");
const {
use_elites,
mutate_levels,
mutate_thresholds,
max_no_chage,
max_generation,
population_size,
POPULATION_SIZE,
} = require("./config");
let { mutate_level } = require("./config");
const data = text;
const cluster = new Cluster(data);
const seed_layouts = [
JCUKEN,
Diktor,
Diktor_VoronovMod,
Redaktor,
JUIYAF,
Zubachev,
Ruhal,
];
co(boot).catch((e) => console.log(e.stack));
function* boot() {
if (mutate_levels.length != mutate_thresholds.length) {
die("Mutate settings are incorrect");
}
for (const promise of cluster.schedule(seed_layouts)) {
const { layout, result } = yield promise;
ui.addResult(layout, new Stats(result));
}
yield start(Population.random(), max_generation);
}
function* start(population, count) {
let last_layout, last_score, no_changes_in;
let rank = 0;
for (let i = 0; i < count; i++) {
const [layout, score] = yield handle(population);
if (!last_layout || last_layout.toString() !== layout.toString()) {
no_changes_in = 0;
if (rank < mutate_levels.length) {
if (score.total > mutate_thresholds[rank]) {
mutate_level = mutate_levels[rank];
rank++;
}
}
} else {
no_changes_in++;
}
ui.addResult(layout, score, no_changes_in, max_no_chage);
last_layout = layout;
last_score = score;
if (no_changes_in == max_no_chage) {
break;
}
population = population.next({ elite: use_elites, mutate: mutate_level });
}
const vs = ui.vs_result(last_score);
const overheads = ui.getOverheads();
ui.destroy();
const fs = require("fs");
const file = new console.Console(
fs.createWriteStream(`./results/output${new Date().getTime()}.txt`)
);
console.log(`Total: ${last_score.total}, Dist: ${last_score.position},\n`);
console.log(
`Symmetry: ${last_score.symmetry}%, Evenness: ${last_score.evenness}%,\n`
);
console.log(
`Hands: ${last_score.handsUsage.map((v) => v + "%").join(" | ")},\n`
);
console.log(
`Overheads: Finger:${overheads.finger}%, Hand:${overheads.hand}%, Shift:${overheads.shift}%\n`
);
console.log(`Fingers ${last_score.fingersUsage}\n`);
console.log(`vs.Diktor: ${vs[0]}`);
console.log(`vs.JCUKEN: ${vs[1]}\n`);
console.log(last_layout.toCyrillic(), "\n");
console.log(last_layout.config);
file.log(`Total: ${last_score.total}, Dist: ${last_score.position},\n`);
file.log(
`Symmetry: ${last_score.symmetry}%, Evenness: ${last_score.evenness}%,\n`
);
file.log(
`Hands: ${last_score.handsUsage.map((v) => v + "%").join(" | ")},\n`
);
file.log(
`Overheads: Finger:${overheads.finger}%, Hand:${overheads.hand}%, Shift:${overheads.shift}%\n`
);
file.log(`Fingers ${last_score.fingersUsage}\n`);
file.log(`vs.Diktor: ${vs[0]}`);
file.log(`vs.JCUKEN: ${vs[1]}\n`);
file.log(last_layout.toCyrillic(), "\n");
file.log(last_layout.config);
}
function* handle(population) {
ui.newPopulation(
population,
max_generation,
use_elites,
mutate_level,
POPULATION_SIZE
);
const layouts = population.genomes.map((g) => g.toLayout());
for (const promise of cluster.schedule(layouts)) {
const { layout, result } = yield promise;
const score = new Stats(result);
ui.logGrade(layout, score);
layouts.forEach((l, i) => {
if (l.config === layout.config) {
population.scores[i] = score;
}
});
}
const best_gene = population.best();
const best_layout = best_gene.toLayout();
const score = population.scoreFor(best_gene);
return [best_layout, score];
}