Ottimizzazione della tastiera del telefono


33

Sembra che ci sia questa mania in corso su persone che imparano noiosamente nuovi layout di tastiera come Dvorak o Neo perché presumibilmente li rendono più produttivi. Sostengo che cambiare layout di tastiera sia una cattiva idea, perché possono volerci mesi per aggiornarti e quando sei sostanzialmente più veloce del 5% rispetto al resto, sei fregato se devi digitare su un computer che non è sei tuo.

Inoltre, tutte queste persone dimenticano dove si trova il vero collo di bottiglia nella comunicazione moderna: la tastiera del telefono.

Ecco come appare la tastiera del telefono media:

La tastiera del telefono

La lettera 'r' è la terza lettera sul pulsante 7; quindi se dovessi digitare la lettera "r" su un telefono cellulare, premi il pulsante 7 tre volte, per "s" lo premi 4 volte e per "a" premi il pulsante 2 una volta.

Considerando questo, inserire 'e' dopo 'd' era probabilmente una cattiva decisione - 'e' è la lettera più comunemente usata nell'alfabeto inglese, quindi, se dovessi etichettare il pulsante 3 "EDF" invece di "DEF", tu risparmierebbe un bel po 'di battiture.

Inoltre, probabilmente avete sperimentato che digitare 2 lettere che condividono lo stesso pulsante è un fastidio: se si desidera scrivere "TU", non si può semplicemente premere 8 tre volte, perché ciò comporterebbe "V". Quindi di solito scrivi 'T', poi premi spazio, poi premi backspace e poi scrivi 'U', che equivale a 5 pressioni di pulsanti invece di 3.


TL; DR

Date queste due regole:

  • Una lettera viene digitata premendo un pulsante n volte, dove n è la posizione in cui si trova la lettera sull'etichetta del pulsante
  • La scrittura di due lettere digitate utilizzando lo stesso pulsante richiede ulteriori 2 pressioni

Qual è il layout della tastiera del telefono che richiede il minor numero di pressioni di pulsanti, dato un testo specifico? Utilizzare solo i pulsanti 2-9, 1 e 0 riservati a simboli speciali.

Ingresso

Il testo per il quale dovresti trovare il layout ottimale viene fornito tramite stdin. Non è necessario gestire altro che l'alfabeto minuscolo e si può presumere che l'input sia costituito solo da questo. Puoi anche supporre che il testo di input sia ragionevolmente grande e che ogni lettera sia presente almeno una volta, se ciò aiuta.

Produzione

Non voglio porre troppi vincoli all'output, dal momento che a volte offre alcune lingue vantaggi rispetto ad altri; quindi comunque la tua lingua mostra che le matrici vanno bene, in alternativa puoi separare ogni etichetta con una nuova riga.

Potrebbero esserci più layout ottimali possibili, è possibile stampare uno qualsiasi di essi. Ecco un semplice esempio:

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

Punti bonus

-35 se il tuo algoritmo non sta forzando brutalmente tutti i possibili layout (sto guardando le "permutazioni" di Haskell qui)

-3 se il tuo codice si inserisce in un messaggio di testo (140 caratteri) e pubblichi una tua foto inviando il tuo codice a un amico.

Questa è la mia prima sfida su StackExchange. Sarei felice di sapere se ti piace o se hai altri feedback a riguardo!


2
Benvenuto su CodeGolf.SE! Non vedo alcun problema con la tua domanda, ma in genere è una buona idea pubblicare la tua sfida nella sandbox prima di ottenere un feedback e rimuovere le ambiguità prima di pubblicare sul sito principale.
Martin Ender,

Ah, va bene, lo farò sicuramente in futuro.
Flonk,

1
Il mio telefono può inviare un singolo SMS di 60 caratteri, ma non supporta correttamente le parentesi, sono fuori dal bonus?
ζ--

1
Bella domanda! Non credo che nessuno sarà in grado di evitare il bonus di -35. Anche se ci limitiamo a layout con 4 caratteri su due dei tasti e 3 su tutti i rimanenti 6, ci sono 26! / (2! * 6!) = 280,063,514,671,253,913,600,000 > 2^77permutazioni uniche, contando i semplici riarrangiamenti dei tasti una sola volta.
Dennis,

2
Inoltre, chiedo a voi persone se è possibile stampare il numero di pressione dei pulsanti della soluzione. Quindi vedremo chi ha trovato il migliore!
Antonio Ragagnin,

Risposte:


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

Ecco un tentativo di ottimizzazione per la regola # 2. Dopo il mio commento, sopra e al posto delle risposte che tengono conto di quella regola (cfr. Valutazione alta delle domande), ho pensato di dover fare qualche sforzo qui ...

Le soluzioni che non ottimizzano per la regola n. 2 possono produrre output molto lontani dall'ottimale. Ho controllato un lungo testo in inglese naturale ("Alice nel Paese delle Meraviglie", in realtà), pre-elaborato (solo lettere minuscole) e, ad esempio, lo script Perl dalla risposta di OJW, risultando essere

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

er da solo lo rovina, più alcune altre coppie non avrebbero mai dovuto finire sulla stessa chiave ...

A proposito, zxqjvkbpfmygwculdrshnioatesono le lettere ordinate, in ordine crescente di frequenza, da quel testo.

Se proviamo a risolverlo in modo semplice (sperando in un bonus di -35, forse) e posizioniamo le lettere una per una, scegliendo la chiave disponibile per un conteggio minimo in coppia, possiamo finire con es:

slbx
hdmz
nrf
iuj
ogv
awk
tcp
eyq

Non inserisco codice per questa soluzione (errata) qui. Ad esempio, nota, cè più frequente di wed è al primo posto. tcLe ctcoppie ( ) sono ovviamente meno frequenti di ac( ca) - 43 + 235 contro 202 + 355. Ma poi wfinisce con a- 598 + 88. Finiamo con coppie awe tc(964 in totale), anche se sarebbe meglio ace tw(635 in totale). Eccetera..

Quindi, l'algoritmo successivo cerca di controllare ogni 8 rimanenti (o 2, se ultimo) lettere più frequenti rispetto alle lettere già presenti sulla tastiera, e di posizionarle in modo che il conteggio delle coppie sia minimo.

$_=<>;                          # 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.

Il risultato è:

sdfz
hlmx
nrv
iyp
ogk
acq
twb
euj

Non mi piace la accoppia (il gatto è uno dei personaggi, dopo tutto), ma, comunque, questo è il posizionamento ottimale delle lettere per l'inglese, se il mio codice non è sbagliato. Non esattamente lo sforzo del "golf", solo una soluzione funzionante, brutta o no.


3

Python3, è tempo di Montecarlo!

Per risolvere questo problema, conto innanzitutto quanti "clic" sono necessari con la tastiera predefinita (inizialmente:) abc,def,ghi,jkl,mno,pqrs,tuv,wxyz. Quindi modifico questa tastiera e vedo se è più economica (il testo è scritto con meno clic). Se questa tastiera è più economica, diventa quella predefinita. Ripeto i 1Mtempi di questo processo .

Per cambiare la tastiera, per prima cosa decido quante modifiche apportare (il numero massimo di modifiche è il numero totale di lettere sulla tastiera). Quindi, per ogni interruttore, scelgo due pulsanti e due posizioni e trasferisco un personaggio dalla prima posizione alla seconda.

Il numero massimo di interruttori per volta è il numero di lettere nella tastiera perché è il numero minimo di modifiche necessarie per passare da due tastiere completamente diverse. (Voglio che sia sempre possibile passare da una tastiera a un'altra)

L'output di echo "jackdawslovemybigsphinxofquartz" | python .\myscript.pyè:

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

Dov'è 61il numero di pulsante premuto per comporre un determinato messaggio.

Personaggi (senza spazi e senza commenti): 577

So che è lungo ma sono davvero nuovo a questa roba.

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)

L'ho trovato così divertente che ho deciso di provare questo algoritmo con LO HOBBIT (ho anche una copia originale a casa!). Ha 383964lettere e questi sono i clic delle coppie contro la tastiera che sto trovando:

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']

Quindi sostengo che quest'ultimo sia uno dei tasti più pratici (in termini di clic).


Come fai a sapere se è ottimale?
PyRulez,

Montecarlo non funziona in questo modo. Ti avvicina sempre di più alla soluzione ottimale. Ma diciamo che se in 1 milione di tentativi la tua soluzione non cambia ... allora probabilmente stai usando quella ottimale. (o non ti stai muovendo abbastanza da questo "minimo locale")
Antonio Ragagnin,

Quindi, per le sfide, abbiamo solo bisogno che funzioni la maggior parte delle volte?
PyRulez,

1
@PyRulez Mi sono reso conto che questo non sarebbe stato un problema facile per trovare una soluzione ottimale (tranne se provassi tutte le possibili soluzioni, che speravo di prevenire con quel bonus di -35), quindi ho davvero scavato questo approccio.
Flonk,

1
Metodo interessante, ma forse questa attività non è esattamente il suo dominio. Ho controllato e, per "Alice", la tastiera predefinita richiede 291613 clic. Ottimizzato con il mio programma - 195597. Con l'approccio 'Monte Carlo' non ho ottenuto meno di 207000 clic in oltre 5 milioni di iterazioni. Inoltre, è meglio scambiare le lettere, ovvero il layout 2x4 + 6x3 rimane costante.
user2846289

2

Bene, se vuoi solo i personaggi più popolari assegnati ai bidoni 2-9, Perl può farlo in 127 caratteri ...

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

dare qualcosa di simile:

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

Oppure stampa tutto su una riga, rimuovendo 12 caratteri:

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

2
puoi facilmente tagliare questo a 100 caratteri:$x{$_}++for split/\s*/,<>;map$o{$n++%8}.=$_,sort{$x{$b}<=>$x{$a}}keys%x;print map"$_:".$o{$_-2},2..9
ardnew

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

Esempio:

$ 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"]

Si potrebbe sostenere che ciò non ottimizza per la regola 2, ma inserisce le lettere più frequenti su chiavi diverse .


0

JavaScript, 192-35 = 157

Ho appena notato la regola dei personaggi che si ripetono; questo non ne tiene conto. Ma come ha notato @mniip nella sua risposta:

Si potrebbe sostenere che ciò non ottimizza per la regola 2, ma inserisce le lettere più frequenti su chiavi diverse .

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)

Probabilmente sarebbe stato su Ruby, ma non sono a casa e sono costretto a usare Internet Explorer (eww). Ma hey, a volte è divertente usare lingue terribili nel golf! ;)

Esempio di output (per il tuo input):

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

Poiché JS non ha STDIN, il programma presuppone che l'input sia memorizzato in una variabile s.


Stai ottimizzando anche questo: "Scrivere due lettere digitate utilizzando lo stesso pulsante richiede 2 ulteriori pressioni dei pulsanti"
Digital Trauma

Ri: ultima modifica. Penso che l'output per 'abcdefghia'non sia esattamente ottimale.
user2846289

@VadimR "Puoi anche supporre che il testo di input sia ragionevolmente grande e che ogni lettera sia presente almeno una volta"
Maniglia della porta

Lo so. 'azbcdefghizjklmnopqzrstuvwxyz'
user2846289

1
È possibile ottimizzare b=['','','','','','','','']a b=[x='',x,x,x,x,x,x,x], s.split('')a s.split(x)e o[x]=o[x]?o[x]+1:1a o[x]=-~o[x].
Spazzolino da denti

0

Python (119-35 = 84):

Supponendo che la stringa sia una variabile a e contenga solo lettere minuscole:

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, possiamo abbandonare l'enorme importazione. Ancora una volta, questo presuppone che la stringa rimossa sia in a.

for h in R(8): print h+2,Z(*S([(CC(a)[d],d) for d in Se(a)])[::-1])[1][h::8]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.