การกดแป้นน้อยที่สุดจำเป็นต้องพิมพ์ข้อความที่กำหนด


45

เราทุกคนรู้ว่าโปรแกรมเมอร์มักจะขี้เกียจ เพื่อเพิ่มเวลาว่างของคุณให้มากที่สุดคุณตัดสินใจที่จะเขียนโปรแกรมที่มีการกดแป้นจำนวนน้อยที่สุดสำหรับข้อความที่ป้อนเข้า

อินพุต : ข้อความที่ต้องถูกแปลงเป็นการกดแป้น คุณอาจตัดสินใจเกี่ยวกับวิธีป้อนข้อความ (STDIN / อ่านจากไฟล์ที่มีให้ในอาร์กิวเมนต์)

เอาท์พุท : การกระทำที่จำเป็นในรูปแบบต่อไปนี้:

  • พวกเขาจะต้องมีหมายเลข
  • Hมัน: กดปุ่มและปล่อยมันทันที
  • Press: การกดปุ่มและไม่ปล่อยปุ่ม (สิ่งนี้จะไม่ดีที่สุดเมื่อคีย์ถูกRทำให้เหมือนการกดแป้นครั้งต่อไป)
  • Release: การปลดPคีย์ที่รับการรับรอง

ตัวอย่าง :

การป้อนข้อมูล:

Hello!

เอาท์พุท:

โซลูชันไร้เดียงสาจะเป็น:

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

สิ่งนี้จะมีประสิทธิภาพมากขึ้น:

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

สิ่งแวดล้อม:

  • ตัวแก้ไขใช้แบบอักษรแบบ monospaced
  • ข้อความถูกห่อหุ้มอย่างนุ่มนวลที่ 80 ตัวอักษร
  • ลูกศรขึ้นและลูกศรลงรักษาคอลัมน์แม้ว่าจะมีเส้นที่สั้นกว่าในระหว่างนั้น
  • คลิปบอร์ดถือว่าว่างเปล่า
  • มีการสันนิษฐานว่าล็อค Num เพื่อเปิดใช้งาน
  • จะทำการปิด Caps Lock
  • Caps Lock ใช้งานได้กับตัวอักษรเท่านั้น (เช่นไม่มี Shift Lock)

ปุ่มลัด / ทางลัด :

  • Home: ข้ามไปยังจุดเริ่มต้นของบรรทัดปัจจุบัน
  • End: ข้ามไปยังจุดสิ้นสุดของบรรทัดปัจจุบัน
  • Ctrl+ A: ทำเครื่องหมายทุกอย่าง
  • Ctrl+ C: คัดลอก
  • Ctrl+ X: ตัด
  • Ctrl+ V: วาง
  • Shift+ เคอร์เซอร์เคลื่อนไหว: การทำเครื่องหมาย
  • Ctrl+ F: เปิดกล่องโต้ตอบการค้นหา
    • การจับคู่ข้อความโง่ ๆ ไม่มีนิพจน์ปกติ
    • กรณีที่สำคัญ
    • การค้นหาพันไปรอบ ๆ
    • ป้อนข้อความบรรทัดเดียวสำหรับการค้นหา
    • อินพุตถูกเติมล่วงหน้าด้วยการเลือกปัจจุบันยกเว้นว่ามีการขึ้นบรรทัดใหม่ระหว่างอินพุตที่สมบูรณ์จะถูกเลือก
    • การคัดลอก / การวางทำงานตามปกติ
    • กดEnterทำการค้นหาแล้วเลือกคู่แรกหลังจากตำแหน่งเคอร์เซอร์ปัจจุบัน
  • F3: ทำซ้ำการค้นหาล่าสุด
  • Ctrl+ H: เปิดกล่องโต้ตอบแทนที่
    • การจับคู่ข้อความโง่ ๆ ไม่มีนิพจน์ปกติ
    • กรณีที่สำคัญ
    • แทนที่ทั้งหมดด้วยการล้อมรอบ
    • อินพุตข้อความบรรทัดเดียว
    • อินพุตการค้นหาจะถูกเติมล่วงหน้าด้วยการเลือกปัจจุบันยกเว้นว่ามีการขึ้นบรรทัดใหม่ระหว่างการป้อนข้อมูลที่สมบูรณ์จะถูกเลือก
    • อินพุตการแทนที่ว่างเปล่า
    • การคัดลอก / การวางทำงานตามปกติ
    • Tab ข้ามไปยังอินพุตแทนที่
    • กดEnterทำการแทนที่ทั้งหมด เคอร์เซอร์จะถูกวางไว้หลังจากการเปลี่ยนครั้งล่าสุด

กฎ :

  • การแก้ปัญหาจะต้องเป็นโปรแกรมที่สมบูรณ์ที่รวบรวม / แยกวิเคราะห์และดำเนินการโดยไม่มีการดัดแปลงใด ๆ เพิ่มเติม
  • แป้นพิมพ์ที่แสดงด้านบนเป็นคีย์บอร์ดที่ใช้
    • ไม่จำเป็นต้องจัดการกับตัวละครที่ไม่สามารถพิมพ์ได้
  • ทุกปุ่มจะต้องปล่อยออกมาในตอนท้าย
  • เคอร์เซอร์ไม่จำเป็นต้องอยู่ท้ายไฟล์ท้ายสุด

เกณฑ์การให้คะแนน :

คะแนนของคุณคือจำนวนรวมของการกระทำที่จำเป็นในการพิมพ์ข้อความต่อไปนี้ ผู้ชนะคือทางออกด้วยคะแนนต่ำสุด 1371 + 833 + 2006 = 4210ใช้วิธีการแก้ปัญหาที่ไร้เดียงสาของฉันฉันได้รับ เอาชนะมัน! ฉันจะเลือกผู้ชนะในอีกสองสัปดาห์

1 วิธีแก้ปัญหาไร้เดียงสาของฉัน

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 การทำซ้ำง่าย

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

3 การทำซ้ำที่ซับซ้อนมากขึ้น

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

คุณสามารถใช้โปรแกรมเล่นซ้ำที่ฉันเขียนขึ้นเพื่อทดสอบวิธีแก้ปัญหาของคุณ (หมายเหตุ: ยังไม่รองรับการค้นหา / การแทนที่ แต่อย่างอื่นก็ใช้ได้)


6
ฉันชอบที่จะดูโปรแกรมเช่นนี้เพื่อเป็นกลุ่ม
Braden ที่ดีที่สุด

4
ปกติฉันจะใช้เมาส์เพื่อเป็นส่วนหนึ่งของสิ่งเหล่านั้น
Victor Stafusa

1
น่าสนใจมาก. ฉันจะไปในตอนเช้า 3
cjfaure

2
คุณไม่ต้องริคม้วนเราจริง ๆ เหรอ? :)
Filip Haglund

1
ฉันค่อนข้างจะกับ @ B1KMusic สำหรับฉันนี่จะน่าสนใจมากขึ้นในการสร้างวิธีแก้ปัญหาสำหรับ vimgolf (ซึ่งเทียบเท่ากับสิ่งที่คุณพยายามทำที่นี่เพียงแค่ใช้คำสั่ง vim) อย่างไรก็ตามในขณะที่เสียงเหมือนความคิดที่สนุกสนานลดการกดแป้นพิมพ์นั้นยากมาก (หรืออย่างน้อยฉันก็คิดว่ามันเป็น) เนื่องจากการเคลื่อนไหวที่แม่นยำสำหรับการเลือกนั้นยาก สิ่งนี้ทำให้การคัดลอกและวางเป็นงานที่ยากมากและใช้การกดแป้นเกือบหลายครั้งเหมือนกับสิ่งที่คุณพยายามคัดลอก (หรืออย่างน้อยนี่คือวิธีที่ฉันอ่านวิธีคัดลอกและวางงาน) และฉันไม่เห็นวิธีอื่น ๆ อีกมากมายในการลดการกดปุ่ม
FDinoff

คำตอบ:


11

Haskell 1309 + 457 + 1618 = 3384

ในที่สุดคำตอบ (คะแนนดีขึ้นมากเมื่อฉันรู้ว่ามีแท็บในการทดสอบครั้งแรกของคุณ - ต้องแก้ไขคำถามเพื่อดูคำถามเหล่านั้น) คอมไพล์ด้วยghcอินพุตอินพุตบน stdin ตัวอย่าง:

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

ฉันลองสิ่งที่ชัดเจนเช่น Dijkstra แต่มันช้าเกินไปแม้ว่าจะลดการแตกกิ่งก้านสาขาไปเป็นการเคลื่อนไหวที่มีประโยชน์เพียงอย่างเดียวนั่นคือเอาท์พุทคีย์ถัดไปหรือคัดลอกจากจุดเริ่มต้นของบรรทัด (Shift + Home, Ctrl + C, สิ้นสุด) หรือวาง

ดังนั้นวิธีนี้ใช้คลิปบอร์ดความยาวคงที่คัดลอกเมื่อคำนำหน้าสายกำลังจะกลายเป็น 'ประโยชน์' และยังคงใช้คำนำหน้านั้นตราบใดที่มันจะสามารถวางได้ในบรรทัดมากกว่าคำนำหน้าของบรรทัดมันต่อไป เมื่อมันไม่สามารถใช้คลิปบอร์ดได้มันก็กลับมาที่โซลูชันที่ไร้เดียงสาดังนั้นจึงรับประกันได้ว่าจะเอาชนะได้เมื่อความยาวที่เลือกมากกว่าค่าใช้จ่ายในการคัดลอก

คะแนนขั้นต่ำจะทำได้เมื่อเลือกความยาวคำนำหน้าให้พอดีกับ "ไม่เคย" มีวิธีการปรับปรุงในเรื่องนี้ แต่ฉันอ่าน 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)

วิธีแก้ปัญหาที่ดีมาก :) Btw: คุณสามารถกำจัดตัวละครเพิ่มได้โดยรวม Pastes (ถ้าเป็นไปได้)
TimWolla

นั่นมีผลกับตัวอย่างที่ 2 จริงๆ - ฉันมีรุ่นอัลกอริทึม Dijkstra ที่พบสิ่งนั้น แต่ใช้ได้เฉพาะกับ 3 บรรทัดแรกเท่านั้น คุณสามารถปรับปรุงโซลูชันของฉันสำหรับการทดสอบทั้งหมดโดยลองใช้คำนำหน้าขนาดต่างกัน วิธีแก้ปัญหานั้นเร็วพอที่คุณสามารถทำได้โดยใช้กำลังดุร้ายต้องใช้การวิ่งประมาณ 10 ครั้งเท่านั้น ที่น่าอึดอัดใจที่จะ refactor ว่าใน Haskell แม้ว่า
bazzargh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.