13
Write a program that outputs the total number of characters and the frequency of each character in its source and its output. You must follow the format illustrated in the example.
Example
If your code was
abb1
Its output would have to be
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.
(Output must go to stdout.)
Notice, for example, that the output contains two capitalized m's. One for My
and one for 2 are "M"
. This must hold true for all characters so the output does not contradict itself in any way.
Unquoted numbers are ignored in the output to avoid unsatisfiable frequency sets. For example, 1 is "1"
is incorrect if both 1's are counted. It should read 2 are "1"
, but then there is only one 1 again.
Format Clarifications
"is" must be used for single character occurrences.
"are" must be used for multiple character occurrences.
"is" should never appear in the list of output characters because it would be superfluous.
1 is 'Z'
refers to the Z in itself, so the entire line can be removed.The three full-sentence phrases must appear in order with the character frequency lists in between (as the example shows). So your output will start with
My source...
and end with...be a program.
. Note that there is no newline at the end of the output.The character frequency lists themselves may be in any order.
Newlines count as one character (in case they are \r\n).
Format Checker
The following Python script takes your code and its output as strings and asserts that the output has no contradictions. It provides a useful error message if something is wrong. You can run it online at http://ideone.com/6H0ldu by forking it, replacing the CODE and OUTPUT strings, then running it. It will never give false positives or negatives (assuming its error free).
#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()
Scoring
This is code-golf. The submission with the fewest characters wins. Submissions must pass the format checker to be valid. Standard loopholes apply, though you may read your own source code and/or hardcode your output.
Is reading your own source file allowed? – Ventero – 2014-07-12T02:52:29.417
@MrLore There may be other errors but I just realized that the triple quotes (''') still escapes things with backslash. This may be related to your problem. I'm fixing it now. – Calvin's Hobbies – 2014-07-12T02:52:44.127
@Ventero Definitely! – Calvin's Hobbies – 2014-07-12T02:53:02.577
@MrLore The regexps allow some false positives, yes. To fix the problem with backslashes inside triple quotes, use raw strings (
r'''CODE'''
). – Ventero – 2014-07-12T02:53:32.990@Calvin'sHobbies Meh. Could've saved a lot of effort then. Since you have tagged this as [tag:quine], I figured the somewhat-standard quine loophole wouldn't be allowed. – Ventero – 2014-07-12T02:54:34.447
Sorry about that. I imagined that even with reading your own source the task is still fairly tricky. – Calvin's Hobbies – 2014-07-12T02:57:34.700
1@MrLore Fixed unescaped dots. Thanks for noticing! – Calvin's Hobbies – 2014-07-12T03:06:01.520
"Besides unquoted numbers..." So we're playing on easy mode, huh? – algorithmshark – 2014-07-12T05:19:36.170
if the program outputs something related to its output, that's recursive. How can we avoid infinite output? – xem – 2014-07-12T06:39:08.867
@xem Well for one thing Ventero already proved it was possible. Also, for every unique character in the output (or code) the output can only increase by 10 characters (11 counting the output size going from 95 to 105, for example). There aren't infinitely many unique characters. – Calvin's Hobbies – 2014-07-12T06:59:06.937
Does the program have to analyze its own source and output, or can it just output the right stuff (with some hardcoding)? – aditsu quit because SE is EVIL – 2014-07-15T16:49:30.347
@aditsu Hardcoding things is fine. – Calvin's Hobbies – 2014-07-15T22:06:24.273