WIP
[evolve-layout.git] / C / config.cpp
blobc8f22e9cb6e90abf3246970bd1ee8ea841cbd7a4
1 #pragma once
2 //Configuration of check_neo, mainly the weights of the cost functions. Intended to be easily modified.
4 #include <string>
5 #include <map>
6 #include <vector>
8 #include "types.cpp"
10 // The mutated letters - only these get changed. You may change these to leave letters in their defined place.
11 std::string abc = "abcdefghijklmnopqrstuvwxyzäöüß,.";
13 // The letters which are used to calculate the costs - do not change anything or results will become incomparable.
14 std::string const abc_full = "abcdefghijklmnopqrstuvwxyzäöüß,.";
16 #define WEIGHT_POSITION 10 // reference cost - gets multiplied with the COST_PER_KEY.
18 #define WEIGHT_FINGER_REPEATS 256 // Cost of a finger repeat. Gets additional +1 from the row change on the same finger.
20 #define WEIGHT_FINGER_REPEATS_TOP_BOTTOM 2048 // Additional cost of a finger repetition from the top to the bottom line. Gets added to the cost of the normal finger repetition. Additionally this gets costs as row repetition on the same hand (+4).
22 #define WEIGHT_BIGRAM_ROW_CHANGE_PER_ROW 0.6f // When I have to switch the row in a bigram while on the same hand, that takes time => Penalty per (row to cross ² / horizontal distance)² if we’re on the same hand.
24 #define WEIGHT_COUNT_ROW_CHANGES_BETWEEN_HANDS false // Should we count a row change with a handswitch as row change?
26 #define WEIGHT_FINGER_DISBALANCE 500 // multiplied with the standard deviation of the finger usage - value guessed and only valid for the 1gramme.txt corpus.
28 #define WEIGHT_HAND_DISBALANCE 30 // Disbalance between the load on the hands. Calculated from the finger disbalance, but coarser. If both hands have slightly unequal load on the individual fingers, but overall both hands have the same load, the layout feels equal.
30 #define WEIGHT_TOO_LITTLE_HANDSWITCHING 300 // how high should it be counted, if the hands aren’t switched in a triple?
32 #define WEIGHT_NO_HANDSWITCH_AFTER_DIRECTION_CHANGE 1 // multipleir for triples without handswitch in which there also is a direction change? Also affects the “unweighted” result from total_cost!
33 #define WEIGHT_NO_HANDSWITCH_WITHOUT_DIRECTION_CHANGE 0 // multipier for triples without handswitch in in which the direction doesn’t change. Also affects the “unweighted” result from total_cost!
35 weight_t const WEIGHT_INTENDED_FINGER_LOAD_LEFT_PINKY_TO_RIGHT_PINKY[] = {
37 1.6,
38 2.6,
39 2.6, // is 1/3 faster
42 2.6,
43 2.6,
44 1.6,
45 1 }; // The intended load per finger. Inversed and then used as multiplier for the finger load before calculating the finger disbalance penalty. Any load distribution which strays from this optimum gives a penalty.
47 #define WEIGHT_XCVZ_ON_BAD_POSITION 0.2f // the penalty *per letter* in the text if xvcz are on bad positions (cumulative; if all 4 are on bad positions (not in the first 5 keys, counted from the left side horizontally) we get 4 times the penalty).
49 #define WEIGHT_FINGER_SWITCH 20 // how much worse is it to switch from middle to indexfinger compared with middle to pinky (~30ms according to Rohmert).
51 enum fingers {
52 l_pinky, l_ring, l_middle, l_index, l_thumb,
53 r_thumb, r_index, r_middle, r_ring, r_pinky,
55 struct finger_cost {
56 fingers finger;
57 cost_t cost;
59 // The cost for moving from one finger to another one with middle-to-index as 1 (30ms). Currently only uses the neighbors. Can also be used to favor a certain direction. Adapted the Rohmert times as per my own experiences: http://lists.neo-layout.org/pipermail/diskussion/2010-May/017171.html and http://lists.neo-layout.org/pipermail/diskussion/2010-May/017321.html
60 finger_cost FINGER_SWITCH_COST[][2] = { // iu td < ui dt dr ua rd au < ai rt < nd eu
61 /*l_pinky*/ { {l_ring, 3}, {l_middle, 3} }, // ring, middle
62 /*l_ring*/ { {l_pinky, 4}, {l_middle, 3} }, // pinky, middle
63 /*l_middle*/ { {l_pinky, 1}, {l_ring, 2} }, // pinky, ring
64 /*l_index*/ { {l_pinky, 1} }, // pinky
65 /*l_thumb*/ { },
66 /*r_thumb*/ { },
67 /*r_index*/ { {r_pinky, 1} }, // pinky
68 /*r_middle*/ { {r_ring, 2}, {r_pinky, 1} }, // ring, pinky
69 /*r_ring*/ { {r_middle, 3}, {r_pinky, 4} }, // middle, pinky
70 /*r_pinky*/ { {r_middle, 3}, {r_ring, 3} }, // middle, ring
71 }; // iutd, drua, uidt, rdau, airt, ndeu :)
73 #define WEIGHT_NO_HANDSWITCH_AFTER_UNBALANCING_KEY 20 // How much penalty we want if there’s no handswitching after an unbalancing key. Heavy unbalancing (wkßz, M3 right, return and the shifts) counts double (see UNBALANCING_POSITIONS). This also gives a penalty for handswitching after an uppercase letter.
75 struct position {
76 int row; // row 1: numberrow
77 int col; // cols left->right, col 1: leftmost
78 cost_t cost; // cost for this position
80 bool operator<(const position &p) const {
81 if(this->row == p.row)
82 return this->col < p.col;
83 return this->row < p.row;
87 // Positions which pull the hand from the base row, position and cost (the strength of the pulling from base row).
88 std::map<position, cost_t> UNBALANCING_POSITIONS;
89 static void init_UNBALANCING_POSITIONS() {
90 UNBALANCING_POSITIONS[(position) {1, 0, 0}] = 2; // Tab
91 UNBALANCING_POSITIONS[(position) {1, 1, 0}] = 1; // x
92 UNBALANCING_POSITIONS[(position) {1, 5, 0}] = 2; // w
93 UNBALANCING_POSITIONS[(position) {1, 6, 0}] = 2; // k
94 UNBALANCING_POSITIONS[(position) {1, 10, 0}] = 1; // q
95 UNBALANCING_POSITIONS[(position) {1, 11, 0}] = 2; // ß
96 UNBALANCING_POSITIONS[(position) {2, 0, 0}] = 2; // L_M3
97 UNBALANCING_POSITIONS[(position) {2, 5, 0}] = 1; // o
98 UNBALANCING_POSITIONS[(position) {2, 6, 0}] = 1; // s
99 UNBALANCING_POSITIONS[(position) {2, 11, 0}] = 1; // y
100 UNBALANCING_POSITIONS[(position) {2, 12, 0}] = 2; // R_M3
101 UNBALANCING_POSITIONS[(position) {2, 13, 0}] = 2; // Return
102 UNBALANCING_POSITIONS[(position) {3, 0, 0}] = 2; // L_Shift
103 UNBALANCING_POSITIONS[(position) {3, 12, 0}] = 2; // R_Shift
104 UNBALANCING_POSITIONS[(position) {3, 6, 0}] = 2; // z
107 // Structured key weighting (but still mostly from experience and deducing from the work of others).
108 // The speed of the fingers is taken out (see INTENDED_FINGER_LOAD_LEFT_PINKY_TO_RIGHT_PINKY).
109 // So this shows the reachability of the keys, ignoring the different speed of the fingers.
110 // “How much does the hand hurt when reaching for the key” :)
111 // rationale: reaching for the Neo 2 x hurts thrice as much as just hitting the Neo2 u → 10 vs. 3.
112 // the upper keys on the right hand can be reached a bit better, since movement is aligned with the hand
113 // (except for q, since the pinky is too short for that).
114 // theoretical minimum (assigning the lowest cost to the most frequent char, counting only the chars on layer 1):
115 // 1123111113 = 3.3490913205386508 mean key position cost
116 // Ringfinger on lower row takes 1.5 times the time of index on the upper row[1].
117 // [1]: http://forschung.goebel-consult.de/de-ergo/rohmert/Rohmert.html - only one person!
119 /*cost_t const COST_PER_KEY[][14] = {
120 // The 0 values aren’t filled in at the moment.
121 // Don’t put mutated keys there, otherwise the best keys will end up there!
122 {50, 40,35,30,30, 35, 40,35,30,30,30,35,40,50}, // Zahlenreihe (0)
123 {24, 20, 6, 5, 6, 9, 10, 5, 4, 5, 8,24,36, 0}, // Reihe 1
124 {12, 3, 3, 3, 3, 5, 5, 3, 3, 3, 3, 5,10,18}, // Reihe 2
125 {15,10,12,24,20, 10, 30, 7, 6,22,22,10, 15}, // Reihe 3
126 {0,0,0, 3 , 0, 0, 0, 0} // Reihe 4 mit Leertaste
127 };*/
128 cost_t const COST_PER_KEY[] = {
129 // The 0 values aren’t filled in at the moment.
130 // Don’t put mutated keys there, otherwise the best keys will end up there!
131 //50, 40,35,30,30, 35, 40,35,30,30,30,35,40,50, // Zahlenreihe (0)
132 // x , v, l, c, w, k , h, g, f, q,ß ,´
133 20, 6, 5, 6, 9, 10, 5, 4, 5, 8,24,36, // Reihe 1
134 // u, i, a, e, o, s, n, r, t, d, y
135 3, 3, 3, 3, 5, 5, 3, 3, 3, 3, 5, // Reihe 2
136 // ü ,ö ,ä , p , z , b, m,, ,. ,j
137 12,24,20, 10, 30, 7, 6,22,22,10, // Reihe 3
138 //0,0,0, 3 , 0, 0, 0, 0 // Reihe 4 mit Leertaste
140 cost_t const COST_LAYER_ADDITION[] = {0, 15, 12, 10, 27, 22};
142 #define COST_PER_KEY_NOT_FOUND 60
144 // for reference the neo layout
145 //NEO = [
146 // [("^"),("1"),("2"),("3"),("4"),("5"),("6"),("7"),("8"),("9"),("0"),("-"),("`"),("←")], # Zahlenreihe (0)
147 // [("⇥"),("x"),("v"),("l"),("c"),("w"),("k"),("h"),("g"),("f"),("q"),("ß"),("´"),()], # Reihe 1
148 // [("⇩"),("u"),("i"),("a"),("e"),("o"),("s"),("n"),("r"),("t"),("d"),("y"),("⇘"),("\n")], # Reihe 2
149 // [("⇧"),(),("ü"),("ö"),("ä"),("p"),("z"),("b"),("m"),(","),("."),("j"),("⇗")], # Reihe 3
150 // [(), (), (), (" "), (), (), (), ()] # Reihe 4 mit Leertaste
154 // not used atm, should allow "hash access" to positions
155 struct finger_positions {
156 position klein;
157 position ring;
158 position mittel;
159 position zeige;
160 position daumen;
162 struct hand_positions {
163 finger_positions l;
164 finger_positions r;
166 // The positions which are by default accessed by the given finger.
167 // + layer
168 position FINGER_POSITIONS[][9] = {
169 /*l_pinky*/ {{1, 1, 0}, {2, 0, 0}, {2, 1, 0}, {3, 0, 0}, {3, 1, 0}, {3, 2, 0}},
170 /*l_ring*/ {{1, 2, 0}, {2, 2, 0}, {3, 3, 0}},
171 /*l_middle*/ {{1, 3, 0}, {2, 3, 0}, {3, 4, 0}},
172 /*l_index*/ {{1, 4, 0}, {2, 4, 0}, {3, 5, 0}, {1, 5, 0}, {2, 5, 0}, {3, 6, 0}},
173 /*l_thumb*/ {{4, 3, 0}},
174 /*r_thumb*/ {{4, 3, 0}},
175 /*r_index*/ {{1, 6, 0}, {2, 6, 0}, {3, 7, 0}, {1, 7, 0}, {2, 7, 0}, {3, 8, 0}},
176 /*r_middle*/ {{1, 8, 0}, {2, 8, 0}, {3, 9, 0}},
177 /*r_ring*/ {{1, 9, 0}, {2, 9, 0}, {3, 10, 0}},
178 /*r_pinky*/ {{1, 10, 0}, {2, 10, 0}, {3, 11, 0}, {1, 11, 0}, {2, 11, 0}, {1, 12, 0}, {2, 12, 0}, {2, 13, 0}, {3, 12, 0}}
181 // call in main to initialize maps
182 void init_config() {
183 init_UNBALANCING_POSITIONS();