การเขียนโปรแกรม Introspective: รหัสที่วิเคราะห์แหล่งที่มาและผลลัพธ์


13

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

ตัวอย่าง

หากรหัสของคุณคือ

abb1

เอาท์พุทมันจะต้องเป็น

My source has 4 characters.
1 is "a"
2 are "b"
1 is "1"
Besides unquoted numbers, my output has 383 characters.
34 are "
"
79 are " "
63 are """
2 are "'"
2 are ","
4 are "."
2 are "1"
2 are "B"
2 are "I"
2 are "M"
39 are "a"
4 are "b"
6 are "c"
4 are "d"
38 are "e"
3 are "g"
5 are "h"
4 are "i"
4 are "m"
3 are "n"
8 are "o"
3 are "p"
2 are "q"
38 are "r"
12 are "s"
8 are "t"
7 are "u"
3 are "y"
It's good to be a program.

(เอาต์พุตต้องไปที่ stdout)

ตัวอย่างเช่นสังเกตว่าเอาต์พุตมีสองตัวพิมพ์ใหญ่ m หนึ่งสำหรับและหนึ่งสำหรับMy 2 are "M"สิ่งนี้จะต้องเป็นจริงสำหรับตัวละครทุกตัวดังนั้นผลลัพธ์จะไม่ขัดแย้งกับตัวเอง แต่อย่างใด

ตัวเลขที่ไม่มีเครื่องหมายจะถูกละเว้นในเอาต์พุตเพื่อหลีกเลี่ยงชุดความถี่ที่ไม่น่าพอใจ ตัวอย่างเช่น1 is "1"ไม่ถูกต้องหากนับทั้งสองอย่าง คุณควรอ่าน2 are "1"แต่มีเพียงหนึ่งเดียวอีกครั้ง

ชี้แจงรูปแบบ

  • "is" ต้องใช้สำหรับการปรากฏตัวอักขระเดี่ยว

  • "is" จะต้องใช้สำหรับการปรากฏตัวหลายครั้ง

  • "is" ไม่ควรปรากฏในรายการของอักขระเอาต์พุตเนื่องจากจะไม่จำเป็น 1 is 'Z'อ้างถึง Z ในตัวมันเองดังนั้นสามารถลบทั้งบรรทัดได้

  • วลีทั้งสามประโยคจะต้องปรากฏขึ้นเพื่อให้รายการความถี่ตัวละครอยู่ระหว่าง (ดังตัวอย่าง) ดังนั้นการส่งออกของคุณจะเริ่มต้นด้วยและจบด้วยMy source... ...be a program.โปรดทราบว่าไม่มีการขึ้นบรรทัดใหม่ในตอนท้ายของเอาต์พุต

  • ความถี่ของตัวละครจะแสดงรายการตัวเองในลำดับใดก็ได้

  • ขึ้นบรรทัดใหม่นับเป็นหนึ่งอักขระ (ในกรณีที่ \ r \ n)

Format Checker

สคริปต์ Python ต่อไปนี้ใช้โค้ดและเอาต์พุตของคุณเป็นสตริงและยืนยันว่าเอาต์พุตไม่มีความขัดแย้ง มันมีข้อความแสดงข้อผิดพลาดที่มีประโยชน์หากมีสิ่งผิดปกติ คุณสามารถเรียกใช้แบบออนไลน์ได้ที่http://ideone.com/6H0lduด้วยการฟอร์กมันแทนที่สตริง CODE และ OUTPUT จากนั้นเรียกใช้ มันจะไม่ให้ผลบวกปลอมหรือเชิงลบ (สมมติว่าปราศจากข้อผิดพลาด)

#Change the CODE and OUTPUT strings to test your program

CODE = r'''abb1'''

OUTPUT = r'''My source has 4 characters.
1 is "a"
2 are "b"
1 is "1"
Besides unquoted numbers, my output has 383 characters.
34 are "
"
79 are " "
63 are """
2 are "'"
2 are ","
4 are "."
2 are "1"
2 are "B"
2 are "I"
2 are "M"
39 are "a"
4 are "b"
6 are "c"
4 are "d"
38 are "e"
3 are "g"
5 are "h"
4 are "i"
4 are "m"
3 are "n"
8 are "o"
3 are "p"
2 are "q"
38 are "r"
12 are "s"
8 are "t"
7 are "u"
3 are "y"
It's good to be a program.'''

#######################################################

import re

amountPattern = r'(\d+) (is|are) "(.)"\n'

class IntrospectionException(Exception):
    pass

def getClaimedAmounts(string, errorOnIs):
    groups = re.findall(amountPattern, string, re.DOTALL)

    for amount, verb, char in groups:
        if verb == 'is':
            if errorOnIs:
                raise IntrospectionException('\'1 is "%s"\' is unnecessary' % char)
            elif amount != '1':
                raise IntrospectionException('At "%s", %s must use "are"' % (char, amount))
        elif verb == 'are' and amount == '1':
            raise IntrospectionException('At "%s", 1 must use "is"' % char)

    amounts = {}
    for amount, verb, char in groups:
        if char in amounts:
            raise IntrospectionException('Duplicate "%s" found' % char)
        amounts[char] = int(amount)
    return amounts

def getActualAmounts(string):
    amounts = {}
    for char in string:
        if char in amounts:
            amounts[char] += 1
        else:
            amounts[char] = 1
    return amounts

def compareAmounts(claimed, actual):
    for char in actual:
        if char not in claimed:
            raise IntrospectionException('The amounts list is missing "%s"' % char)
    for char in actual: #loop separately so missing character errors are all found first
        if claimed[char] != actual[char]:
            raise IntrospectionException('The amount of "%s" characters is %d, not %d' % (char, actual[char], claimed[char]))
    if claimed != actual:
        raise IntrospectionException('The amounts are somehow incorrect')

def isCorrect(code, output):
    p1 = r'^My source has (\d+) characters\.\n'
    p2 = r'Besides unquoted numbers, my output has (\d+) characters\.\n'
    p3 = r"It's good to be a program\.$"
    p4 = '%s(%s)*%s(%s)*%s' % (p1, amountPattern, p2, amountPattern, p3)

    for p in [p1, p2, p3, p4]:
        if re.search(p, output, re.DOTALL) == None:
            raise IntrospectionException('Did not match the regex "%s"' % p)

    claimedCodeSize = int(re.search(p1, output).groups()[0])
    actualCodeSize = len(code)
    if claimedCodeSize != actualCodeSize:
        raise IntrospectionException('The code length is %d, not %d' % (actualCodeSize, claimedCodeSize))

    filteredOutput = re.sub(r'([^"])\d+([^"])', r'\1\2', output)

    claimedOutputSize = int(re.search(p2, output).groups()[0])
    actualOutputSize = len(filteredOutput)
    if claimedOutputSize != actualOutputSize:
        raise IntrospectionException('The output length (excluding unquoted numbers) is %d, not %d' % (actualOutputSize, claimedOutputSize))

    splitIndex = re.search(p2, output).start()

    claimedCodeAmounts = getClaimedAmounts(output[:splitIndex], False)
    actualCodeAmounts = getActualAmounts(code)
    compareAmounts(claimedCodeAmounts, actualCodeAmounts)

    claimedOutputAmounts = getClaimedAmounts(output[splitIndex:], True)
    actualOutputAmounts = getActualAmounts(filteredOutput)
    compareAmounts(claimedOutputAmounts, actualOutputAmounts)

def checkCorrectness():
    try:
        isCorrect(CODE, OUTPUT)
        print 'Everything is correct!'
    except IntrospectionException as e:
        print 'Failed: %s.' % e

checkCorrectness()

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

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


อนุญาตให้อ่านไฟล์ต้นฉบับของคุณเองได้หรือไม่
Ventero

@MrLore อาจมีข้อผิดพลาดอื่น ๆ แต่ฉันเพิ่งรู้ว่าเครื่องหมายคำพูดสามคำ ('' ') ยังคงหลบสิ่งต่าง ๆ ด้วยแบ็กสแลช สิ่งนี้อาจเกี่ยวข้องกับปัญหาของคุณ ตอนนี้ฉันกำลังซ่อมอยู่
งานอดิเรกของ Calvin

@Ventero แน่นอน!
งานอดิเรกของ Calvin

@MrLore regexps อนุญาตการบวกที่ผิดพลาดใช่ ในการแก้ไขปัญหาแบ็กสแลชภายในเครื่องหมายคำพูดสามรายการให้ใช้ raw strings ( r'''CODE''')
Ventero

1
@MrLore แก้ไขจุดที่ไม่ได้ Escape ขอบคุณที่สังเกต!
งานอดิเรกของ Calvin

คำตอบ:


2

CJam - 189

{`"_~"+:T;"Besides unquoted numbers, my output has &It's good to be a program.&My source has & characters.
"'&/~_]:X2=T,X3=3i({T_&:B{TI/,(" are ":AM`I*N}fIXK=]o
XBA`N+f+2*+s:T,X3=}fK'q];}_~

ลองที่http://cjam.aditsu.net/

เอาท์พุท:

My source has 189 characters.
3 are "{"
3 are "`"
6 are """
4 are "_"
3 are "~"
4 are "+"
5 are ":"
5 are "T"
2 are ";"
3 are "B"
8 are "e"
9 are "s"
2 are "i"
3 are "d"
17 are " "
6 are "u"
2 are "n"
2 are "q"
8 are "o"
6 are "t"
3 are "m"
2 are "b"
7 are "r"
4 are ","
2 are "y"
2 are "p"
3 are "h"
7 are "a"
5 are "&"
4 are "I"
3 are "'"
2 are "g"
2 are "."
2 are "M"
3 are "c"
2 are "
"
2 are "/"
3 are "]"
5 are "X"
2 are "2"
4 are "="
3 are "3"
2 are "("
2 are "A"
2 are "*"
2 are "N"
3 are "}"
3 are "f"
2 are "K"
Besides unquoted numbers, my output has 988 characters.
3 are "B"
108 are "e"
11 are "s"
3 are "i"
5 are "d"
214 are " "
8 are "u"
4 are "n"
3 are "q"
9 are "o"
9 are "t"
5 are "m"
4 are "b"
108 are "r"
3 are ","
4 are "y"
4 are "p"
6 are "h"
108 are "a"
3 are "I"
3 are "'"
4 are "g"
5 are "."
3 are "M"
7 are "c"
102 are "
"
2 are "{"
198 are """
2 are "`"
2 are "_"
2 are "~"
2 are "+"
2 are ":"
2 are "T"
2 are ";"
2 are "&"
2 are "/"
2 are "]"
2 are "X"
2 are "2"
2 are "="
2 are "3"
2 are "("
2 are "A"
2 are "*"
2 are "N"
2 are "}"
2 are "f"
2 are "K"
It's good to be a program.

11

ตัวอักษร Ruby, 269 (311, 367)

ฉันมีคำตอบสามข้อสำหรับความท้าทายนี้ แต่ละคนใช้ชุดของเทคนิคที่แตกต่างกัน:

โซลูชัน "เหมาะสม", 367 ตัวอักษร:

ทางออกที่ยาวที่สุดนั้นมากหรือน้อยเพียงแค่พิสูจน์แนวคิดที่เป็นไปได้ในการแก้ปัญหานี้โดยไม่ต้องใช้กลอุบายใด ๆ มันเป็นควินจริง (นั่นคือมันสร้างซอร์สโค้ดของตัวเองแทนที่จะอ่านจากไฟล์) และคำนวณตัวเลขทั้งหมดที่พิมพ์ (ความยาวรหัสความยาวเอาท์พุทอักขระที่ปรากฏ) เนื่องจากวิธีการทำงานของ quine รหัสทั้งหมดจะต้องอยู่ในบรรทัดเดียวและภายในตัวอักษรสตริง

eval r="S='eval r=%p'%r;O=-~$.;q=\"My source has \#{S.size}\"+(X=' characters.\n')+S.chars.uniq.map{|c|[k=S.count(c),k>O ? :are: :is,?\"+c+?\"]*' '}*$/+'\nBesides unquoted numbers, my output has ';r=(w=q+X+s=\"It's good to be a program.\").scan(D=/\\D/).uniq;$><<q<<(w+v=r.map{|c|j=' are \"\n\"';(-~(w+j*r.size).count(c)).to_s+(j[~O]=c;j)}*$/+$/).scan(D).size<<X+v+s"

เอาต์พุตฮาร์ดโค้ดบางส่วน, 311 ตัวอักษร:

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

โปรดทราบว่าโค้ดจะถูกนำหน้าด้วยการขึ้นบรรทัดใหม่ที่สำคัญมากสองบรรทัดซึ่ง StackExchange จะไม่แสดงในบล็อคโค้ด ด้วยเหตุผลดังกล่าวฉันได้เพิ่มบรรทัดเพิ่มเติมไว้ข้างหน้าหากมีการขึ้นบรรทัดใหม่ซึ่งไม่ได้เป็นส่วนหนึ่งของรหัส

#


eval R="I=$/+$/+'eval R=%p'%R;?\\4>w='%d are \"%s\"';B=\"My source has \#{I.size}\#{X=\" characters.\n\"}\#{z=(m=I.chars.uniq).map{|x|w%[I.count(x),x]}*$/}\nBesides unquoted numbers, my output has 1114\"+X;$><<B+m.map{|c|w%[(B+z+$M=\"\nIt's good to be a program.\").gsub!(/\\d++(?!\")/,'').count(c),c]}*$/+$M"

ทางออกที่สั้นที่สุด 269 ตัวอักษร:

การแก้ปัญหาที่สั้นที่สุดนอกจากนี้ฮาร์ดโค้ดความยาวของแหล่งของตัวเอง โดยการใช้ชื่อตัวแปรที่ / ยังไม่ได้เป็นส่วนหนึ่งของซอร์สโค้ดคุณสามารถค้นหา "fixpoint" โดยที่อักขระทั้งหมดในซอร์สโค้ด (รวมถึงตัวเลขจากความยาวฮาร์ดโค้ด!) เกิดขึ้นอย่างน้อยสองครั้ง

โซลูชันนี้ยังช่วยประหยัดอักขระเพิ่มอีกไม่กี่ตัวโดยเพียงแค่อ่านซอร์สโค้ดของตัวเองจากไฟล์โค้ดแทนที่จะสร้างมัน ในฐานะที่เป็นผลข้างเคียงที่ดีนี้ทำให้รหัส "อ่านง่าย" มากขึ้น (แต่ผู้ที่ใส่ใจเกี่ยวกับรหัสที่อ่านได้ใน ... ) ขณะนี้รหัสไม่ต้องอยู่ภายในตัวอักษรสตริงอีกต่อไป

U='%d are "%s"'
O=IO.read$0
?\126>B="My source has 269#{X=" characters.
"}#{z=(m=O.chars.uniq).map{|c|U%[O.count(c),c]}*$/}
Besides unquoted numbers, my output has 1096"+X
$><<B+m.map{|c|U%[(B+z+$M="
It's good to be a program.").gsub!(/\d++(?!")/,"").count(c),c]}*$/+$M

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

import subprocess

CODE = open("packed.rb").read()
OUTPUT = subprocess.check_output(["ruby", "packed.rb"])

print CODE
print len(CODE)

ตอนนี้สคริปต์จะรันโค้ดของฉันโดยอัตโนมัติอ่านเอาต์พุตและหยิบซอร์สโค้ดจากไฟล์โค้ด


นี่คือผลลัพธ์ที่สร้างขึ้นโดยรหัสที่สั้นที่สุด:

My source has 269 characters.
3 are "U"
7 are "="
3 are "'"
4 are "%"
6 are "d"
17 are " "
11 are "a"
9 are "r"
9 are "e"
11 are """
11 are "s"
6 are "
"
4 are "O"
2 are "I"
10 are "."
6 are "$"
2 are "0"
2 are "?"
2 are "\"
2 are "1"
2 are "2"
3 are "6"
2 are ">"
4 are "B"
3 are "M"
2 are "y"
9 are "o"
10 are "u"
12 are "c"
4 are "h"
2 are "9"
2 are "#"
4 are "{"
2 are "X"
8 are "t"
4 are "}"
2 are "z"
6 are "("
7 are "m"
5 are "n"
2 are "i"
2 are "q"
6 are ")"
4 are "p"
4 are "|"
2 are "["
4 are ","
2 are "]"
2 are "*"
4 are "/"
3 are "b"
7 are "+"
2 are "<"
3 are "g"
2 are "!"
Besides unquoted numbers, my output has 1096 characters.
2 are "U"
2 are "="
3 are "'"
2 are "%"
5 are "d"
238 are " "
120 are "a"
120 are "r"
120 are "e"
222 are """
11 are "s"
114 are "
"
2 are "O"
3 are "I"
5 are "."
2 are "$"
2 are "0"
2 are "?"
2 are "\"
2 are "1"
2 are "2"
2 are "6"
2 are ">"
3 are "B"
3 are "M"
4 are "y"
9 are "o"
8 are "u"
7 are "c"
6 are "h"
2 are "9"
2 are "#"
2 are "{"
2 are "X"
9 are "t"
2 are "}"
2 are "z"
2 are "("
5 are "m"
4 are "n"
3 are "i"
3 are "q"
2 are ")"
4 are "p"
2 are "|"
2 are "["
3 are ","
2 are "]"
2 are "*"
2 are "/"
4 are "b"
2 are "+"
2 are "<"
4 are "g"
2 are "!"
It's good to be a program.

คุณช่วยโพสต์สำเนารหัสและเอาท์พุทของคุณเพื่อให้ฉันสามารถทดสอบได้อย่างง่ายดายหรือไม่? รหัสไม่ควรส่งออกตัวเองและการส่งออกควรสิ้นสุดในช่วงเวลาที่ไม่ขึ้นบรรทัดใหม่
งานอดิเรกของ Calvin

@ Calvin'sHobbies การบล็อกรหัสแรกคือรหัสจริงของฉัน มันพิมพ์ผลลัพธ์ด้วยการขึ้นบรรทัดใหม่สุดท้ายดังนั้นขอเวลาสักสองสามนาทีเพื่อแก้ไขสิ่งนั้น (นี่คือสิ่งที่คุณควรพูดถึงอย่างแน่นอนในสเปค)
Ventero

แน่นอนฉันเพิ่งอัปเดตข้อมูลจำเพาะ
งานอดิเรกของ Calvin

@ Calvin'sHobbies Done First code block เป็นรหัสที่แท้จริงซึ่งสร้างขึ้นโดยบล็อคโค้ดตัวที่สอง (เพื่อที่ฉันจะได้ไม่ต้องจัดการกับการหลบหนีของสตริงและทุกอย่างในขณะที่เขียนโค้ด)
Ventero
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.