#!/usr/local/bin/perl # # computes mechanical distances between keystrokes # $Id: exp.pl,v 1.2 1999/04/08 17:10:58 jonh Exp jonh $ $dvorak = ['\',.pyfgcrl', 'aoeuidhtns', ';qjkxbmwvz']; $qwerty = [ 'qwertyuiop', 'asdfghjkl;', 'zxcvbnm,./']; sub posmap { my $keyboard = shift; my $rowxbase = [0, 3/16, 9/16]; my @finger = split(//, '0123344567'); my $posmap = {}; for (my $rowi = 0; $rowi<3; $rowi++) { my $row = $keyboard->[$rowi]; my @keys = split(//, $row); for (my $keyi = 0; $keyi<@keys; $keyi++) { my $key = $keys[$keyi]; if (isalpha($key)) { my $x = 0.75*$keyi+$rowxbase->[$rowi]; my $y = 0.75*$rowi; $posmap->{$key} = [$x, $y, ($keyi<5?'0':'1'), $finger[$keyi]]; } } } return $posmap; } sub isalpha { my $key = shift; my $result = $key=~m/[a-z]/i; return $result; } sub pairmap { my $posmap = shift; my $pairmap = {}; for (my $k0='a'; $k0 le 'z'; $k0 = ($k0 eq 'z') ? '~' : ++$k0) { for (my $k1='a'; $k1 le 'z'; $k1 = ($k1 eq 'z') ? '~' : ++$k1) { my ($x0,$y0,$s0) = @{$posmap->{$k0}}; my ($x1,$y1,$s1) = @{$posmap->{$k1}}; my $alter = $s0 ne $s1; my $dist = sqrt(sqr($x0-$x1)+sqr($y0-$y1)); $pairmap->{$k0.$k1} = [$dist, $alter]; } } return $pairmap; } sub sqr { return $_[0]*$_[0]; } sub testposmap { my $map = posmap($qwerty); my @list = map { sprintf("%s: %3.2f %3.2f %s %1d\n", $_, $map->{$_}->[0], $map->{$_}->[1], $map->{$_}->[2], $map->{$_}->[3]) } sort keys %{$map}; print join('', @list); } sub testpairmap { my $map = pairmap(posmap($qwerty)); my @list = map { sprintf("%s: %3.2f %1d\n", $_, $map->{$_}->[0], $map->{$_}->[1]) } sort keys %{$map}; print join('', @list); } sub processfile { my $posmap = shift; my $pairmap = shift; my $filename = shift; open (FILE, "<$filename") || die "opening $filename: $!"; my @data = ; close FILE; my $string = join('', @data); my $cumdist = 0; my $cumalter = 0; my $cumalpha = 0; my @lastcharonhand = ('', ''); # previous character this hand had to type my $lastchar; # previous character typed my $lasthand; # hand used to type previous character my @lastcharonfinger = (); # previous character this finger had to type for (my $i=0; $i{$char}->[2]; my $finger = $posmap->{$char}->[3]; #my $dist = $pairmap->{$lastcharonhand[$hand].$char}->[0]; my $dist = $pairmap->{$lastcharonfinger[$finger].$char}->[0]; my $alter = $hand ne $lasthand; # debug to see if we're computing this stuff correctly #print "char $char@$hand, last $lastchar@$lasthand, lastonhand ".$lastcharonhand[$hand].": $dist $alter\n"; $cumdist += $dist; $cumalter += $alter; $cumalpha++; # set up for next $lastcharonhand[$hand] = $char; $lastcharonfinger[$finger] = $char; $lastchar = $char; $lasthand = $hand; } } print "cum dist = $cumdist, cumalter = $cumalter, cumalpha = $cumalpha\n"; my $dpa = $cumdist/$cumalpha; print sprintf("distance per alpha = %3.3f\n", $dpa); my $ar = 100*$cumalter/$cumalpha; print sprintf("alternation ratio = %3.2f\%\n", $ar); return ($dpa,$ar); } sub comparefile { my $filename = shift || 'qwerty-article.txt'; print "Filename: $filename\n"; my $posmap = posmap($qwerty); my $pairmap = pairmap($posmap); my @sq = processfile($posmap, $pairmap, $filename); $posmap = posmap($dvorak); $pairmap = pairmap($posmap); my @sd = processfile($posmap, $pairmap, $filename); print sprintf("distance reduction: %3.2f\%\n", 100-(100*($sd[0]/$sq[0]))); print sprintf("alternation improvement: %3.2f\%\n", $sd[1]-$sq[1]); } comparefile($ARGV[0]);