Tổ hợp phím tối thiểu cần thiết để nhập một văn bản đã cho


45

Chúng ta đều biết rằng các lập trình viên có xu hướng lười biếng. Để tối đa hóa thời gian rảnh của bạn, bạn quyết định viết một chương trình tạo ra số lượng tổ hợp phím tối thiểu cho văn bản được đưa vào đó.

Đầu vào : Văn bản phải được chuyển đổi thành tổ hợp phím. Bạn có thể quyết định cách nhập văn bản (STDIN / đọc từ tệp được cung cấp trong các đối số)

Đầu ra : Các hành động cần thiết theo định dạng sau:

  • Chúng phải được đánh số
  • Hnó: Nhấn một phím và phát hành ngay lập tức
  • Press: Nhấn phím và không nhả phím (điều này sẽ không bao giờ tối ưu khi phím được Rrút ra làm tổ hợp phím tiếp theo)
  • Release: Phát hành Pchìa khóa

Ví dụ :

Đầu vào:

Hello!

Đầu ra:

Một giải pháp ngây thơ sẽ là:

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

Điều này sẽ hiệu quả hơn:

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

Xung quanh:

  • Trình chỉnh sửa sử dụng phông chữ đơn cách
  • Văn bản được bọc mềm ở 80 ký tự
  • Mũi tên lên và Mũi tên xuống bảo vệ cột, ngay cả khi có các dòng ngắn hơn ở giữa
  • Bảng tạm được coi là trống
  • Khóa số được cho là được kích hoạt
  • Khóa mũ được coi là bị vô hiệu hóa
  • Caps lock chỉ hoạt động cho các chữ cái (tức là không có Shift Lock)

Phím nóng / Phím tắt :

  • Home: Nhảy đến đầu dòng hiện tại
  • End: Nhảy đến cuối dòng hiện tại
  • Ctrl+ A: Đánh dấu mọi thứ
  • Ctrl+ C: Sao chép
  • Ctrl+ X: Cắt
  • Ctrl+ V: Dán
  • Shift+ Di chuyển con trỏ: Đánh dấu
  • Ctrl+ F: Mở hộp thoại tìm kiếm.
    • Khớp văn bản ngu ngốc, không có biểu thức chính quy
    • Trường hợp nhạy cảm
    • Tìm kiếm bao quanh
    • Nhập văn bản một dòng cho tìm kiếm
    • Đầu vào được điền sẵn với lựa chọn hiện tại, trừ khi có một dòng mới ở giữa, đầu vào hoàn chỉnh được chọn
    • Sao chép / dán hoạt động như bình thường
    • Nhấn Enterthực hiện tìm kiếm, chọn kết quả khớp đầu tiên sau vị trí con trỏ hiện tại
  • F3: Lặp lại tìm kiếm cuối cùng
  • Ctrl+ H: Mở hộp thoại thay thế
    • Khớp văn bản ngu ngốc, không có biểu thức chính quy
    • Trường hợp nhạy cảm
    • Thay thế tất cả, với bọc xung quanh
    • Nhập văn bản một dòng
    • Đầu vào tìm kiếm được điền sẵn với lựa chọn hiện tại, trừ khi có một dòng mới ở giữa, đầu vào hoàn chỉnh được chọn
    • Đầu vào thay thế trống
    • Sao chép / dán hoạt động như bình thường
    • Tab nhảy đến đầu vào thay thế
    • Nhấn Enterthực hiện thay thế tất cả. Con trỏ được đặt sau lần thay thế cuối cùng

Quy tắc :

  • Các giải pháp phải là một chương trình hoàn chỉnh để biên dịch / phân tích cú pháp và thực thi mà không cần sửa đổi gì thêm
  • Bàn phím hiển thị ở trên là bàn phím để sử dụng
    • Không bắt buộc phải xử lý các ký tự không thể gõ với nó
  • Mỗi khóa phải được phát hành vào cuối
  • Con trỏ không cần ở cuối tập tin ở cuối

Ghi điểm :

Điểm của bạn là tổng số lượng hành động cần thiết để nhập các văn bản sau. Người chiến thắng là giải pháp có số điểm thấp nhất. Sử dụng giải pháp ngây thơ của tôi, tôi nhận được 1371 + 833 + 2006 = 4210. Đánh nó đi Tôi sẽ chọn một người chiến thắng trong hai tuần.

1 giải pháp ngây thơ của tôi

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 sự lặp lại dễ dàng

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

3 sự lặp lại phức tạp hơn

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

Bạn có thể sử dụng chương trình phát lại do tôi viết để kiểm tra các giải pháp của bạn (Lưu ý: Nó không hỗ trợ Tìm kiếm / Thay thế, mọi thứ khác sẽ hoạt động).


6
Tôi rất thích xem một chương trình như thế này cho vim.
Braden hay nhất vào

4
Thông thường tôi sử dụng chuột cho một phần của những điều đó.
Victor Stafusa

1
Rất thú vị. Tôi sẽ đi vào buổi sáng, 3
cjfaure

2
Bạn không thực sự phải Rick Roll chúng tôi, phải không? :)
Filip Haglund

1
Tôi tốt bụng với @ B1KMusic. Đối với tôi điều này sẽ thú vị hơn khi tạo ra các giải pháp cho vimgolf. (Tương đương với những gì bạn đang cố gắng thực hiện ở đây chỉ bằng cách sử dụng các lệnh vim.) Tuy nhiên, điều này nghe có vẻ như là một ý tưởng thú vị trong việc giảm các lần nhấn phím là rất khó (hoặc ít nhất là tôi nghĩ là vậy) vì việc di chuyển chính xác để lựa chọn là khó khăn. Điều này làm cho việc sao chép và dán là một công việc thực sự khó khăn và mất gần như nhiều lần nhấn phím như điều bạn đang cố gắng sao chép. (Hoặc ít nhất đây là cách tôi đang đọc cách sao chép và dán hoạt động). Và tôi không thấy nhiều cách khác để giảm bớt các nét chính.
FDinoff

Câu trả lời:


11

Haskell 1309 + 457 + 1618 = 3384

Cuối cùng, một câu trả lời (điểm số được cải thiện rất nhiều khi tôi nhận ra có các tab trong bài kiểm tra đầu tiên của bạn - phải chỉnh sửa câu hỏi để xem những câu hỏi đó). Biên dịch với ghc, cung cấp đầu vào trên stdin. Thí dụ:

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

Tôi đã thử những thứ rõ ràng như Dijkstra nhưng nó quá chậm, ngay cả sau khi giảm việc phân nhánh thành các động tác hữu ích duy nhất, đó là: xuất khóa tiếp theo hoặc sao chép từ đầu dòng (Shift + Home, Ctrl + C, Kết thúc), hoặc dán.

Vì vậy, cách tiếp cận này sử dụng bảng tạm có độ dài cố định, sao chép khi tiền tố dòng sắp trở nên 'hữu ích' và tiếp tục sử dụng tiền tố đó miễn là nó có thể được dán trên nhiều dòng hơn tiền tố của dòng tiếp theo. Khi không thể sử dụng bảng tạm, nó sẽ rơi vào giải pháp ngây thơ, do đó, nó được đảm bảo để đánh bại nó một khi độ dài được chọn nhiều hơn chi phí của một bản sao.

Điểm tối thiểu đạt được khi độ dài tiền tố được chọn để phù hợp với "Không bao giờ". Có nhiều cách để cải thiện vấn đề này, nhưng tôi đã đọc đủ về 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)

Giải pháp rất hay :) Btw: Bạn có thể loại bỏ thêm một số nhân vật bằng cách kết hợp các Pastes (nếu có thể).
TimWolla

Điều đó chỉ thực sự ảnh hưởng đến ví dụ 2 - Tôi đã có phiên bản thuật toán Dijkstra tìm thấy điều đó, nhưng nó chỉ có thể sử dụng được trong 3 dòng đầu tiên. Bạn có thể cải thiện giải pháp của tôi cho tất cả các bài kiểm tra bằng cách thử các kích thước tiền tố khác nhau; giải pháp đủ nhanh để bạn có thể thực hiện việc này bằng vũ lực, chỉ cần khoảng 10 lần chạy. Lúng túng để cấu trúc lại điều đó trong haskell mặc dù.
bazzargh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.