Diperlukan sedikit penekanan tombol untuk mengetik teks yang diberikan

45

Kita semua tahu bahwa programmer cenderung malas. Untuk memaksimalkan waktu luang Anda, Anda memutuskan untuk menulis sebuah program yang menghasilkan penekanan tombol minimal untuk teks yang dimasukkan ke dalamnya.

Input : Teks yang harus dikonversi menjadi penekanan tombol. Anda dapat memutuskan bagaimana cara memasukkan teks (STDIN / membaca dari file yang disediakan dalam argumen)

Output : Tindakan yang diperlukan dalam format berikut:

  • Mereka harus diberi nomor
  • Hitu: Menekan tombol dan segera melepaskannya
  • Press: Menekan tombol dan tidak melepaskannya (ini tidak akan pernah optimal ketika kunci tersebut Rdihapus sebagai keystroke berikutnya)
  • Release: Melepaskan Pkunci yang dicangkul

Contoh :

Memasukkan:

Hello!

Keluaran:

Solusi naif adalah:

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

Ini akan lebih efisien:

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

Lingkungan Hidup:

  • Editor menggunakan font monospace
  • Teks dibungkus dengan lembut hingga 80 karakter
  • Panah atas dan Panah bawah mempertahankan kolom, meskipun ada garis yang lebih pendek di antaranya
  • Papan klip diasumsikan kosong
  • Num lock diasumsikan diaktifkan
  • Caps lock diasumsikan dinonaktifkan
  • Caps lock hanya berfungsi untuk huruf-huruf (yaitu tidak ada Shift Lock)

Tombol cepat / Pintasan :

  • Home: Lompat ke awal baris saat ini
  • End: Lompat ke akhir baris saat ini
  • Ctrl+ A: Tandai semuanya
  • Ctrl+ C: Salin
  • Ctrl+ X: Potong
  • Ctrl+ V: Tempel
  • Shift+ Gerakan kursor: Menandai
  • Ctrl+ F: Membuka dialog pencarian.
    • Pencocokan teks bodoh, tidak ada Ekspresi Reguler
    • Hal - hal sensitif
    • Pencarian membungkus
    • Input teks baris tunggal untuk pencarian
    • Input diawali dengan pilihan saat ini, kecuali ada baris baru di antara, input lengkap dipilih
    • Menyalin / menempel berfungsi seperti biasa
    • Menekan Entermelakukan pencarian, memilih pasangan pertama setelah posisi kursor saat ini
  • F3: Ulangi pencarian terakhir
  • Ctrl+ H: Membuka dialog ganti
    • Pencocokan teks bodoh, tidak ada Ekspresi Reguler
    • Hal - hal sensitif
    • Ganti Semua, dengan membungkus
    • Input teks baris tunggal
    • Input pencarian diawali dengan pilihan saat ini, kecuali ada baris baru di antara, input lengkap dipilih
    • Input ganti kosong
    • Menyalin / menempel berfungsi seperti biasa
    • Tab melompat ke input ganti
    • Menekan Entermelakukan ganti semua. Kursor ditempatkan setelah penggantian terakhir

Aturan :

  • Solusi harus berupa program lengkap yang mengkompilasi / mem-parsing dan mengeksekusi tanpa modifikasi lebih lanjut
  • Keyboard yang ditampilkan di atas adalah keyboard yang digunakan
    • Tidak perlu menangani karakter yang tidak bisa diketik dengannya
  • Setiap kunci harus dilepaskan pada akhirnya
  • Kursor tidak harus berada di akhir file di akhir

Mencetak :

Skor Anda adalah jumlah tindakan yang diperlukan untuk mengetik teks berikut. Pemenangnya adalah solusi dengan skor terendah. Menggunakan solusi naif saya, saya dapatkan 1371 + 833 + 2006 = 4210. Kalahkan itu! Saya akan memilih pemenang dalam dua minggu.

1 Solusi naif saya

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 Pengulangan mudah

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

3 Pengulangan yang lebih kompleks

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

Anda dapat menggunakan program replay yang ditulis oleh saya untuk menguji solusi Anda (Catatan: Itu belum mendukung Pencarian / Pengganti, semua yang lain harus bekerja).

TimWolla
sumber
6
Saya akan senang melihat program seperti ini untuk vim.
Braden Best
4
Biasanya saya menggunakan mouse untuk bagian dari hal-hal itu.
Victor Stafusa
1
Sangat menarik. Saya akan
coba
2
Anda tidak benar-benar harus dengan Rick Roll kami, bukan? :)
Filip Haglund
1
Saya agak dengan @ B1KMusic. Bagi saya ini akan lebih menarik untuk menghasilkan solusi untuk vimgolf. (Yang setara dengan apa yang Anda coba lakukan di sini hanya dengan menggunakan perintah vim.) Namun ini kedengarannya seperti ide yang menyenangkan mengurangi penekanan tombol sangat sulit (atau setidaknya saya pikir begitu) karena gerakan yang tepat untuk seleksi sulit. Ini membuat menyalin dan menempel adalah tugas yang sangat sulit dan mengambil penekanan tombol hampir sebanyak yang Anda coba salin. (Atau setidaknya begitulah cara saya membaca cara kerja salin dan tempel). Dan saya tidak melihat banyak cara lain untuk mengurangi stroke kunci.
FDinoff

Jawaban:

11

Haskell 1309 + 457 + 1618 = 3384

Akhirnya, sebuah jawaban (skor sangat meningkat begitu saya menyadari ada tab dalam tes pertama Anda - harus mengedit pertanyaan untuk melihatnya). Kompilasi dengan ghc, masukkan input pada stdin. Contoh:

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

Saya mencoba hal-hal yang jelas seperti Dijkstra tetapi itu terlalu lambat, bahkan setelah mengurangi percabangan menjadi satu-satunya langkah yang berguna, yaitu: output kunci berikutnya, atau menyalin dari awal baris (Shift + Home, Ctrl + C, Akhir), atau rekatkan.

Jadi, pendekatan ini menggunakan clipboard dengan panjang tetap, salinan ketika awalan baris akan menjadi 'berguna', dan terus menggunakan awalan itu selama itu akan dapat ditempel pada lebih banyak baris daripada awalan garis yang dicapai berikutnya. Ketika tidak dapat menggunakan clipboard, itu jatuh kembali pada solusi naif, jadi dijamin untuk mengalahkannya setelah panjang yang dipilih lebih dari biaya salinan.

Skor minimum dicapai ketika panjang awalan dipilih agar sesuai dengan "Never going". Ada beberapa cara untuk memperbaiki ini, tetapi saya sudah cukup membaca 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)
bazzargh
sumber
Solusi yang sangat bagus :) Btw: Anda dapat mengurangi beberapa karakter dengan menggabungkan Pasta (jika mungkin).
TimWolla
Itu hanya benar-benar mempengaruhi contoh 2 - Saya memiliki versi algoritma Dijkstra yang menemukan itu, tetapi hanya dapat digunakan terhadap 3 baris pertama. Anda dapat meningkatkan solusi saya untuk semua tes dengan mencoba berbagai ukuran awalan; solusinya cukup cepat sehingga Anda dapat melakukan ini dengan kekerasan, hanya sekitar 10 putaran yang diperlukan. Canggung untuk refactor untuk itu di haskell sekalipun.
bazzargh