A Silly Task

October 22, 2019

Today’s task is silly:

Your task is to write a program that, when executed, writes to the output in words the number of characters in the program. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

6 Responses to “A Silly Task”

  1. James Smith said

    This time – no cheating and no real golfing…. OK – so works up to about 100K as I haven’t got the and/, rule right above that …. The critical bits are “-s $0” gives the size of the current file!, and stuff after END is ignored – added to test code for different lengths…

    #!/usr/local/bin/perl
    
    use feature qw(say);
    use strict;
    use warnings;
    
    my @u=('',qw(one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen));
    my @t=('',qw(ten twenty thirty forty fifty sixty seventy eighty ninety));
    my $s = -s $0;
    my @blocks;
    if( $s > 1000 ) {
      push @blocks, fs($s/1000).' thousand', ', ';
      $s %= 1000;
    }
    if( $s >= 100 ) {
      push @blocks, fs($s/100).' hundred',', ';
      $s %= 100;
    }
    push @blocks, fs($s),', ' if $s;
    pop @blocks;
    $blocks[-2] = ' and ' if @blocks > 2; ## Replace last "," with an "and".
    say @blocks;
    
    sub fs {
      my $x = shift;
      return $u[$x] if $x < 20;
      return $t[$x/10].' '.$u[$x%10] if $x%10;
    }
    
    __END__
    
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam lacinia lacinia nisi nec sollicitudin. Suspendisse cursus scelerisque sem id accumsan. Nulla ac quam tortor. Etiam ante urna, congue eget nunc eget, sollicitudin suscipit tellus. Nunc sed erat sagittis, ultricies diam nec, dapibus mauris. Sed consectetur ex ac ligula pellentesque viverra. Fusce varius facilisis facilisis. Nunc scelerisque, nibh in iaculis lacinia, libero nunc rutrum elit, id fringilla tortor arcu nec ex. Duis bibendum nisi metus, a aliquam nibh ultrices et. Etiam vulputate, neque quis finibus porta, neque ante luctus urna, quis suscipit turpis ligula at justo. Aliquam pretium laoreet urna in tincidunt. Duis laoreet auctor nisl et imperdiet. In mattis dolor sed tristique malesuada. Vestibulum nec sagittis dolor. Phasellus quis sapien ipsum. Sed placerat lacus at mauris auctor vestibulum.
    ....
    ....
    ....
    
  2. chaw said

    Here is a very naive solution in R7RS Scheme that I feel is more in
    keeping with the spirit of the question, which I interpreted in the
    vein of Quines.

    With that interpretation (which I realize may not be the author’s
    intention), the solutions so far by @programmingpraxis and James Smith
    are typically considered ‘”Cheating” quines”:

    https://en.wikipedia.org/wiki/Quine_(computing)#%22Cheating%22_quines

    (import (scheme base)
            (scheme write))
    'buf
    (display "eighty")
    (newline)
    

  3. matthew said

    Let’s use the excellent Python num2words library to make things easier. Since num2words is multilingual, and in the interests of international solidarity, we’ll generate solutions of the form “print(…)” in a variety of languages:

    from num2words import num2words
    for n in range(100):
        for lang in ['en','fr','de','it','ro','lt','lv','ar','he','vi']:
            s = "print('{}')\n".format(num2words(n,lang=lang))
            if n == len(s.encode()): print(n,":",s,end='')
    

    Output (note that we check the encoded length, not the number of characters):

    16 : print('sedici')
    18 : print('eighteen')
    18 : print('dix-huit')
    18 : print('achtzehn')
    18 : print('diciotto')
    20 : print('dvidešimt')
    20 : print('عشرون')
    20 : print('עשרים')
    20 : print('hai mươi')
    21 : print('vingt et un')
    23 : print('hai mươi ba')
    24 : print('vierundzwanzig')
    25 : print('fünfundzwanzig')
    25 : print('divdesmit pieci')
    25 : print('hai mươi lăm')
    29 : print('douăzeci și nouă')
    29 : print('עשרים ותשע')
    38 : print('ثمانية و ثلاثون')
    
  4. Daniel said

    Here’s a solution in Python.

    base = [
        'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven',
        'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'
    ]
    
    tens = [
        None, None, 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'
    ]
    
    thousands = [
        None, 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion',
        'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion',
        'quattuordecillion', 'quindecillion', 'sexdecillion', 'septendecillion', 'octodecillion',
        'novemdecillion', 'vigintillion', 'centillion'
    ]
    
    def convert(x):
        """Convert an integer to the corresponding words."""
        if x < 0:
            return f'negative {convert(abs(x))}'
        elif x < 20:
            return base[x]
        elif x < 100:
            q, r = divmod(x, 10)
            return tens[q] if r == 0 else f'{tens[q]} {base[r]}'
        elif x < 1000:
            q, r = divmod(x, 100)
            return f'{base[q]} hundred {convert(r)}'
        else:
            output = []
            parts = [int(part) for part in reversed(f'{x:,}'.split(','))]
            for part, thousand in zip(parts, thousands):
                if part == 0:
                    continue
                words = convert(part)
                if thousand:
                    words += f' {thousand}'
                output.append(words)
            return ' '.join(reversed(output))
    
    # Assumes __file__ has path to source code, not bytecode
    with open(__file__) as f:
        print(convert(len(f.read())))
    

    Output:

    one thousand five hundred fifty four
    
  5. matthew said

    Here’s a Python meta solution (ie. run the program to make a program), no libraries, no cheating. Iterate to a fix point to find the right length (proof of termination welcome):

    program = """\
    a = ["zero","one","two","three","four","five","six","seven","eight",
         "nine","ten","eleven","twelve","thirteen","fourteen","fifteen",
         "sixteen","seventeen","eighteen","nineteen"]
    b = ["twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"]
    
    def words(n):
        s = ""
        if n >= 1000:
            s += words(n//1000) + " thousand"
            n %= 1000
            if n == 0: return s
        if n >= 100:
            if s: s += ", "
            s += words(n//100) + " hundred"
            n %= 100
            if n == 0: return s
        if s: s += " and "
        if n >= 20:
            s += b[(n-20)//10]
            n %= 10
            if n == 0: return s
            s += "-"
        s += a[n]
        return s
    print(words({}))
    """
    
    def diag(program,n=0):
        while True:
            s = program.format(n)
            if n == len(s): return s
            n = len(s)
    
    print(diag(program),end="")
    

    Now we have:

    $ python3 silly.py | wc -c
    694
    $ python3 silly.py | python3
    six hundred and ninety-four
    
  6. Jan Van lent said

    A solution in Common Lisp using the loop syntax and built-in english language number formatting (“~r”).

    (with-open-file (f "a-silly-task.lisp")
      (format t "~r~%" (loop for c = (read-char f nil) while c counting c)))
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: