พิมพ์ขนาดของช่วงเวลาภายในชิ้นส่วนของเพลง


10

พื้นหลัง

ในเพลงตะวันตกโน้ตเพลงทุกเพลงมีชื่อที่กำหนด ภายในแต่ละคู่มีแปดโน้ตที่ไม่ซ้ำกันในลำดับต่อไปนี้: "CC # / Db DD # / Eb EFF # / Gb GG # / Ab AA # / Bb B C" ซึ่งสุดท้าย C เป็นหนึ่งคู่เหนือคนแรก

ในการบอกความแตกต่างระหว่างโน้ตของอ็อกเทฟที่แตกต่างกันตัวเลข (สำหรับการท้าทายนี้ จำกัด เพียงตัวเลขหลัก) จะถูกต่อท้ายชื่อโน้ต ดังนั้น C5 คือโน้ตที่มีหนึ่งระดับแปดเสียงเหนือ C4 Bb6 สูงกว่า B5

ข้อเท็จจริงที่สำคัญคือ B5 และ C6 เป็นโน้ตที่อยู่ติดกันและ C0 และ B9 เป็นโน้ตที่ต่ำที่สุดและสูงที่สุด

ระหว่างโน้ตสองอันนั้นมีระยะทางซึ่งเป็นจำนวนเซมิโคลอนระหว่างโน้ต Bb4 คือหนึ่ง semitone ต่ำกว่า B4 ซึ่งเป็นหนึ่ง semitone ต่ำกว่า C5 มีสิบสอง semitones ในอ็อกเทฟดังนั้น Bb4 จึงเป็นระยะทาง 12 จาก A # 3 เนื่องจากเป็นอ็อกเทฟด้านบน (สังเกตว่าโน้ตเดี่ยวสามารถมีได้ถึงสองชื่อ)

ความท้าทาย

ความท้าทายของคุณคือการเขียนโปรแกรมที่สั้นที่สุดที่สามารถบันทึกรายการเพลงจาก STDIN และพิมพ์รายการการเปลี่ยนแปลงช่วงเวลาเป็น STDOUT

อินพุตจะเป็นรายการบันทึกเพลงคั่นด้วยช่องว่าง แต่ละโน้ตจะประกอบด้วยตัวอักษรตัวพิมพ์ใหญ่ AG ตัวเลือก b หรือ # sign และตัวเลขหลักเดียว คุณจะไม่ต้องจัดการกับ E # / Fb หรือ B # / Cb อินพุตตัวอย่าง:

C4 D4 E4 F4 G4 A4 B4 C5 C4

เอาต์พุตจะเป็นรายการจำนวนเต็มซึ่งคั่นด้วยช่องว่างซึ่งเป็นตัวแทนของระยะห่างระหว่างโน้ตแต่ละอันต่อเนื่องโดยมีเครื่องหมาย + หรือ - นำหน้าเสมอเพื่อแสดงว่าโน้ตนั้นเรียงจากน้อยไปมากหรือมากไปน้อย จะมีจำนวนน้อยหนึ่งเอาต์พุตที่มากกว่าโน้ตที่ป้อนเข้า ตัวอย่างเอาต์พุตสำหรับอินพุตด้านบน:

+2 +2 +1 +2 +2 +2 +1 -12

ตัวอย่างอินพุตเพิ่มเติม:

E5 D#5 E5 B4 E5 F#5 E5 B4
C0 B0 Bb1 A2 G#3 G4 F#5 F6
G4 Ab4 Gb4 A4 F4 A#4

และผลลัพธ์ที่สอดคล้องกัน:

-1 +1 -5 +5 +2 -2 -5
+11 +11 +11 +11 +11 +11 +11
+1 -2 +3 -4 +5

กฎและข้อ จำกัด

  1. ผู้ชนะจะพิจารณาจากจำนวนอักขระในซอร์สโค้ด

  2. โปรแกรมของคุณควรประกอบด้วยอักขระ ASCII ที่พิมพ์ได้เท่านั้น

  3. คุณไม่ได้รับอนุญาตให้ใช้ฟังก์ชั่นในตัวที่เกี่ยวข้องกับเพลงหรือเสียง

  4. นอกจากนั้นจะใช้กฎมาตรฐานของรหัสกอล์ฟ


ควรพิมพ์+0หรือ-0หรือ0สำหรับบันทึกย่อที่เหมือนกันสองรายการ
Howard

@Howard เนื่องจากฉันไม่ได้ระบุอาจเป็นที่ยอมรับได้
PhiNotPi

1
"Bb4 คือหนึ่ง semitone ต่ำกว่า B4 ซึ่งเป็นหนึ่ง semitone ต่ำกว่า C4" คุณหมายถึง C5 ในตอนท้ายใช่ไหม?
Keith Randall

ว้าวไม่เคยสังเกตว่า ขอขอบคุณที่พบข้อผิดพลาด ตอนนี้ได้รับการแก้ไขแล้ว
PhiNotPi

คำตอบ:



4

Haskell, 161 ตัวอักษร

f(c:r)=maybe(12*read[c])(+f r).lookup c$zip"bC#D.EF.G.A.B"[-1..]
g n|n<0=show n|1<3='+':show n
h x=zipWith(-)(tail x)x
main=interact$unwords.map g.h.map f.words


3

C, 123 ตัวอักษร

ขึ้นอยู่กับวิธีแก้ปัญหาของ leftaroundabout พร้อมการปรับปรุงบางอย่าง

main(c,b,d)
    char*b;
{
    while(d=c,~scanf("%s",b)?c=-~*b*1.6,c%=12,c+=b[~b[1]&16?c+=1-b[1]/40,2:1]*12:0)
        d>1&&printf("%+d ",c-d);
}

เทคนิคบางอย่างที่ฉันคิดว่าน่าพูดถึง:
1. argv[0](ที่นี่เรียกว่าb) เป็นตัวชี้ไปยังชื่อโปรแกรม แต่ใช้ที่นี่เป็นบัฟเฟอร์ในการลบ เราต้องการเพียง 4 ไบต์ (เช่นC#2\0) ดังนั้นเราจึงมีเพียงพอ
2. cคือจำนวนอาร์กิวเมนต์ดังนั้นจึงเริ่มเป็น 1 (เมื่อรันโดยไม่มีอาร์กิวเมนต์) เราใช้มันเพื่อป้องกันการพิมพ์ในรอบแรก

ปัญหาที่c+=b[..c+=..]เป็นไปได้ - แปลกชนิดหนึ่ง ฉันไม่คิดว่ามันเป็นพฤติกรรมที่ไม่ได้กำหนดเพราะ?:เป็นจุดต่อเนื่อง แต่บางทีฉันผิด


หากคุณคิดว่ามันเป็นc = c + b[..c+=..]พฤติกรรมที่ไม่ได้กำหนดไว้อย่างชัดเจน โดยไม่คำนึงถึงลำดับภายใน[..]คุณไม่ทราบว่าด้านนอกจะมาก่อนระหว่างหรือหลังc b[..]
ephemient

@ephemient REG=c;REG+=b[..c+=..];c=REGผมคิดว่าในทางทฤษฎีคอมไพเลอร์จะทำ อย่างไรก็ตามฉันจะแปลกใจที่เห็นสิ่งนี้ในทางปฏิบัติ แต่มันยังคงเป็น UB
ugoren

It's Code Golf - เราได้เรียกใช้ UB โดยscanfไม่ใช้ต้นแบบและไม่เป็นไร เป็นเรื่องที่ดีเพียงเพื่อให้รู้ว่าสิ่งที่เป็นและไม่ได้ตามกฎหมายในชีวิตจริง :)
ephemient

2

ค, 241 229 183

F(c){c-=65;return c*1.6+sin(c/5.+.3)+9;}
#define r if(scanf("%s",b)>0){c=F(*b)%12;c+=b[b[1]<36&&++c||b[1]>97&&c--?2:1]*12
main(e,c,d){char b[4];r;}s:d=c;r;printf("%+d ",c-d);goto s;}}

printf("%+d ",c-d)แทนการทำเครื่องหมายบวกตัวคุณเองคุณสามารถเพียงแค่ทำ
ไวยากรณ์

คุณสามารถละเว้นได้ด้วยideone.com/G00fS
Hauleth

ดีมาก. ข้อเสนอแนะบางอย่าง: F(*b-65)แทนที่จะc-=65;, b[1]<36&&++c||b[1]>97&&c--?2:1-> b[1]&16?1:(c+=b[1]%2*2-1,2), ละเมิด argv โดย: main(e,b,c,d)char*b{(ใช้ตัวชี้อาร์กิวเมนต์ตัวแรกเป็นบัฟเฟอร์งาน)
ugoren

อีกคนหนึ่ง - ฉันคิดว่าสามารถถูกแทนที่ด้วยc=F(*b)%12 c=-~*b*1.6;c%=12ทำไม? sinในต้นฉบับFสามารถถูกแทนที่ด้วย 9.6 c*1.6+9.6เป็น(c+6)*1.6, c-=65และ(c+6)กลายเป็นc-59แล้วc+1(60 * 96% 12 == 0)
ugoren

ขอบคุณสำหรับคำแนะนำทั้งหมด! มันทำงานได้ดีและทำให้สั้นลง แต่ฉันคิดว่าฉันจะทิ้งมันไปอย่างที่เป็นอยู่ตอนนี้ มันจะไม่เป็นทางออกของฉันอีกต่อไปหากปราศจากไซน์
หยุดหมุนทวนเข็มนาฬิกาเมื่อ

1

ตัวละคร 303 ตัว

USING: combinators formatting io kernel math regexp sequences ;
f contents R/ [#-b]+/ all-matching-slices
[ 0 swap [ {
{ [ dup 48 < ] [ drop 1 ] }
{ [ dup 65 < ] [ 48 - 12 * ] }
{ [ dup 98 < ] [ "C-D-EF-G-A-B" index ] }
[ drop -1 ]
} cond + ] each
swap [ over [ - "%+d " printf ] dip ] when* ] each drop

ด้วยความเห็น

! combinators => cond
! formatting => printf
! io => contents
! kernel => swap dup drop over dip when*
! math => < - * +
! regexp => R/ all-matching-slices
! sequences => each
USING: combinators formatting io kernel math regexp sequences ;

f       ! Push false, no previous note value.

! Find notes (as string slices) in standard input. The golfed regexp
! R/ [#-b]+/ matches all notes and no whitespace.
contents R/ [#-b]+/ all-matching-slices

! For each string slice:
[
    0       ! Push 0, initial note value.
    swap    ! Move note slice to top of stack, above note value.

    ! For each Unicode codepoint in note:
    [
        ! Convert the Unicode codepoint to its value in semitones.
        ! For golf, [ 48 ] is shorter than [ CHAR: A ].
        {
            ! Sharp # {35} has 1 semitone.
            { [ dup 48 < ] [ drop 1 ] }
            ! 0-9 {48-57} has 0 to 9 octaves (1 octave = 12 semitones).
            { [ dup 65 < ] [ 48 - 12 * ] }
            ! A-G {65-71} has 0 to 11 semitones.
            { [ dup 98 < ] [ "C-D-EF-G-A-B" index ] }
            ! Flat b {98} has -1 semitone.
            [ drop -1 ]
        } cond

        +       ! Add semitones to cumulative note value.
    ] each

    swap    ! Move previous note value to top of stack.
    ! When there is a previous note value:
    [
        ! Keep current note on stack.
        over [
            ! Compute and print interval.
            - "%+d " printf
        ] dip
    ] when*
    ! Current note replaces previous note at top of stack.
] each

drop    ! Drop previous note, so stack is empty.

สำหรับสคริปต์นี้ "รายการที่คั่นด้วยช่องว่าง" สามารถมีช่องว่างระหว่างองค์ประกอบตั้งแต่ 1 รายการขึ้นไปและ 0 หรือมากกว่านั้นในตอนต้นหรือตอนท้าย สคริปต์นี้จะพิมพ์พื้นที่พิเศษเมื่อสิ้นสุดการส่งออก แต่ก็ยอมรับพื้นที่พิเศษ (หรือขึ้นบรรทัดใหม่) ที่ส่วนท้ายของอินพุต

ถ้าฉันจะใช้คำจำกัดความที่เข้มงวดที่ "รายการคั่นด้วยช่องว่าง" มี 1 ช่องว่างระหว่างองค์ประกอบและ 0 ช่องว่างที่จุดเริ่มต้นหรือสิ้นสุดจากนั้นฉันสามารถย่อcontents R/ [#-b]+/ all-matching-slicesให้สั้นลงcontents " " split(โดยใช้splittingไม่ใช่regexp) อย่างไรก็ตามฉันจะต้องเพิ่มรหัสเพิ่มเติมเพื่อป้องกันพื้นที่พิเศษเมื่อสิ้นสุดผลลัพธ์

หากฉันใช้คำที่dupdไม่ต้องการฉันสามารถย่อover [ - "%+d " printf ] dipให้สั้นได้เพื่อdupd - "%+d " printfประหยัด 8 อักขระ ฉันไม่ได้ใช้คำที่คัดค้านเพราะพวกเขา "ตั้งใจจะลบออกในไม่ช้า"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.