-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdistance.go
117 lines (93 loc) · 2.26 KB
/
distance.go
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
package keyboard
import (
"math"
)
// Layout is the type used to define keyboard layouts
type Layout string
// Predefined keyboard layouts
const (
Default Layout = QwertyUS
QwertyUS Layout = "qwerty-us"
)
type keyGrid map[string]coordinates
var (
// @todo this design currently ignores the possibility of pressing the shift key while typing
// we might want to allow printable symbols with the same coordinates as their un-shifted counterfeit
keyboardLayouts = map[Layout][]string{
QwertyUS: {
"`1234567890-=",
" qwertyuiop[]\\",
" asdfghjkl;'",
" zxcvbnm,./",
},
/*
"azerty-fr": {
"&é\"'(-è çà)=",
"azertyuiop $",
"qsdfghjklmù*",
"<wxcvbn,;:!",
},
*/
}
)
type coordinates struct {
X float64
Y float64
}
// KeyDist is the type that allows to find the best alternative based on keyboard layouts
type KeyDist struct {
grid keyGrid
}
// New produces a new instance of KeyDist, based on the keyboard layout you choose
func New(l Layout) KeyDist {
return KeyDist{
grid: generateKeyGrid(keyboardLayouts[l]),
}
}
// FindNearest finds the item in the list that is nearest to the input, based on the keyboard layout
func (kd KeyDist) FindNearest(input string, list []string) (string, float64) {
var bestScore = math.Inf(1)
var result string
for _, ref := range list {
var score float64
// Scanning each letter of this ref
for i := 0; i < len(input); i++ {
if i >= len(ref) {
// @todo missing characters should have a cost, decide on a correct punishment value
score += float64(1 * (len(input) - len(ref)))
break
}
if input[i] == ref[i] {
continue
}
left, right := input[i:i+1], ref[i:i+1]
score += getDistance(kd.grid[left], kd.grid[right])
}
if score < bestScore {
bestScore = score
result = ref
}
}
return result, bestScore
}
func getDistance(a, b coordinates) float64 {
return math.Sqrt(
math.Pow(b.X-a.X, 2) + math.Pow(b.Y-a.Y, 2),
)
}
func generateKeyGrid(rows []string) keyGrid {
var keyMap = make(keyGrid, len(rows))
for rowIndex, row := range rows {
for column, char := range row {
character := string(char)
if character == " " {
continue
}
keyMap[character] = coordinates{
X: float64(column),
Y: float64(rowIndex),
}
}
}
return keyMap
}