Skip to content

Commit

Permalink
支持一音多键(飞键)
Browse files Browse the repository at this point in the history
  • Loading branch information
macroxue committed Jan 9, 2024
1 parent ebaef51 commit 386559a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 49 deletions.
27 changes: 15 additions & 12 deletions eval.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ <h1>双拼方案评测、优化和生成
<button id='stat' onclick='stat_pinyin()'>统计拼音频率</button>
<br/>
<textarea rows='6' cols='60' id='input-text'>
在这里输入文稿。最快的方式是拷贝粘帖大量文本,比如一整本小说。处理几十万字不成问题。
定义双拼方案时以‘0’表示零声母。所有声母的位置都可以自定义,具体例子参见下面的‘乱序优化’方案。
如果要添加笔画辅助码,则以 -、|、/、\、^ 分别表示横、竖、撇、点(捺)、折。
1. 在这里输入文稿。最快的方式是拷贝粘帖大量文本,比如一整本小说。处理几十万字不成问题。
2. 定义双拼方案时以‘0’表示零声母。所有声母的位置都可以自定义,具体例子参见下面的‘乱序优化’方案。
3. 支持在多个键位上定义同一个声母或韵母,程序会自动选取最佳组合。参见’大牛‘方案。
4. 如果要添加笔画辅助码,则以 -、|、/、\、^ 分别表示横、竖、撇、点(捺)、折,参见’UAI优化顶功‘方案。
</textarea>
</td>
<td class='stats' id='pinyin-stats-cell'>
Expand Down Expand Up @@ -72,22 +73,24 @@ <h1>双拼方案评测、优化和生成
<p/><b>双拼方案: </b>
<label>
<select id='scheme-name' onchange='select_scheme()'>
<option value='自定义'>自定义</option>
<option value='' disabled='disabled'>───常见───</option>
<option value='加加'>加加</option>
<option value='小鹤'>小鹤</option>
<option value='微软'>微软</option>
<option value='智能ABC'>智能ABC</option>
<option value='紫光'>紫光</option>
<option value='自然码'>自然码</option>
<option value='国标'>国标</option>
<option value='' disabled='disabled'>-------</option>
<option value='' disabled='disabled'>───特殊───</option>
<option value='大牛'>大牛</option>
<option value='飞猫'>飞猫</option>
<option value='乱序优化'>乱序优化</option>
<option value='全拼'>全拼</option>
<option value='' disabled='disabled'>───私人───</option>
<option value='UAI优化'>UAI优化</option>
<option value='UAI优化顶功'>UAI优化顶功</option>
<option value='乱序优化'>乱序优化</option>
<option value='六六'>六六</option>
<option value='' disabled='disabled'>-------</option>
<option value='自定义'>自定义</option>
<option value='' disabled='disabled'>-------</option>
<option value='全拼'>全拼</option>
</select>
</label>
<button onclick='evaluate_current_scheme()'>评测当前方案</button>
Expand Down Expand Up @@ -166,7 +169,7 @@ <h1>双拼方案评测、优化和生成
<div class='result' id='result'>
<table>
<tr>
<td>
<td class='result'>
<p/><b>评测结果:</b> <b id='score'></b> &nbsp; <b id='error'></b>
<br/>
<table>
Expand Down Expand Up @@ -274,10 +277,10 @@ <h1>双拼方案评测、优化和生成
<td>
&nbsp; &nbsp; &nbsp;
</td>
<td id='improvement'>
<td class='result' id='improvement'>
<p/><b>优化:</b>
<button id='improve' onclick='improve_scheme()'>建议</button><br/>
<select id='suggestion' onclick='apply_suggestion()' size=13>
<select id='suggestion' onclick='apply_suggestion()' size=10>
</select>
</td>
</tr>
Expand Down
4 changes: 4 additions & 0 deletions evaluator.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ div.result {
}
div.result #error {
background: #ff0;
font-size: smaller;
}
div.result textarea {
position: relative;
Expand All @@ -69,6 +70,9 @@ div.result select {
top: 4px;
width: 200px;
}
td.result {
vertical-align: top;
}
table[class='stats'], td[class='stats'] {
background: #fed;
border: 1px solid #243;
Expand Down
100 changes: 63 additions & 37 deletions evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ var schemes = {
紫光:'Q=ao,W=en,R=an,T=eng,Y=in uai,U=zh,I=sh,O=uo 0,P=ai,A=ch,S=ang,D=ie,F=ian,G=iang uang,H=ong iong,J=iu er,K=ei,L=uan,FH=ing,Z=ou,X=ia ua,B=iao,N=ui ve ue,M=un',
自然码:'Q=iu,W=ia ua,R=uan er,T=ve ue,Y=ing uai,U=sh,I=ch,O=uo,P=un,S=ong iong,D=iang uang,F=en,G=eng,H=ang,J=an,K=ao,L=ai,Z=ei,X=ie,C=iao,V=zh ui,B=ou,N=in,M=ian',
国标:'Q=ia ua,W=uan,R=en,T=ie,Y=iu uai,U=sh,I=ch,O=uo,P=ou,A=0,S=ong iong,D=ian,F=an,G=ang,H=eng,J=ing,K=ai,L=in er,Z=un,X=ue ve,C=ao,V=zh ui,B=ei,N=iang uang,M=iao',
大牛:'Q=ua ian,W=vn ei,E=0,R=ou,T=iu,Y=un,U=sh er,I=ch,O=zh uo,P=ie,A=zh,S=ao,D=an,F=ang,G=uai ing,H=ai ue,J=eng van,K=en ia,L=ong iong,Z=uan,X=ve uang,C=ian,V=sh ui,B=in,N=ui iang,M=iao',
飞猫:'Q=c uan,W=s ue ve,E=y ing uang,R=k in uai,T=g iu,Y=n eng vn,U=f an,I=m e,O=0 ou,P=d a,A=sh ang,S=l ei,D=d ian ua,F=ch un,G=h ui er iang,H=w uo o,J=j ao,K=q i,L=p u,Z=z v,X=b i,C=zh ie,V=r en ia,B=t iao,N=sh ong iong,M=x ai van',
UAI优化:'Q=iu,W=en,E=zh,R=ou,T=ue ve ui,Y=uan,U=sh,I=ch,O=uo 0,P=un,S=ao,D=ang,F=eng,G=ing er,H=ong iong,J=ai,K=an,L=ian uai,FH=iang uang,X=ia ua,C=ie,B=in,N=iao,M=ei',
UAI优化顶功:'Q=iu,W=en,E=zh,R=ou,T=ue ve ui,Y=uan,U=sh,I=ch,O=uo -,P=un,A=^,S=ao,D=ang,F=eng er,G=ing,H=ong iong,J=ai 0,K=an,L=ian uai,FH=iang uang \\,X=ia ua,C=ie,V=|,B=in,N=iao,M=ei,CH=/',
乱序优化:'Q=ua,W=x uan,E=q uang v,R=j ue ve ui,T=0 un,Y=c iu,U=g ing,I=k iong ou,O=h iang,P=ie,A=t ong,S=l ao,D=y ai,F=d an,G=n ang,H=r in,J=sh e,K=w i er,L=zh u,FH=ch a ia,Z=p ei,X=m en,C=f eng,V=b o uo,B=uai,N=s iao,M=z ian',
Expand Down Expand Up @@ -384,12 +386,12 @@ function read_pinyin_map_from_scheme(scheme) {
if (py == '') {
continue;
}
var existing_key = pinyin_map[py];
if (existing_key != null && existing_key != key) {
error += py + '在' + existing_key.toUpperCase() + '和'
+ key.toUpperCase() + '上\n';
if (py in pinyin_map) {
pinyin_map[py] += key;
error += py + '在' + pinyin_map[py].toUpperCase().split('').join('和') + '上\n';
} else {
pinyin_map[py] = key;
}
pinyin_map[py] = key;
}
}

Expand All @@ -403,7 +405,7 @@ function read_pinyin_map_from_scheme(scheme) {
return {pinyin_map: pinyin_map, error:error};
}

function pinyin_to_key_strokes(pinyin, sheng_yun_key_map) {
function pinyin_to_key_strokes(pinyin, sheng_yun_key_map, layout, is_staggered) {
var sheng_yun = split_pinyin(pinyin);
var sheng = sheng_yun.sheng;
var yun = sheng_yun.yun;
Expand All @@ -425,15 +427,19 @@ function pinyin_to_key_strokes(pinyin, sheng_yun_key_map) {
var error = '无法打出拼音' + pinyin + '=' + sheng + '+' + yun + '\n';
return {key_strokes: '', error: error};
}
return {key_strokes: sheng_key + yun_key, error: ''};
var best = get_multi_key_pair_time(sheng_key, yun_key, layout, is_staggered);
return {key_strokes: best.key_strokes, error: ''};
}

function all_pinyin_to_key_strokes(sheng_yun_key_map) {
var geometry = document.getElementById('geometry').value;
var is_staggered = (geometry == 'staggered');
var layout = get_layout();
var pinyin_key_map = {};
var key_pinyin_map = {};
var error = '';
for (var i = 0; i < all_pinyin.length; ++i) {
var conversion = pinyin_to_key_strokes(all_pinyin[i], sheng_yun_key_map);
var conversion = pinyin_to_key_strokes(all_pinyin[i], sheng_yun_key_map, layout, is_staggered);
if (conversion.error != '') {
return {pinyin_key_map: {}, error: conversion.error};
}
Expand All @@ -446,6 +452,7 @@ function all_pinyin_to_key_strokes(sheng_yun_key_map) {
conversion.key_strokes.toUpperCase() + '\n';
}
}
//console.log(pinyin_key_map);
return {pinyin_key_map: pinyin_key_map, error: error};
}

Expand Down Expand Up @@ -490,6 +497,10 @@ function convert_text_to_key_strokes(scheme_name, scheme) {
ignored_pinyins.add(pinyin);
continue;
}
if (!(pinyin in pinyin_key_map)) {
ignored += c;
continue;
}
key_strokes += pinyin_key_map[pinyin];
}
if (ignored_chars.size > 0) {
Expand Down Expand Up @@ -726,6 +737,38 @@ function total_pairs(pair_freq) {
return total;
}

function get_key_pair_time(first_key, second_key, layout, is_staggered) {
var x0 = layout[first_key][0];
var y0 = layout[first_key][1];
var x1 = layout[second_key][0];
var y1 = layout[second_key][1];

var f0 = column_finger[x0];
var f1 = column_finger[x1];
var same_hand = is_left(x0) == is_left(x1);

var d = press_depth;
if (f0 == f1) {
d += distance(x0, y0, x1, y1, is_staggered);
} else if (same_hand) {
d += distance(x0 + f1 - f0, y0, x1, y1, is_staggered);
}

return d / finger_speed[f1];
}

function get_multi_key_pair_time(sheng_keys, yun_keys, layout, is_staggered) {
var combo_costs = {}
for (var s in sheng_keys) {
for (var y in yun_keys) {
cost = get_key_pair_time(sheng_keys[s], yun_keys[y], layout, is_staggered);
combo_costs[sheng_keys[s] + yun_keys[y]] = cost;
}
}
var [best_combo] = Object.entries(combo_costs).sort(([ ,v1], [ ,v2]) => v1 - v2);
return {key_strokes: best_combo[0], hit_time: best_combo[1]};
}

function fast_evaluate_scheme(pinyin_map, pair_freq) {
var geometry = document.getElementById('geometry').value;
var is_staggered = (geometry == 'staggered');
Expand Down Expand Up @@ -755,24 +798,13 @@ function fast_evaluate_scheme(pinyin_map, pair_freq) {
if (second_key == null) {
second_key = second;
}
var x0 = layout[first_key][0];
var y0 = layout[first_key][1];
var x1 = layout[second_key][0];
var y1 = layout[second_key][1];

var f0 = column_finger[x0];
var f1 = column_finger[x1];
var same_hand = is_left(x0) == is_left(x1);

var d = press_depth;
if (f0 == f1) {
d += distance(x0, y0, x1, y1, is_staggered);
} else if (same_hand) {
d += distance(x0 + f1 - f0, y0, x1, y1, is_staggered);
if (first_key.length > 1 || second_key.length > 1) {
var best = get_multi_key_pair_time(first_key, second_key, layout, is_staggered);
time += best.hit_time * pair_freq[first][second];
} else {
var hit_time = get_key_pair_time(first_key, second_key, layout, is_staggered);
time += hit_time * pair_freq[first][second];
}

var hit_time = d / finger_speed[f1];
time += hit_time * pair_freq[first][second];
}
}
return time;
Expand All @@ -796,32 +828,26 @@ function improve_scheme() {
}
var first_pinyin = [];
for (var pinyin in pinyin_map) {
if (pinyin_map[pinyin] == first && first != pinyin) {
if (pinyin_map[pinyin].includes(first) && first != pinyin) {
first_pinyin.push(pinyin);
}
}
if (first_pinyin == []) {
continue;
}
for (var second in layout) {
if (first >= second || fixed_keys.includes(second)) {
continue;
}
var second_pinyin = [];
for (var pinyin in pinyin_map) {
if (pinyin_map[pinyin] == second && second != pinyin) {
if (pinyin_map[pinyin].includes(second) && second != pinyin) {
second_pinyin.push(pinyin);
}
}
if (second_pinyin == []) {
continue;
}
// Swap assignments.
for (var i = 0; i < first_pinyin.length; ++i) {
pinyin_map[first_pinyin[i]] = second;
pinyin_map[first_pinyin[i]] = pinyin_map[first_pinyin[i]].replace(first, second);
}
for (var i = 0; i < second_pinyin.length; ++i) {
pinyin_map[second_pinyin[i]] = first;
pinyin_map[second_pinyin[i]] = pinyin_map[second_pinyin[i]].replace(second, first);
}

var time = fast_evaluate_scheme(pinyin_map, sheng_yun_freq)
Expand All @@ -835,10 +861,10 @@ function improve_scheme() {

// Undo swap.
for (var i = 0; i < first_pinyin.length; ++i) {
pinyin_map[first_pinyin[i]] = first;
pinyin_map[first_pinyin[i]] = pinyin_map[first_pinyin[i]].replace(second, first);
}
for (var i = 0; i < second_pinyin.length; ++i) {
pinyin_map[second_pinyin[i]] = second;
pinyin_map[second_pinyin[i]] = pinyin_map[second_pinyin[i]].replace(first, second);
}
}
}
Expand Down

0 comments on commit 386559a

Please sign in to comment.