aboutsummaryrefslogtreecommitdiff
path: root/src/layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout.rs')
-rw-r--r--src/layout.rs186
1 files changed, 109 insertions, 77 deletions
diff --git a/src/layout.rs b/src/layout.rs
index bc476c8..9662b84 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1,8 +1,34 @@
-use crate::config::*;
+use crate::corpus::*;
use rand::prelude::*;
use std::fmt;
+pub const NUM_KEYS: usize = 30;
+pub const ROW_LENGTH: usize = 10;
+
+pub const KEY_CHARS: [char; NUM_KEYS] = [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '/', '.', ',', '\'',
+];
+
+pub fn canonicalise(inp: char) -> Option<char> {
+ if inp.is_ascii_alphabetic() {
+ return Some(inp.to_ascii_uppercase());
+ } else {
+ match inp {
+ '.' => Some('.'),
+ '>' => Some('.'),
+ ',' => Some(','),
+ '<' => Some(','),
+ '/' => Some('/'),
+ '?' => Some('/'),
+ '\'' => Some('\''),
+ '"' => Some('\''),
+ _ => None,
+ }
+ }
+}
+
#[derive(Copy, Clone)]
pub struct Prelayout {
standard_columns: [[char; 3]; 6],
@@ -95,28 +121,12 @@ impl Prelayout {
index_columns,
}
}
-
- fn to_char_array(&self) -> [char; NUM_KEYS] {
- let mut result = ['x'; NUM_KEYS];
-
- for i in 0..6 {
- let ind = if i < 3 { i } else { i + 4 };
- for j in 0..3 {
- result[ind + j * ROW_LENGTH] = self.standard_columns[i][j];
- }
- }
-
- for j in 0..3 {
- result[3 + j * ROW_LENGTH] = self.index_columns[0][j];
- result[6 + j * ROW_LENGTH] = self.index_columns[1][j];
- result[4 + j * ROW_LENGTH] = self.index_columns[0][j + 3];
- result[5 + j * ROW_LENGTH] = self.index_columns[1][j + 3];
- }
-
- result
- }
}
+const KEY_TO_FINGER: [usize; NUM_KEYS] = [
+ 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 0, 1, 2, 3, 3, 4, 4, 5, 6, 7, 0, 1, 2, 3, 3, 4, 4, 5, 6, 7,
+];
+
#[derive(Copy, Clone)]
pub struct Layout {
keys: [char; NUM_KEYS],
@@ -127,9 +137,69 @@ impl Layout {
Prelayout::from_char_array(&self.keys)
}
- pub fn from_prelayout(pl: &Prelayout) -> Layout {
- // TODO: something more clever about permuting colums, keys within columns etc
- Layout::char_array_to_layout(pl.to_char_array())
+ pub fn from_prelayout(pl: &Prelayout, corpus: &Corpus) -> Layout {
+ fn weight_function<const N: usize, const M: usize>(
+ columns: &[[char; N]; M],
+ corpus: &Corpus,
+ ) -> Vec<(Vec<char>, u32)> {
+ let mut result = columns
+ .iter()
+ .map(|col| {
+ let mut weight = 0;
+ let mut wcol: Vec<(char, u32)> = col
+ .iter()
+ .map(|&c| {
+ let w = corpus.get_character_count(c);
+ weight += w;
+ (c, w)
+ })
+ .collect();
+ wcol.sort_by(|(_, l), (_, r)| r.cmp(l));
+ wcol.swap(0, 1);
+ if N == 6 {
+ wcol.swap(3, 4);
+ }
+ (wcol.into_iter().map(|(k, _)| k).collect(), weight)
+ })
+ .collect::<Vec<(Vec<char>, u32)>>();
+ result.sort_by(|(_, l), (_, r)| r.cmp(l));
+ result
+ }
+
+ let mut balance: i64 = 0;
+ let mut left_col: usize = 0;
+ let mut right_col: usize = 9;
+ let mut keys = ['x'; NUM_KEYS];
+
+ let mut w_standard_columns = weight_function(&pl.standard_columns, corpus);
+ while let Some((col, weight)) = w_standard_columns.pop() {
+ let left: bool = ((balance >= 0) && (left_col <= 2)) || (right_col <= 6);
+ let ind = if left { left_col } else { right_col };
+ for i in 0..3 {
+ keys[ind + i * ROW_LENGTH] = col[i];
+ }
+ if left {
+ left_col += 1;
+ } else {
+ right_col -= 1;
+ }
+ balance += if left {
+ -(weight as i64)
+ } else {
+ weight as i64
+ };
+ }
+
+ let w_index_columns = weight_function(&pl.index_columns, corpus);
+ let (left_ind, right_ind) = if balance >= 0 { (0, 1) } else { (1, 0) };
+ for j in 0..3 {
+ keys[3 + j * ROW_LENGTH] = w_index_columns[left_ind].0[j];
+ keys[6 + j * ROW_LENGTH] = w_index_columns[right_ind].0[j];
+ keys[4 + j * ROW_LENGTH] = w_index_columns[left_ind].0[j + 3];
+ keys[5 + j * ROW_LENGTH] = w_index_columns[right_ind].0[j + 3];
+ }
+
+ Layout { keys }
}
pub fn get_index(&self, c: char) -> usize {
@@ -169,21 +239,6 @@ impl Layout {
return Some(Layout::char_array_to_layout(layout));
}
-
- // pub fn new_random_from<R: RngCore>(kbd: &Layout, rng: &mut R) -> Layout {
- // let mut layout = kbd.keys;
- // // layout.shuffle(rng);
- // let mut count = rng.gen_range(1..=NUM_KEYS / 2);
- // while count > 0 {
- // let a = rng.gen_range(0..NUM_KEYS);
- // let b = rng.gen_range(0..NUM_KEYS);
- // let k = layout[b];
- // layout[b] = layout[a];
- // layout[a] = k;
- // count -= 1;
- // }
- // Layout::char_array_to_layout(layout)
- // }
}
impl fmt::Display for Layout {
@@ -212,10 +267,7 @@ impl Evaluation {
let mut result = String::new();
let tot = self.total_keypress as f32;
- result += &format!(
- "Total keypresses: {}\nPercent per key:\n",
- self.total_keypress
- );
+ result += &"Percent per key:\n";
result += &format_block_output(self.keypress.into_iter().map(|k| 100.0 * k as f32 / tot));
let mut finger_usages = [0; 8];
@@ -223,16 +275,22 @@ impl Evaluation {
finger_usages[KEY_TO_FINGER[i]] += c;
}
- result += "finger usage: ";
+ result += "\nFinger usage: ";
+ let mut lh: f32 = 0.0;
+ let mut rh: f32 = 0.0;
for (i, &u) in finger_usages.iter().enumerate() {
- result += &format!(
- "{:>5.2}%{}",
- u as f32 / tot * 100.0,
- if i < 7 { ", " } else { "" }
- );
+ let f = u as f32 / tot * 100.0;
+ result += &format!("{:>5.2}%{}", f, if i < 7 { ", " } else { "" });
+ if i % 10 < 4 {
+ lh += f;
+ } else {
+ rh += f;
+ }
}
- result += "\nsame finger bigrams: ";
+ result += &format!("\nHand usage: {:.2}% vs {:.2}%", lh, rh);
+
+ result += "\nSame finger bigrams: ";
for (i, &u) in self.sfb.iter().enumerate() {
result += &format!(
"{:>6.3}%{}",
@@ -242,36 +300,10 @@ impl Evaluation {
}
let sfb = self.sfb.iter().sum::<u32>();
- result += &format!("\ntotal sfb: {:.2}% ({})", sfb as f32 / tot * 100.0, sfb);
+ result += &format!("\nTotal sfb: {:.2}% ({})", sfb as f32 / tot * 100.0, sfb);
return result;
}
-
- // TODO
- // pub fn fitness(&self) -> f32 {
- // let mut finger_usages = [0; 8];
- // let tot = self.total_keypress as f32;
- // for (i, &c) in self.keypress.iter().enumerate() {
- // finger_usages[KEY_TO_FINGER[i]] += c;
- // }
- // const MAX_FINGER_USAGES: [f32; 8] = [8.0, 11.0, 21.0, 21.0, 21.0, 21.0, 11.0, 8.0];
- // const MAX_FINGER_USAGES: [f32; 8] =
- // [100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0];
- // if finger_usages
- // .iter()
- // .enumerate()
- // .any(|(i, &c)| c as f32 / tot * 100.00 > MAX_FINGER_USAGES[i])
- // {
- // std::u32::MAX
- // } else {
- // self.sfb
- // .iter()
- // .enumerate()
- // .map(|(i, &s)| s as f32 / finger_usages[i] as f32 * 50.0)
- // .sum()
- // }
- // self.sfb.iter().sum::<u32>() as f32
- // }
}
impl fmt::Display for Evaluation {