Save results into folder
This commit is contained in:
parent
ed1ce0706d
commit
684c75c9ee
|
@ -2,3 +2,4 @@ node_modules
|
|||
npm-debug.log*
|
||||
best-found.txt
|
||||
text/*.txt
|
||||
results
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Попытка создать самую эффективную кириллическую раскладку при помощи эволюционного алгоритма.
|
||||
|
||||
На данный момент не удаётся обогнать раскладку ЙУИЯФ.
|
||||
На данный момент сгенерированно более 40 раскладок, среди которых есть достойные кандидаты.
|
||||
|
||||
## Инструкция
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
|||
2. Наполнить папку `text` файлами `*.txt`. Я использовал классические произведения
|
||||
русской литературы, которые являются общественным достоянием.
|
||||
|
||||
3. Обработать каждый файл с помощью `convert.sh`. Файлы должны быть в кодировке *UTF-8*.
|
||||
3. Обработать каждый файл с помощью `convert.sh`. Файлы должны быть в кодировке _UTF-8_.
|
||||
Удобно пройтись по каждому файлу с помощью цикла в оболочке командной строки.
|
||||
|
||||
4. Сконфигурировать генератор. Настройки распологаются в файле `src/config.js`.
|
||||
|
@ -22,4 +22,4 @@
|
|||
|
||||
5. Запустить генерацию командой `npm start`.
|
||||
|
||||
6. Добавить получившуюся раскладку в файл `src/compare.js` и сравнить с другими `npm test`.
|
||||
6. Добавить получившуюся раскладку в файл `src/compare.js` и сравнить с другими `npm test`.
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
*/
|
||||
|
||||
// Generator config
|
||||
exports.use_elites = true;
|
||||
exports.mutate_level = 7; // Start mutate level
|
||||
exports.use_elites = true;
|
||||
exports.mutate_level = 7; // Start mutate level
|
||||
exports.mutate_levels = [5, 3, 2, 1];
|
||||
exports.mutate_thresholds = [780000, 850000, 980000, 990000];
|
||||
exports.max_no_chage = 250;
|
||||
exports.max_generation = 10000;
|
||||
exports.POPULATION_SIZE = 15;
|
||||
|
||||
exports.EFFORT_LIMIT = 3000000;
|
||||
exports.EFFORT_LIMIT = 3000000;
|
||||
exports.SAME_FINGER_PENALTY = 10; // multiplier
|
||||
exports.SAME_HAND_PENALTY = 1; // multiplier
|
||||
exports.SAME_HAND_PENALTY = 1; // multiplier
|
||||
|
||||
// just a mapping for easier conversions
|
||||
const COORDINATES = parseMapping(`
|
||||
|
@ -62,9 +62,15 @@ exports.FINGERS = buildMapping(`
|
|||
`);
|
||||
|
||||
const FINGER_NAMES = {
|
||||
a: 'l-pinky', b: 'l-ring', c: 'l-middle', d: 'l-point',
|
||||
h: 'r-pinky', g: 'r-ring', f: 'r-middle', e: 'r-point',
|
||||
t: 'thumb'
|
||||
a: "l-pinky",
|
||||
b: "l-ring",
|
||||
c: "l-middle",
|
||||
d: "l-point",
|
||||
h: "r-pinky",
|
||||
g: "r-ring",
|
||||
f: "r-middle",
|
||||
e: "r-point",
|
||||
t: "thumb",
|
||||
};
|
||||
|
||||
for (const key in exports.FINGERS) {
|
||||
|
@ -73,20 +79,26 @@ for (const key in exports.FINGERS) {
|
|||
|
||||
// parses a map into key-index -> letter thing
|
||||
function parseMapping(string) {
|
||||
return string.trim().split("\n").reduce((mapping, line) => {
|
||||
const reps = { "\\n" : "\n", "space": " " };
|
||||
line.trim().split(/\s+/).forEach(symbol =>
|
||||
mapping.push(reps[symbol] || symbol)
|
||||
);
|
||||
return mapping;
|
||||
}, []);
|
||||
};
|
||||
return string
|
||||
.trim()
|
||||
.split("\n")
|
||||
.reduce((mapping, line) => {
|
||||
const reps = { "\\n": "\n", space: " " };
|
||||
line
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.forEach((symbol) => mapping.push(reps[symbol] || symbol));
|
||||
return mapping;
|
||||
}, []);
|
||||
}
|
||||
|
||||
// creates a letter -> value mapping
|
||||
function buildMapping(string) {
|
||||
return parseMapping(string).reduce((mapping, value, i) =>
|
||||
Object.assign(mapping, { [COORDINATES[i]] :
|
||||
/^\d+$/.test(value) ? parseInt(value) : value
|
||||
})
|
||||
, {});
|
||||
};
|
||||
return parseMapping(string).reduce(
|
||||
(mapping, value, i) =>
|
||||
Object.assign(mapping, {
|
||||
[COORDINATES[i]]: /^\d+$/.test(value) ? parseInt(value) : value,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
|
118
src/index.js
118
src/index.js
|
@ -1,21 +1,45 @@
|
|||
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 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];
|
||||
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));
|
||||
co(boot).catch((e) => console.log(e.stack));
|
||||
|
||||
function *boot() {
|
||||
if(mutate_levels.length != mutate_thresholds.length) {
|
||||
function* boot() {
|
||||
if (mutate_levels.length != mutate_thresholds.length) {
|
||||
die("Mutate settings are incorrect");
|
||||
}
|
||||
for (const promise of cluster.schedule(seed_layouts)) {
|
||||
|
@ -26,55 +50,89 @@ function *boot() {
|
|||
yield start(Population.random(), max_generation);
|
||||
}
|
||||
|
||||
function *start(population, count) {
|
||||
function* start(population, count) {
|
||||
let last_layout, last_score, no_changes_in;
|
||||
let rank = 0;
|
||||
|
||||
for (let i=0; i < count; i++) {
|
||||
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]) {
|
||||
if (rank < mutate_levels.length) {
|
||||
if (score.total > mutate_thresholds[rank]) {
|
||||
mutate_level = mutate_levels[rank];
|
||||
rank ++;
|
||||
rank++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
no_changes_in ++;
|
||||
no_changes_in++;
|
||||
}
|
||||
|
||||
ui.addResult(layout, score, no_changes_in, max_no_chage);
|
||||
last_layout = layout; last_score = score;
|
||||
last_layout = layout;
|
||||
last_score = score;
|
||||
|
||||
if (no_changes_in == max_no_chage) {
|
||||
break;
|
||||
}
|
||||
|
||||
population = population.next({elite: use_elites, mutate: mutate_level});
|
||||
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(
|
||||
`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);
|
||||
function* handle(population) {
|
||||
ui.newPopulation(
|
||||
population,
|
||||
max_generation,
|
||||
use_elites,
|
||||
mutate_level,
|
||||
POPULATION_SIZE
|
||||
);
|
||||
|
||||
const layouts = population.genomes.map(g => g.toLayout());
|
||||
const layouts = population.genomes.map((g) => g.toLayout());
|
||||
|
||||
for (const promise of cluster.schedule(layouts)) {
|
||||
const { layout, result } = yield promise;
|
||||
|
|
Loading…
Reference in New Issue