-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patheffort_calculator.py
152 lines (130 loc) · 4.36 KB
/
effort_calculator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import logging
import utils
import json
log = logging.getLogger("abbrgen")
finger_maping = [
[1, 2, 3, 4, 4, 5, 5, 6, 7, 8],
[1, 2, 3, 4, 4, 5, 5, 6, 7, 8],
[1, 2, 3, 4, 4, 5, 5, 6, 7, 8],
]
hand_row_maping = [
["tl", "tl", "tl", "tl", "tl", "tr", "tr", "tr", "tr", "tr"],
["ml", "ml", "ml", "ml", "ml", "mr", "mr", "mr", "mr", "mr"],
["bl", "bl", "bl", "bl", "bl", "br", "br", "br", "br", "br"],
]
# you can ban chords that you find uncomfortable, this left hand side is mirrored
banned_chords = [
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 1, 0, 0],
],
[
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0],
],
[
[1, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
],
]
class EffortCalculator:
def __init__(self, layout, effort_map):
self.layout = layout
self.effort_map = effort_map
self.layout_map = {}
self.effort_map = {}
self.hand_row_map = {}
for r in range(0, len(layout)):
for c in range(0, len(layout[r])):
self.layout_map[layout[r][c]] = finger_maping[r][c]
self.effort_map[layout[r][c]] = effort_map[r][c]
self.hand_row_map[layout[r][c]] = hand_row_maping[r][c]
self.banned_chords_sets = []
# Add mirrored chords and padding
mirrored = []
global banned_chords
padding = [0, 0, 0, 0, 0]
for ban in banned_chords:
mirror = []
for r in range(0, len(ban)):
mirror.append(padding + list(reversed(ban[r])))
ban[r] += padding
mirrored.append(mirror)
banned_chords += mirrored
for ban in banned_chords:
s = set()
for r in range(0, len(ban)):
for c in range(0, len(ban[r])):
if ban[r][c]:
s.add(layout[r][c])
self.banned_chords_sets.append(s)
def get_scissor_count(self, abbr):
result = 0
indexes = {
"tl": 0,
"ml": 0,
"bl": 0,
"tr": 0,
"mr": 0,
"br": 0,
}
for i in range(0, len(abbr)):
indexes[self.hand_row_map[abbr[i]]] += 1
if indexes["tl"] and indexes["bl"]:
result += min(indexes["tl"], indexes["bl"])
if indexes["tr"] and indexes["br"]:
result += min(indexes["tr"], indexes["br"])
return result
def get_sfb_count(self, abbr):
result = 0
indexes = {}
for i in range(0, len(abbr)):
index = self.layout_map[abbr[i]]
if not index in indexes:
indexes[index] = 1
else:
indexes[index] += 1
for x in indexes.values():
if x > 1:
result += x - 1
return result
def calculate(self, abbr, sfb_penalty, scissor_penalty, chorded_mode):
for i in range(0, len(abbr)):
if abbr[i] not in self.layout_map:
log.debug(f"rejected: letter '{abbr[i]}' not in keyboard layout")
return
scissor_count = self.get_scissor_count(abbr)
sfb_count = self.get_sfb_count(abbr)
if chorded_mode:
seen = set()
for char in abbr:
if char in seen:
log.debug(
"rejected: duplicate letters not accepted in chorded mode"
)
return
seen.add(char)
for ban in self.banned_chords_sets:
if ban.issubset(seen):
log.debug("rejected: banned chord")
return
if scissor_count:
log.debug("rejected: scissors not accepted in chorded mode")
return
if sfb_count:
log.debug("rejected: SFBs not accepted in chorded mode")
return
result = 0
for i in range(0, len(abbr)):
result += self.effort_map[abbr[i]]
if not chorded_mode:
if scissor_count:
log.debug("Applying scissor penalty")
result += scissor_count * scissor_penalty
if sfb_count:
log.debug("Applying SFB penalty")
result += sfb_count * sfb_penalty
return result