Telefon tuş takımını optimize etme


33

Dvorak veya Neo gibi yeni klavye düzenlerini sıkıca öğrenen insanlar için bu sürekli çılgınlık var gibi görünüyor çünkü sözde onları daha üretken kılıyor. Klavye düzenini değiştirmenin kötü bir fikir olduğunu savunuyorum, çünkü hızlanmanız aylarca sürebilir ve diğerlerinden% 5 daha hızlı olursanız, başka bir bilgisayara yazmaya ihtiyacınız olursa mahvolursunuz. kendi değil.

Ayrıca, tüm bu insanlar modern iletişimdeki gerçek darboğazın nerede olduğunu unutuyor - telefon tuş takımı.

Ortalama telefon tuş takımınız şöyle görünür:

Telefon tuş takımı

'R' harfi, 7 düğmesindeki üçüncü harftir; cep telefonunda 'r' harfini yazarsanız, 7 düğmesine üç defa basarsınız, 's' için 4 kez basarsınız ve 'a' için bir kez 2 düğmesine basarsınız.

Bunu göz önünde bulundurursak, 'd'yi sonra' e'yi koymak muhtemelen kötü bir karardı - 'e' ingilizce alfabesinde en çok kullanılan harfdi, bu nedenle, "DEF" yerine 3 "EDF" düğmesini etiketlemişseniz, çok fazla tuşa basış kaydeder.

Dahası, muhtemelen aynı düğmeyi paylaşan 2 harf yazmanın bir sıkıntı olduğunu kendiniz de deneyimlediniz - "TU" yazmak istiyorsanız, sadece 8 kez üçe basamazsınız, çünkü bu 'V' ile sonuçlanır. Genelde 'T' yazarsınız, sonra boşluk basarsınız, sonra geri çekilirsiniz ve sonra 3 yerine 5 tuşa basarsanız 'U' yazarsınız.


TL; DR

Bu iki kural göz önüne alındığında:

  • Bir düğmeye n kere basılarak bir harf girilir, burada n, düğmenin etiketinde harfin bulunduğu konumdur.
  • Aynı düğmeyi kullanarak yazdığınız iki harfin eklenmesi için 2 düğmeye daha basılması gerekir

Belirli bir metin verildiğinde, en az miktarda düğmeye basılmasını gerektiren telefon klavyesi düzeni nedir? Sadece 2-9, 1 ve 0 düğmelerini kullanmanız özel semboller için ayrılmıştır.

Giriş

İdeal yerleşimi bulmanız gereken metin stdin ile sağlanır. Küçük harfli alfabe dışındaki herhangi bir işlem yapmanıza gerek yoktur ve girişin yalnızca bundan ibaret olduğunu varsayabilirsiniz. Ayrıca, giriş metninin oldukça büyük olduğunu ve eğer yardımcı olursa her harfin en az bir kez içinde olduğunu varsayabilirsiniz.

Çıktı

Çıktıya çok fazla kısıtlama getirmek istemiyorum, çünkü bu bazen bazı dillere diğerlerine göre avantajlar sağlıyor; bu nedenle diliniz dizilerin iyi olduğunu gösteriyor, alternatif olarak her etiketi bir yeni satırla ayırabilirsiniz.

Birden çok olası en uygun düzen olabilir, bunlardan herhangi birini yazdırabilirsiniz. İşte basit bir örnek:

>> echo "jackdawslovemybigsphinxofquartz" | foo.sh
ojpt
avhz
cen
skm
dyf
wbq
ixu
lgr

Bonus puanlar

-35 Algoritmanız olası tüm düzenleri kaba bir şekilde zorlamıyorsa (burada Haskell'in 'permütasyonlarına bakıyorum)

-3 kısa mesaj (140 karakter) ve içinizde kod uyan bir arkadaşınıza kodunuzu göndererek bir pic sonrası eğer.

Bu benim StackExchange'teki ilk zorluğum. Beğendiğinizi veya başka bir geri bildirim aldığınızı duymaktan mutlu olurum!


2
CodeGolf.SE'ye Hoşgeldiniz! Sorunuzla ilgili herhangi bir sorun görmüyorum, ancak genellikle geri bildirim almak ve ana siteye göndermeden önce belirsizlikleri kaldırmak için önce sanal alana meydan okumayı göndermek iyi bir fikirdir .
Martin Ender,

Ah bu harika, kesinlikle gelecekte yapacağım.
Flonk

1
Telefonum 60 karakterlik tek bir SMS gönderebilir, ancak parantezleri düzgün bir şekilde desteklemiyor, bonus dışı mıyım?
41'de

1
Güzel soru! Kimsenin mümkün olacak sanmıyorum önlemek -35 ikramiye. Kendimizi tuşların ikisinde 4 karakter ve diğer 6'da 3 karaktere sahip olan mizanpajlarla sınırlandırsak bile, tuşların 26! / (2! * 6!) = 280,063,514,671,253,913,600,000 > 2^77basit yeniden düzenlemelerini sayarak yalnızca bir kez sayılan benzersiz permütasyonlar vardır .
Dennis,

2
Ayrıca, sizden, çözümünüzün düğmeye basarak sayısını basıp yazamayacağınızı soruyorum. Böylece, en iyisini kimin bulduğunu göreceğiz!
Antonio Ragagnin,

Yanıtlar:


5

Perl, 333

$_=<>;$c{$&}++while/./g;@c=sort{$c{$b}<=>$c{$a}}keys%c;$d{$&.$1}++while/.(?=(.))/g;sub f{my$x=shift;if(my$c=pop@$x){for(grep!$_[$_],0..7){my@y = @_;$y[$_]=$c;f([@$x],@y)}}else{for(0..7){$z=$_[$_];$c+=$d{$z.$_}+$d{$_.$z}for@{$a[$_]}}$c<$m?($m=$c,@n=@_):1}}while(@c){$m= ~0;f[splice@c,0,8];push@{$a[$_]},$n[$_]for 0..7}print@$_,$/for@a

2 numaralı kural için optimizasyon yapmayı dene. Yorumumdan sonra, yukarıda ve bu kuralı dikkate alan cevapların yerine (yüksek soru derecelendirmesi), burada biraz çaba borçlu olduğumu düşündüm ...

Kural 2 için optimize etmeyen çözümler, optimal sonuçlardan çok uzakta çıktılar üretebilir. Uzun doğal İngilizce metinleri ("Alice Harikalar Diyarında", aslında), önceden işlenmiş (yalnızca küçük harfler) ve örneğin OJW'nin cevabındaki Perl yazısını kontrol ettim, sonuç olarak

2: ermx
3: tdfz
4: alp
5: oub
6: ick
7: nwv
8: hgj
9: syq

er yalnız onu mahveder, artı bazı çiftler aynı anahtarda asla bitmemeliydi ...

BTW, zxqjvkbpfmygwculdrshnioatebu metinden sıralanan, artan frekans harflerdir.

Kolayca çözmeyi denersek (belki de -35 bonus umuduyla) ve harfleri birer birer yerleştirirsek, minimum çift başına sayım ile uygun anahtar seçerek, örneğin:

slbx
hdmz
nrf
iuj
ogv
awk
tcp
eyq

Buradaki (yanlış) çözüm için kod göndermiyorum. Örneğin, not, ilk sıraya cgöre daha sık wve sıktır . tc( ct) çiftlerin ac( ca+) 43 + 235'ten 202 + 355'e göre daha az sık olduğu açıktır . Fakat daha sonra - 598 + 88 wile bitiyor a. Biz çiftleri ile biten awve tcdaha iyi olacağını rağmen (964 total) acve tw(635 toplam). Vb..

Bu nedenle, bir sonraki algoritma kalan her 8'i (veya en son 2 ise) en sık kullanılan harfleri tuş takımındaki harflere karşı kontrol etmeye ve bunları çift sayım minimum olacak şekilde yerleştirmeye çalışır.

$_=<>;                          # Read STDIN.
$c{$&}++while/./g;              # Count letters (%c hash).
@c=sort{$c{$b}<=>$c{$a}}keys%c; # Sort them by frequency, ascending
$d{$&.$1}++while/.(?=(.))/g;    # (@c array), and count pairs (%d hash).

                                # Next is recursive sub that does the job.
                                # Some CPAN module for permutations
                                # would probably do better...
                                # Arguments are reference to array of what's 
                                # left un-placed of current 8-pack of letters,
sub f{                          # and 8 element list of placed letters
    my$x=shift;                 # (or undefs).
    if(my$c=pop@$x){            # Pop a letter from 8-pack (if anything left),
        for(grep!$_[$_],0..7){  # try placing it on each available key, and 
            my@y = @_;          # call sub again passing updated arguments.
            $y[$_]=$c;
            f([@$x],@y)
        }
    }else{                      # If, OTOH, 8-pack is exhausted, find sum of
        for(0..7){              # pairs count of current permutation (@_) and 
            $z=$_[$_];          # letters placed in previous rounds (8-packs).
                                # @a is "array of arrays" - note, we didn't 
                                # have to initialize it. First "8-pack" will
                                # be placed on empty keypad "automatically".
                                # We re-use undefined (i.e. 0) $c.

            $c+=$d{$z.$_}+$d{$_.$z}for@{$a[$_]}
        }
        $c<$m                   # Is sum for current placement minimal?
            ?($m=$c,@n=@_)      # Then remember this minimum and placement.
            :1
    }
}

while(@c){
    $m= ~0;                         # Initialize "minimum" with large enough 
    f[splice@c,0,8];                # number, then call sub with each 8-pack
                                    # (and empty list of placed letters 
                                    # from current round). On return,
                                    # @n will have optimal arrangement.
    push@{$a[$_]},$n[$_]for 0..7    # Then place it permanently on keypad.
}
print@$_,$/for@a                    # Show us what you've done.

Sonuç:

sdfz
hlmx
nrv
iyp
ogk
acq
twb
euj

acÇifti sevmiyorum (Sonuçta karakterlerden biri olan Kedi), ama kodum yanlışsa, yine de İngilizce için en uygun harf yerleşimi. Tam olarak 'golf oynama' çabası değil, sadece çirkin ya da olmayan bir çalışma çözümü.


3

Python3, Montecarlo Zamanı!

Bu sorunu çözmek için ilk önce varsayılan klavye ile ne kadar "klik" istediğinizi sayıyorum (esas olarak:) abc,def,ghi,jkl,mno,pqrs,tuv,wxyz. Sonra bu klavyeyi değiştirip daha ucuz olup olmadığına bakarım (metin daha az tıklamayla yazılmıştır). Bu klavye daha ucuzsa, varsayılanı değiştirir. Bu işlem 1Mzamanlarını yineliyorum .

Klavyeyi değiştirmek için önce ne kadar değişiklik yapacağınıza karar verdim (maksimum değişiklik sayısı klavyedeki toplam harf sayısıdır). Sonra, her anahtar için iki düğme ve iki konum seçiyorum ve ilk konumdan ikinciye bir karakter aktarıyorum.

Zaman başına düşen maksimum anahtar sayısı, klavyedeki harf sayısıdır, çünkü iki farklı klavyeden değiştirmeniz gereken minimum değişiklik sayısıdır. (Bir klavyeden diğerine geçmek her zaman mümkün olmalıdır)

Çıktısı echo "jackdawslovemybigsphinxofquartz" | python .\myscript.py:

61 ['anb', 'sef', 'hjc', 'iykl', 'odm', 'qgr', 'tuxv', 'wpz']

Nerede 61düğmenin sayısı belirli bir ileti oluşturmak için basılır.

Karakterler (boşluksuz ve yorumsuz): 577

Uzun olduğunu biliyorum ama bu konuda gerçekten yeniyim.

from random import *
S=['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
def P(L): # perform a switch of the keys of the keyboard:to switch from a given keyboard to another, the maximum number of exchanges is the number of the keys.
    R=randint
    N = len(''.join(L))
    W = randint(1,N)   # decide how many switches to perform
    EL = list(L)
    for i in range(0,W):
        B1=R(0,len(EL)-1)   # decide what buttons are considered in the switch
        B2=R(0,len(EL)-1)
        if len(EL[B1])==0: continue   
        P1=R(0,len(EL[B1])-1)       # decide what letter to switch and where
        if len(EL[B2])==0: P2=0
        else:   P2=R(0,len(EL[B2])-1)
        C1 = EL[B1][P1]     
        EL[B1]=EL[B1].replace(C1,'')
        EL[B2]=EL[B2][:P2]+C1+EL[B2][P2:]
    return EL
def U(L,X): # count how many clicks you need to compose the text X
    S=0
    Z=' '
    for A in X:
        for T in L:
            if A in T and Z not in T: S+=1+T.index(A)
            if A in T and Z in T: S+=3+T.index(A) # if the last character was in the same button..here the penality!
        Z=A
    return S
X=input()
n_iter=10**6
L = list(S)
cc=U(L,X)
print(cc,L)
for i in range(0,n_iter): #do some montecarlo stuff
    cc=U(L,X)
    pl=P(L)
    pc=U(pl,X)
    if(cc>pc):
        L=pl 
        print(pc,L)

O kadar komik buldum ki, bu algoritmayı LO HOBBIT ile denemeye karar verdim (Evde de orjinal bir kopyası var!). Bu sahiptir 383964harfleri ve bu çift tıklama vs tuş takımı ben buluyorum o:

909007 ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
879344 ['abkc', 'def', 'gqhi', 'jl', 'mno', 'rs', 'tupv', 'wxyz']
861867 ['abg', 'def', 'qhyi', 'jcl', 'mno', 'r', 'tupxv', 'swkz']
851364 ['abg', 'e', 'qchi', 'jyl', 'mn', 'dr', 'tupxv', 'sowkfz']
829451 ['ag', 'ef', 'qchi', 'jyl', 'mn', 'dbr', 'tupxv', 'sowkz']
815213 ['amg', 'ef', 'qch', 'ojyl', 'i', 'dbnr', 'tupxv', 'swkz']
805521 ['amg', 'ef', 'ch', 'ojyl', 'qi', 'dbnr', 'tupxv', 'swkz']
773046 ['amg', 'ef', 'ch', 'ojyl', 'qi', 'bnr', 'tupxv', 'dswkz']
759208 ['amg', 'eqf', 'ch', 'ojyl', 'i', 'bnr', 'tupxv', 'dswkz']
746711 ['ag', 'ekq', 'clh', 'sojy', 'bi', 'nmfr', 'tupxv', 'dwz']
743541 ['ag', 'ekq', 'clh', 'sojy', 'bi', 'nmfr', 'tpxv', 'dwuz']
743389 ['ag', 'ekq', 'clh', 'sojy', 'i', 'nmfr', 'tpxbv', 'dwuz']
734431 ['ag', 'ekq', 'lh', 'sjy', 'ci', 'nrf', 'tpxbv', 'dowumz']
705730 ['ag', 'oekq', 'lh', 'sjy', 'ci', 'nrf', 'tpxbv', 'dwumz']
691669 ['ag', 'oekq', 'lh', 'nsjy', 'ic', 'rf', 'tpxbv', 'dwumz']
665866 ['ag', 'hokq', 'el', 'nsjy', 'ic', 'rbf', 'tpxv', 'dwumz']
661610 ['agm', 'hokq', 'e', 'nsj', 'ilc', 'rbf', 'tpyxv', 'dwuz']

Bu yüzden, sonuncunun en kullanışlı tuş takımından (tıklama açısından) biri olduğunu iddia ediyorum.


En uygun olup olmadığını nasıl anlarsınız?
PyRulez

Montecarlo bu şekilde çalışmaz. Sizi yalnızca optimum çözüme yaklaştırır ve yaklaştırır. Ancak şunu söyleyelim: 1 milyon denemede çözümünüz değişmezse ... daha sonra muhtemelen en uygun olanı kullanıyorsunuz demektir. (veya bu "yerel asgari" den yeterince hareket
etmiyorsunuz

Yani, zorluklar için, o zaman sadece çoğu zaman çalışmasına ihtiyacımız var?
PyRulez

1
@ PyRulez Bunun, bunun için en uygun çözümü bulmak için kolay bir sorun olmadığını fark ettim (bu -35 bonusu ile önleyeceğimi umduğum tüm olası çözümleri denediğiniz hariç), bu yüzden gerçekten bu yaklaşımı kazdım.
Flonk

1
İlginç bir yöntem, ama belki de bu görev tam olarak etki alanı değil. Kontrol ettim ve 'Alice' için varsayılan klavye 291613 tıklama gerektiriyor. Programımla optimize edildi - 195597. 'Monte Carlo' yaklaşımıyla, 5 milyondan fazla tekrarlamayla 207000 tıklamadan daha az tıklama almadım. Ve, harfleri değiştirmek daha iyidir, yani 2x4 + 6x3 düzeni sabit kalır.
user2846289

2

Eğer sadece 2-9 kutularına atanmış en popüler karakterleri istiyorsan, Perl bunu 127 karakterde yapabilir ...

foreach(split /\s*/,<>){$x{$_}++}
foreach(sort{$x{$b}<=>$x{$a}}keys %x){$o{$n++%8}.=$_}
for(0..7){printf "%d: %s\n",$_+2,$o{$_}}

gibi bir şey vererek:

echo "jackdawslovemybigsphinxofquartz" | perl ./keypad.pl
2: ajeb
3: iynz
4: suv
5: ohm
6: wkl
7: rgp
8: xfc
9: dtq

Veya 12 karakter kaldırarak hepsini tek bir satıra yazdırın:

foreach(split /\s*/,<>){$x{$_}++}
foreach(sort{$x{$b}<=>$x{$a}}keys %x){$o[$n++%8].=$_}
print join",",values@o,"\n";

2
Bunu 100 karaktere kolayca kırpabilirsiniz:$x{$_}++for split/\s*/,<>;map$o{$n++%8}.=$_,sort{$x{$b}<=>$x{$a}}keys%x;print map"$_:".$o{$_-2},2..9
saat

1

Haskell, 160 - 35 = 125

import Data.List
import GHC.Exts
main=interact f where f s=show$transpose$map($sortWith(\x->length$filter(/=x)s)['a'..'z'])[t,t.d,t.d.d,d.d.d];t=take 8;d=drop 8

Örnek:

$ runhaskell % <<< "jackdaws loves my big sphinx of quartz"
["afpy","sgqz","ihr","ojt","bku","clv","dmw","enx"]
$ </usr/share/dict/propernames tr A-Z a-z | runhaskell % 
["atjx","edgq","rhb","nmp","iyv","lcf","ouw","skz"]

Biri, bunun kural 2 için optimize etmediğini, ancak en sık harfleri farklı tuşlara koyduğunu iddia edebilir.


0

JavaScript, 192 - 35 = 157

Sadece yinelenen karakter kuralını fark ettim; bu dikkate almaz. Ancak @mniip'in cevabında yazdığı gibi:

Biri, bunun kural 2 için optimize etmediğini, ancak en sık harfleri farklı tuşlara koyduğunu iddia edebilir.

o={}
a=[]
b=['','','','','','','','']
i=-1
s.split('').forEach(function(x){o[x]=o[x]?o[x]+1:1})
for(x in o)a.push([o[x],x])
a.sort().reverse().forEach(function(x){b[i=(i+1)%8]+=x[1]})
alert(b)

Bu muhtemelen Ruby'de olurdu, ama evde değilim ve Internet Explorer'ı (eww) kullanmaya zorlanıyorum. Ama hey, bazen golf oynamak golf için korkunç dilleri kullanarak eğlenceli! ;)

Örnek çıktı (girişiniz için):

avlc,sukb,otj,irh,zqg,ypf,xne,wmd

JS'de STDIN olmadığından, program girişin değişken olarak saklandığını varsaymaktadır s.


Bunu da göz önünde bulundurarak optimize ediyor musunuz: "Aynı düğmeyi kullanarak yazdığınız iki harfin eklenmesi için 2 düğmeye daha basılması gerekiyor"
Digital Trauma

Re: son düzenleme. Bunun için çıktı 'abcdefghia'tam olarak optimal değil bence .
user2846289

@VadimR "Girdi metninin oldukça büyük olduğunu ve her harfin en az bir kez içinde bulunduğunu
varsayabilirsin

Biliyorum. 'azbcdefghizjklmnopqzrstuvwxyz'
user2846289

1
Sen optimize edebilirsiniz b=['','','','','','','','']etmek b=[x='',x,x,x,x,x,x,x], s.split('')için s.split(x)ve o[x]=o[x]?o[x]+1:1için o[x]=-~o[x].
Diş fırçası

0

Python (119-35 = 84):

Dize a değişkeni olarak kabul edilir ve yalnızca küçük harfler içerir:

for h in range(8): print h+2,zip(*sorted([(__import__("collections").Counter(a)[d],d) for d in set(a)])[::-1])[1][h::8]

ungolfed:

import collections

#a="jackdawslovemybigsphinxofquartz"
a=__import__("string").lowercase

b=collections.Counter(a)

c=set(a)

d=[(b[d],d) for d in c]

e=sorted(d)

f=e[::-1]

g=zip(*f)[1]

for h in range(8): print h+2,g[h::8]

PYG (76-35 = 41):

Aaah, muazzam ithalatı bırakabiliriz. Yine, bu sıyrılan dizenin bir a olduğunu varsaymaktadır.

for h in R(8): print h+2,Z(*S([(CC(a)[d],d) for d in Se(a)])[::-1])[1][h::8]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.