root/akl/akl.awk

Revision 985, 6.3 kB (checked in by alpt, 2 years ago)

Initial revision

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/bin/gawk -f
2 #
3 #                       Automatic keyboard layout
4 #               http://www.freaknet.org/alpt/src/misc/akl/akl.awk
5 #
6 # --
7 #
8 # A program which, given a text as input, computes the most efficient keyboard
9 # layout for the given text.
10 #
11 # "Most efficient keyboard layout" means a layout which permits to write the
12 # given text in the fastest and easiest way.
13 #
14 # *** Usage
15 #
16 #       ./akl.awk < input | less -R
17 #
18 # Note: the non printable ASCII character are printed in their hexadecimal
19 # form.
20 #
21 # *** Example
22 #
23 #$ echo idiki the wiki | ./akl.awk
24 #,___________________.
25 #|___|___|___|___|___|
26 #|___|_t_|_d_|___|___|
27 #|___|_h_|_i_|_w_|___|
28 #|___|_e_|_k_|_ _|___|
29 #|___|___|___|___|___|
30 #
31 #,_______________________.
32 #|___|___|___|___|___|___|
33 #|___|___|_t_|_h_|_e_|___|
34 #|___|___|_d_|_i_|_k_|___|
35 #|___|___|___|_w_|_ _|___|
36 #|___|___|___|___|___|___|
37 #
38 # *** Algorithm
39 #       
40 #       - build the frequency list for each pair of keys
41 #       
42 #       - sort the list and traverse it, starting from the most frequent
43 #         pair
44 #
45 #               - Let (a,b) be the current pair
46 #
47 #               - If  a  has been previously added in the layout matrix, set
48 #                 p=coordinates_of_a
49 #
50 #               - If  a  doesn't exists in the layout matrix, try the swapped
51 #                 pair: t=b, b=a, a=t
52 #
53 #               - If  a  still doesn't exist, find the a key  p  in the
54 #                 layout matrix such that (p,a) is an existing pair and the
55 #                 frequency of (p,a) is higher than (x,a), for any valid
56 #                 x.
57 #
58 #               - Find, in the layout matrix, the nearest empty points to  p.
59 #
60 #               - Choose the nearest empty point  e  to  p  in term of
61 #                 frequency, i.e. (e,p) must be higher than any other (e',p).
62 #
63 #               - Add  b  in  e.
64 #
65 #
66 # AlpT (@freaknet.org)
67 #
68
69
70 # ord.awk --- do ord and chr
71 # Global identifiers:
72 #    _ord_:        numerical values indexed by characters
73 #    _ord_init:    function to initialize _ord_
74 #
75 # Arnold Robbins, arnold@gnu.org, Public Domain
76 # 16 January, 1992
77 # 20 July, 1992, revised
78 BEGIN    { _ord_init() }
79
80 function _ord_init(    low, high, i, t)
81 {
82     low = sprintf("%c", 7) # BEL is ascii 7
83     if (low == "\a") {    # regular ascii
84         low = 0
85         high = 127
86     } else if (sprintf("%c", 128 + 7) == "\a") {
87         # ascii, mark parity
88         low = 128
89         high = 255
90     } else {        # ebcdic(!)
91         low = 0
92         high = 255
93     }
94
95     for (i = low; i <= high; i++) {
96         t = sprintf("%c", i)
97         _ord_[t] = i
98     }
99 }
100 function ord(str,    c)
101 {
102     # only first character is of interest
103     c = substr(str, 1, 1)
104     return _ord_[c]
105 }
106 function chr(c)
107 {
108     # force c to be numeric by adding 0
109     return sprintf("%c", c + 0)
110 }
111
112
113
114 function frequencies(str,         i,a,b)
115 {
116         strl=length(str)
117
118         for(i=1; i<=strl-1; i++) {
119                 a=substr(str, i,1)
120                 b=substr(str, i+1,1)
121
122                 freq[a,b]++
123                 freq[b,a]++
124                 singlefreq[a]++
125         }
126 }
127
128 function buildmatrix(              i, maxf, maxfi, idx)
129 {
130         # Choose the most frequent key and put it in x=0,y=0
131         maxf=0
132         for(i in singlefreq) {
133                 if(singlefreq[i] >= maxf) {
134                         maxf=singlefreq[i]
135                         maxfi=i
136                 }
137         }
138         layout[0,0]=maxfi
139         hl[maxfi]=(0 SUBSEP 0)
140
141         # Sort the `freq' array
142         for(i in  freq) {
143                 if((freq[i]) in freqi)
144                         freqi[freq[i]]=(freqi[freq[i]] ":J:" i)
145                 else
146                         freqi[freq[i]]=(i)
147         }
148         n = asorti(freqi, freqis)
149
150         # Traverse the sorted array
151         for(i=n; i>=1; i--) {
152                 idx=freqis[i]
153                 e=split(freqi[idx], links, ":J:")
154                 for(x=1; x<=e; x++) {
155                         if(split(links[x], a, SUBSEP) >= 2) {
156                                 add_layout(a[1], a[2])
157                         }
158                 }
159         }
160 }
161
162 function add_layout(a, b,       d, i, max, x, y, pxy, fxy, f, xx,yy,p,r)
163 {
164
165         if(!((a) in hl)) {
166                 t=a
167                 a=b
168                 b=t
169         }
170        
171         if(!((a) in hl)) {
172                 max=0
173                 p=""
174                 for(i in layout) {
175                         if(!((a,layout[i]) in freq))
176                                 continue
177
178                         f=freq[a,layout[i]]
179                         if(max < f) {
180                                 max=f
181                                 p=i
182                         }
183                 }
184                 if(!p)
185                         p=(0 SUBSEP 0)
186                 #print "add_layout2 ", layout[p], a, p
187                 add_layout(layout[p], a)
188         }
189
190         if(((b) in hl)) {
191                 #print "'"b"' rejected"
192                 return 0
193         }
194
195         p=hl[a]
196         split(p, pxy, SUBSEP)
197         #print "add_layout ", "'"a"'", "'"b"'", pxy[1], pxy[2]
198
199         for(r=1;  ; r++) {
200                 f=0
201                 delete foundxy
202
203                 y=pxy[2]
204                 for(x=pxy[1]-r+1; x <= pxy[1]+r-1; x++) {
205                         if(((x, y-r) in layout) && ((x, y+r) in layout))
206                                 continue
207
208                         if(!((x, y-r) in layout)) {
209                                 foundxy[++f]=(x SUBSEP y-r)
210                         } else if(!((x, y+r) in layout)) {
211                                 foundxy[++f]=(x SUBSEP y+r)
212                         }
213                 }
214
215                 x=pxy[1]
216                 for(y=pxy[2]-r+1; y <= pxy[2]+r-1; y++) {
217                         if(((x-r, y) in layout) && ((x+r, y) in layout))
218                                 continue
219
220                         if(!((x-r, y) in layout)) {
221                                 foundxy[++f]=(x-r SUBSEP y)
222                         } else if(!((x+r, y) in layout)) {
223                                 foundxy[++f]=(x+r SUBSEP y)
224                         }
225                 }
226
227                 if(!f) {
228                         #try the corners
229
230                         x=pxy[1]-r; y=pxy[2]-r
231                         if(!((x, y) in layout))
232                                 foundxy[++f]=(x SUBSEP y)
233                         x=pxy[1]-r; y=pxy[2]+r
234                         if(!((x, y) in layout))
235                                 foundxy[++f]=(x SUBSEP y)
236                         x=pxy[1]+r; y=pxy[2]-r
237                         if(!((x, y) in layout))
238                                 foundxy[++f]=(x SUBSEP y)
239                         x=pxy[1]+r; y=pxy[2]+r
240                         if(!((x, y) in layout))
241                                 foundxy[++f]=(x SUBSEP y)
242                 }
243
244                 if(f)
245                         break
246         }
247
248         max=0
249         maxi=1
250         for(i=1; i<=f; i++) {
251                 split(foundxy[i], fxy, SUBSEP)
252
253                 for(xx=-1; xx<=1; xx++)
254                         for(yy=-1; yy<=1; yy++) {
255                                 if(!((b, fxy[1]+xx,fxy[2]+yy) in layout))
256                                         continue
257                                 f=freq[b, layout[fxy[1]+xx,fxy[2]+yy] ]
258                                 if(max < f) {
259                                         max=f
260                                         maxi=i
261                                 }
262                         }
263         }
264
265         hl[b]=foundxy[maxi]
266         layout[hl[b]]=b
267         #print "new", foundxy[maxi], "'"b"'", layout[hl[b]]
268 }
269
270 function abs(n)
271 {
272         return n >= 0 ? n : -n;
273 }
274
275 function c2c(c)
276 {
277         if(c == "_" || c !~ /[[:print:]]/)
278                 c=sprintf("x%02x", ord(c))
279         else
280                 c="_"toupper(c)"_"
281         return c
282 }
283
284 function print_layout(       i,p, x,y, maxx, maxy,c)
285 {
286         maxx=maxy=0
287         for(i in layout) {
288                 split(i, p, SUBSEP)
289
290                 if(maxx < p[1])
291                         maxx=abs(p[1])*2
292                 if(maxy < p[2])
293                         maxy=abs(p[2])*2
294         }
295
296         printf(",")
297         for(x=-maxx*5; x<=5*maxx-2; x++)
298                 printf("_")
299         printf(".\n")
300         for(y=+maxy; y>=-maxy; y--) {
301                 if((+maxx,y) in layout) {
302                         printf("|%s|", c2c(layout[+maxx,y]))
303                 } else
304                         printf("|___|")
305                 for(x=+maxx-1; x>=-maxx; x--) {
306                         if((x,y) in layout) {
307                                 printf("%s|", c2c(layout[x,y]))
308                         } else
309                                 printf("___|")
310                 }
311                 printf("\n")
312         }
313         printf("\n")
314
315         printf(",")
316         for(y=-maxy*5; y<=5*maxy+2; y++)
317                 printf("_")
318         printf(".\n")
319         for(x=+maxx; x>=-maxx; x--) {
320                 if((+maxx,y) in layout) {
321                         printf("|%s|", c2c(layout[+maxx,y]))
322                 } else
323                         printf("|___|")
324
325                 for(y=+maxy; y>=-maxy; y--) {
326                         if((x,y) in layout) {
327                                 printf("%s|", c2c(layout[x,y]))
328                         } else
329                                 printf("___|")
330                 }
331                 printf("\n")
332         }
333         printf("\n")
334 }
335
336 {
337         INPUT=INPUT "\n" tolower($0)
338 }
339
340 END {
341         frequencies(INPUT)
342         buildmatrix()
343         print_layout()
344 }
Note: See TracBrowser for help on using the browser.