1 // Copyright © Tavian Barnes <tavianator@tavianator.com>
2 // SPDX-License-Identifier: 0BSD
10 // Assume QWERTY layout for now
11 static const int8_t key_coords[UCHAR_MAX + 1][3] = {
115 static int char_distance(char a, char b) {
116 const int8_t *ac = key_coords[(unsigned char)a], *bc = key_coords[(unsigned char)b];
118 for (int i = 0; i < 3; ++i) {
119 ret += abs(ac[i] - bc[i]);
124 int typo_distance(const char *actual, const char *expected) {
125 // This is the Wagner-Fischer algorithm for Levenshtein distance, using
126 // Manhattan distance on the keyboard for individual characters.
128 const int insert_cost = 12;
130 size_t rows = strlen(actual) + 1;
131 size_t cols = strlen(expected) + 1;
133 int arr0[cols], arr1[cols];
134 int *row0 = arr0, *row1 = arr1;
136 for (size_t j = 0; j < cols; ++j) {
137 row0[j] = insert_cost * j;
140 for (size_t i = 1; i < rows; ++i) {
141 row1[0] = row0[0] + insert_cost;
143 char a = actual[i - 1];
144 for (size_t j = 1; j < cols; ++j) {
145 char b = expected[j - 1];
146 int cost = row0[j - 1] + char_distance(a, b);
147 int del_cost = row0[j] + insert_cost;
148 if (del_cost < cost) {
151 int ins_cost = row1[j - 1] + insert_cost;
152 if (ins_cost < cost) {
163 return row0[cols - 1];