Tasti minimi necessari per digitare un determinato testo


45

Sappiamo tutti che i programmatori tendono ad essere pigri. Per massimizzare il tuo tempo libero, decidi di scrivere un programma che genera un numero minimo di tasti per il testo inserito al suo interno.

Input : testo che deve essere convertito in sequenze di tasti. Puoi decidere come inserire il testo (STDIN / lettura da un file fornito negli argomenti)

Output : le azioni necessarie nel seguente formato:

  • Devono essere numerati
  • Hit: premendo un tasto e rilasciandolo immediatamente
  • PRess: premendo un tasto e non rilasciandolo (questo non sarà mai ottimale quando il tasto viene Rrilasciato come la prossima sequenza di tasti)
  • Release: rilascio di una Pchiave rieletta

Esempio :

Ingresso:

Hello!

Produzione:

Una soluzione ingenua sarebbe:

1 P Shift
2 H h
3 R Shift
4 H e
5 H l
6 H l
7 H o
8 P Shift
9 H 1
10 R Shift

Questo sarebbe più efficiente:

1 P Shift
2 H h
3 H 1
4 R Shift
5 H Left
6 H e
7 H l
8 H l
9 H o

Ambiente:

  • L'editor utilizza un carattere a spaziatura fissa
  • Il testo è morbido con 80 caratteri
  • Freccia su e Freccia giù preservano la colonna, anche se ci sono linee più brevi in ​​mezzo
  • Si presume che gli appunti siano vuoti
  • Si presume che il blocco numerico sia abilitato
  • Si presume che il blocco maiuscole sia disabilitato
  • Il blocco maiuscole funziona solo per le lettere (vale a dire senza Shift Lock)

Tasti di scelta rapida / scorciatoie :

  • Home: Salta all'inizio della riga corrente
  • End: Salta alla fine della riga corrente
  • Ctrl+ A: Segna tutto
  • Ctrl+ C: Copia
  • Ctrl+ X: Taglia
  • Ctrl+ V: Incolla
  • Shift+ Spostamento del cursore: marcatura
  • Ctrl+ F: Apre una finestra di ricerca.
    • Stupida corrispondenza del testo, nessuna espressione regolare
    • Che tiene conto del maiuscolo o minuscolo
    • Le ricerche si susseguono
    • Inserimento di testo a riga singola per la ricerca
    • L'input è precompilato con la selezione corrente, a meno che non ci sia una nuova riga in mezzo, viene selezionato l'input completo
    • Copia / Incolla funziona come al solito
    • Premendo si Enteresegue la ricerca, selezionando la prima corrispondenza dopo la posizione corrente del cursore
  • F3: Ripete l'ultima ricerca
  • Ctrl+ H: Apre una finestra di dialogo di sostituzione
    • Stupida corrispondenza del testo, nessuna espressione regolare
    • Che tiene conto del maiuscolo o minuscolo
    • Sostituisci tutto, con avvolgente
    • Input di testo a riga singola
    • L'input di ricerca è precompilato con la selezione corrente, a meno che non ci sia una nuova riga in mezzo, viene selezionato l'input completo
    • L'ingresso di sostituzione è vuoto
    • Copia / Incolla funziona come al solito
    • Tab passa all'ingresso di sostituzione
    • Premendo si Enteresegue la sostituzione di tutto. Il cursore viene posizionato dopo l'ultima sostituzione

Regole :

  • Le soluzioni devono essere un programma completo che compila / analizza ed esegue senza ulteriori modifiche
  • La tastiera visualizzata sopra è la tastiera da usare
    • Non è necessario gestire caratteri che non possono essere digitati con esso
  • Ogni chiave deve essere rilasciata alla fine
  • Non è necessario che il cursore si trovi alla fine del file alla fine

Punteggio :

Il tuo punteggio è la somma delle azioni necessarie per digitare i seguenti testi. Il vincitore è la soluzione con il punteggio più basso. Con la mia ingenua soluzione ottengo 1371 + 833 + 2006 = 4210. Darsela a gambe! Sceglierò un vincitore tra due settimane.

1 La mia ingenua soluzione

number = 1

H = (char) -> console.log "#{number++} H #{char}"
P = (char) -> console.log "#{number++} P #{char}"
R = (char) -> console.log "#{number++} R #{char}"

strokes = (text) ->
    shiftActive = no

    for char in text
        if /^[a-z]$/.test char
            if shiftActive
                R "Shift"
                shiftActive = no

            H char
        else if /^[A-Z]$/.test char
            unless shiftActive
                P "Shift"
                shiftActive = yes

            H char.toLowerCase()
        else
            table =
                '~': '`'
                '!': 1
                '@': 2
                '#': 3
                '$': 4
                '%': 5
                '^': 6
                '&': 7
                '*': 8
                '(': 9
                ')': 0
                '_': '-'
                '+': '='
                '|': '\\'
                '<': ','
                '>': '.'
                '?': '/'
                ':': ';'
                '"': "'"
                '{': '['
                '}': ']'

            if table[char]?
                unless shiftActive
                    P "Shift"
                    shiftActive = yes

                H table[char]
            else
                H switch char
                    when " " then "Space"
                    when "\n" then "Enter"
                    when "\t" then "Tab"
                    else
                        if shiftActive
                            R "Shift"
                            shiftActive = no

                        char
    R "Shift" if shiftActive

input = ""

process.stdin.on 'data', (chunk) -> input += chunk
process.stdin.on 'end', -> strokes input

2 Ripetizione facile

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

3 Ripetizione più complessa

We're no strangers to love
You know the rules and so do I
A full commitment's what I'm thinking of
You wouldn't get this from any other guy
I just wanna tell you how I'm feeling
Gotta make you understand

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

We've known each other for so long
Your heart's been aching but
You're too shy to say it
Inside we both know what's been going on
We know the game and we're gonna play it
And if you ask me how I'm feeling
Don't tell me you're too blind to see

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

(Ooh, give you up)
(Ooh, give you up)
(Ooh)
Never gonna give, never gonna give
(Give you up)
(Ooh)
Never gonna give, never gonna give
(Give you up)

We've know each other for so long
Your heart's been aching but
You're too shy to say it
Inside we both know what's been going on
We know the game and we're gonna play it

I just wanna tell you how I'm feeling
Gotta make you understand

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

Puoi utilizzare il programma di riproduzione scritto da me per testare le tue soluzioni (Nota: non supporta ancora la ricerca / sostituzione, tutto il resto dovrebbe funzionare).


6
Mi piacerebbe vedere un programma come questo per Vim.
Braden Best

4
Normalmente uso il mouse per parte di quelle cose.
Victor Stafusa,

1
Molto interessante. Ci
proverò

2
Non dovevi davvero farci Rick Roll, vero? :)
Filip Haglund l'

1
Sono un pò con @ B1KMusic. Per me questo sarebbe più interessante generare soluzioni a Vimgolf. (Che è l'equivalente di quello che stai cercando di fare qui usando solo i comandi di vim.) Tuttavia, mentre suona come un'idea divertente ridurre i tasti è molto difficile (o almeno penso che lo sia) in quanto un preciso movimento di selezione è difficile. Questo rende la copia e incolla un compito davvero difficile e richiede quasi tutte le sequenze di tasti della cosa che stavi cercando di copiare. (O almeno questo è come sto leggendo come funziona il copia e incolla). E non vedo molti altri modi per ridurre i tasti.
FDinoff,

Risposte:


11

Haskell 1309 + 457 + 1618 = 3384

Infine, una risposta (il punteggio è notevolmente migliorato quando mi sono reso conto che c'erano delle schede nel tuo primo test, ho dovuto modificare la domanda per vederle). Compilare con ghc, fornire input su stdin. Esempio:

$ ghc keyboard.hs && echo hello|./keyboard
1 H h
2 H e
3 H l
4 H l
5 H o
6 H Enter

Ho provato cose ovvie come Dijkstra ma era troppo lento, anche dopo aver ridotto la ramificazione alle uniche mosse utili, che sono: emettere il tasto successivo o copiare dall'inizio della riga (Maiusc + Home, Ctrl + C, Fine) o incolla.

Quindi, questo approccio utilizza un blocco appunti a lunghezza fissa, copia quando un prefisso di linea sta per diventare "utile" e continua a utilizzare quel prefisso fintanto che sarebbe incollabile su più righe rispetto ai prefissi di linee che raggiunge successivamente. Quando non può usare gli Appunti, ricade sulla soluzione ingenua, quindi è garantito batterlo una volta che la lunghezza scelta è superiore al costo di una copia.

Il punteggio minimo viene raggiunto quando si sceglie la lunghezza del prefisso per adattarsi a "Mai". Ci sono modi per migliorare, ma ne ho abbastanza di leggere Rick Astley.

import Data.List (isPrefixOf,isInfixOf)
import Control.Monad (foldM)
plen=12
softlines text=sl 0 [] text
  where
    sl n [] [] = []
    sl n acc [] = [(n,reverse acc)]
    sl n acc (x:xs)
      |x=='\n'||length acc==79=(n,reverse (x:acc)):(sl (n+1) [] xs)
      |otherwise=sl n (x:acc) xs
pasteable (a,b) (c,d)=(c>a && b`isInfixOf`d)
                      || (c==a && b`isInfixOf`(drop (length b) d))
findprefixes l=filter (\(a,b,c)->c/=[])
               $ map (\(a,b)->(a, b, map fst $ filter (pasteable (a,b)) l))
               $ filter (\(a,b)->length b==plen && last b/='\n')
               $ map (\(a,b)->(a, take plen b)) l
mergePrefixes [] = []
mergePrefixes (p:ps) = mergePrefixes' p ps
 where mergePrefixes' p [] = [p]
       mergePrefixes' (a,x,b) ((c,y,d):qs) =
         if length (filter (>=c) b) >= length d then
           mergePrefixes' (a,x,b) qs
         else
           (a, x, (filter (<c) b)):(mergePrefixes' (c,y,d) qs)
uc = ("~!@#$%^&*()_+<>?:{}|\""++['A'..'Z'])
lc = ("`1234567890-=,./;[]\\'"++['a'..'z'])
down c = case [[lo]|(lo,hi)<-zip lc uc,c==hi] of []->error [c];p->head p
applyPrefixToLine prefix [] s=return s
applyPrefixToLine [] line s=emit line s
applyPrefixToLine prefix line@(ch:rest) s=
 if prefix`isPrefixOf`line then
   do { s<-emitPaste s; applyPrefixToLine prefix (drop (length prefix) line) s}
 else
   do { s<-emitch s ch; applyPrefixToLine prefix rest s}
type Keystroke = (Char, [Char])
key action k (n, shift) = do
  putStrLn ((show n)++" "++[action]++" "++k)
  if k=="Shift" then return (n+1, (not shift))
  else return (n+1, shift)
emitch (m, shift) ch=
  case ch of
    '\t'->key 'H' "Tab" (m,shift)
    '\n'->key 'H' "Enter" (m,shift)
    ' '->key 'H' "Space" (m,shift)
    _->
      if shift && ch`elem`lc then
        do { key 'R' "Shift" (m, True); key 'H' [ch] (m+1, False) }
      else if not shift && ch`elem`uc then
             do { key 'P' "Shift" (m, False); key 'H' (down ch) (m+1, True) }
           else if ch`elem`lc
                then key 'H' [ch] (m, shift)
                else key 'H' (down ch) (m, shift)
emit line s = foldM emitch s line
emitPaste s = do
  s<-key 'P'"Ctrl" s
  s<-key 'H' "v" s
  key 'R' "Ctrl" s
emitCopy s = do
  s<-key 'H' "Home" s
  s<-key 'P'"Ctrl" s
  s<-key 'H' "c" s
  s<-key 'R' "Ctrl" s
  s<-key 'R' "Shift" s
  key 'H' "End" s
applyPrefix pf ((a,b):xs) p@((c,y,d):ps) s=
  if (c==a) then
    do
      s@(n, shift) <- emit y s
      s <- if shift then return s else key 'P' "Shift" s
      s <- emitCopy s
      s <- applyPrefixToLine y (drop (length y) b) s
      applyPrefix y xs ps s
  else
    do
      s<-applyPrefixToLine pf b s
      applyPrefix pf xs p s
applyPrefix "" ((a,b):xs) [] s=
  do
    s <- emit b s
    applyPrefix "" xs [] s
applyPrefix pf ((a,b):xs) [] s=
  do
    s<-applyPrefixToLine pf b s
    applyPrefix pf xs [] s
applyPrefix _ [] _ s=return s

main=do
  input <- getContents
  let lines = softlines input
  let prefixes = mergePrefixes (findprefixes lines)
  (n,shift) <- applyPrefix "" lines prefixes (1, False)
  if shift then
    key 'R' "Shift" (n, shift)
  else
    return(n,shift)

Soluzione molto bella :) Btw: puoi radere altri personaggi combinando le Paste (se possibile).
TimWolla,

Questo riguarda solo l'esempio 2: avevo una versione dell'algoritmo Dijkstra che lo trova, ma è utilizzabile solo contro le prime 3 righe. Puoi migliorare la mia soluzione per tutti i test provando diverse dimensioni di prefisso; la soluzione è abbastanza veloce da poterlo fare con la forza bruta, sono necessarie solo circa 10 corse. Però è imbarazzante rifarsi a quello in haskell.
bazzargh,
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.