The Daily WTF: Curious Perversions in Information Technology
Welcome to TDWTF Forums Sign in | Join | Help
in Search

Narcissistic program challenge

Last post 07-08-2008 10:50 AM by rdrunner. 28 replies.
Page 1 of 1 (29 items)
Sort Posts: Previous Next
  • 03-31-2008 1:57 PM

    Narcissistic program challenge

    Write a narcissistic program. Which means it takes the input and if it matches the program code you output 1, if it doesn't you output 0. Do not cheat by accessing the program's source code.

    : IF COMPILE ?-GOTO COMPILE-HERE ; IMMEDIATE
    : THEN HERE SWAP ! ; IMMEDIATE
    : ELSE COMPILE GOTO COMPILE-HERE SWAP HERE SWAP ! ; IMMEDIATE
  • 03-31-2008 2:12 PM In reply to

    Re: Narcissistic program challenge

    So basically this is a bizarre reverse-quine? WFT.
    irc://irc.slashnet.org/#TDWTF
    <Ling> Looks like [lotus] notes was indeed clock sucking and pissing wildly on my disk
    <Duplication_Prevention_Bot> Wow, that was a disturbing image.
  • 03-31-2008 2:32 PM In reply to

    Re: Narcissistic program challenge

    // narc.cpp
    
    #include <cstdio>
    
    int main()
    {
    	FILE narc = fopen("narc.cpp", "w+");
    
    	for (int ch = getchar(); ch != EOF; ch = getchar())
    		fputc(ch, narc);
    
    	fclose(narc);
    
    	puts("1");
    
    	return 0;
    }
    
    rpar PROTON all
  • 03-31-2008 2:39 PM In reply to

    Re: Narcissistic program challenge

    I have another solution too, but it involves you not being able to see the source.

    rpar PROTON all
  • 03-31-2008 4:44 PM In reply to

    Re: Narcissistic program challenge

    It's not even so much of a reverse quine - any quine that builds a string of its code can do a comparison between that and the input:

    <?php $str = '<?php $str = \'X\'; echo substr_replace($str, addslashes($str), 14, 1); ?>'; echo substr_replace($str, addslashes($str), 14, 1); ?>

    ... becomes ...

    <?php $str = '<?php $str = \'O\'; $prog = substr_replace($str, addslashes($str), 14, 1); if (!strcmp($argv[\'input\'], $prog)) echo \'1\'; else echo \'0\'; ?>'; $prog = substr_replace($str, addslashes($str), 14, 1); if (!strcmp($_GET['input'], $prog)) echo '1'; else echo '0'; ?>

    Briefcase is Lord!
  • 03-31-2008 5:09 PM In reply to

    Re: Narcissistic program challenge

    Here's a Ruby solution.... 

    cmd=<<EOF
      def do_compare(testFile,cmdString)
        cmdArr=cmdString.to_a.each {|l| l.chomp!}
        cmdArr[0,0]= "cmd=<<EOF"
        cmdArr.push "EOF","eval cmd","do_compare(ARGV[0],cmd)"
        testArr=File.open(testFile).collect.each {|l| l.chomp!}
        puts "1" if cmdArr==testArr
        puts "0" unless cmdArr==testArr
      end
    EOF
    eval cmd
    do_compare(ARGV[0],cmd)

  • 04-01-2008 10:39 AM In reply to

    • zentar
    • Not Ranked
    • Joined on 04-01-2008
    • Posts 3

    Re: Narcissistic program challenge

    This is the closest I could come up with, in a bash shell script:

    #!/bin/bash
    diff $0 $1 1> /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo 1
    else
        echo 0
    fi
  • 04-02-2008 6:27 AM In reply to

    • flop
    • Top 500 Contributor
    • Joined on 04-27-2007
    • Posts 51

    Re: Narcissistic program challenge

    If it must not access its own source code, there are two solutions: Either it accesses a copy of its own source code, or it uses another way to know whether it found it.

    Using a CRC32 would have too many false positives, so I settled for MD5 ... but my machine is too slow, I only have 14 of 32 characters matching: b452cdaf2785e22fb69cbb078cbafa80 vs. be32ca183785e22db6cbb52a18b528e0.

    #!/bin/sh
    
    CONSTANT=b452cdaf2785e22fb69cbb078cbafa80
    if [[ `md5sum < "$1" | cut -f1 -d" "` eq $CONSTANT ]]
    then
      echo 1
    else
      echo 0
    fi
    
    

    Please note that an empty line must be included at the end.

  • 04-02-2008 8:15 AM In reply to

    • flop
    • Top 500 Contributor
    • Joined on 04-27-2007
    • Posts 51

    Re: Narcissistic program challenge

    What I forgot to mention: Yes, I know about hashclash (http://www.win.tue.nl/hashclash/), and yes, I'm hoping for the best.

    Just a quick-and-dirty solution (try) ... If I'd replace all but 31 characters in the constant by ? I'd even have a match now. (Still standing at 14.)

  • 04-29-2008 8:59 PM In reply to

    Re: Narcissistic program challenge

    Here's one in JavaScript.  Doesn't access any files, and takes the Script tags into account. or input, just use any old textarea and paste it in, and onclick the value to the function:

     

    <script language='javascript'>
    function narcissistic(input) {
    var narcissist = "%3Cscript%20language%3D%27javascript%27%3E%0Afunction%20narcissistic%28input%29%20%7B%0A%09var%20narcissist%20%3D%20%22%22%3B%0A%09var%20narcissist2%20%3D%20narcissist.substr%280%2C119%29+escape%28narcissist%29+narcissist.substr%28119%29%3B%0A%09if%20%28input%20%3D%3D%20unescape%28narcissist2%29%29%20return%20true%3B%0A%09return%20false%3B%0A%7D%0A%3C/script%3E";
    var narcissist2 = narcissist.substr(0,119)+escape(narcissist)+narcissist.substr(119);
    if (input == unescape(narcissist2)) return true;
    return false;
    }
    </script>


    It's 'sourcecode pattern' var uses the pattern of the primary program without the escaped source put into it (just "" if unescaped), then drops it in programmatically on the next line.

    That way it can "know what it looks like when it knows what it looks like"

    but hell - it works without cheating! 

    The mind boggles,
    And yet the goggles,
    They do nothing.
  • 04-29-2008 9:10 PM In reply to

    Re: Narcissistic program challenge

    Whole HTML if anyone cares:


    <html>
    <head>
    <script language='javascript'>
    function narcissistic(input) {
    	var narcissist = "%3Cscript%20language%3D%27javascript%27%3E%0Afunction%20narcissistic%28input%29%20%7B%0A%09var%20narcissist%20%3D%20%22%22%3B%0A%09var%20narcissist2%20%3D%20narcissist.substr%280%2C119%29+escape%28narcissist%29+narcissist.substr%28119%29%3B%0A%09if%20%28input%20%3D%3D%20unescape%28narcissist2%29%29%20return%20true%3B%0A%09return%20false%3B%0A%7D%0A%3C/script%3E";
    	var narcissist2 = narcissist.substr(0,119)+escape(narcissist)+narcissist.substr(119);
    	if (input == unescape(narcissist2)) return true;
    	return false;
    }
    </script>
    </head>
    <body>
    <form name="mainform">
    <textarea name="inputdata" cols="400" rows="20" ></textarea><br>
    <input type="button"name="btn" value="test" onclick="alert(narcissistic(document.mainform.inputdata.value));">
    </form>
    </body>
    </html>
    It goes off the page to the right, but will show up if you copy/paste.  The program is considered from "<script..." to "...</script>" without the following linebreak.
    The mind boggles,
    And yet the goggles,
    They do nothing.
  • 04-30-2008 9:30 PM In reply to

    Re: Narcissistic program challenge

    unless I'm mistaken, this isn't much of a challenge right..?

     

    pseudo code:

     

    String programCode = "all the code in this file" ;

    if(input.equals(programCode)

        return 1;

    return 0;

     

     

    A more enjoyable solution would be to read the program from memory and work from there.. although you would only find out if the logic was the same, not the code itself.

  • 05-01-2008 1:28 AM In reply to

    • ammoQ
    • Top 10 Contributor
    • Joined on 04-13-2005
    • Vienna.Austria.Europe.Earth
    • Posts 3,333

    Re: Narcissistic program challenge

    The Enterpriser:

    unless I'm mistaken, this isn't much of a challenge right..?

     

    pseudo code:

     

    String programCode = "all the code in this file" ;

    if(input.equals(programCode)

        return 1;

    return 0;

     

    I'm not sure whether or not this post is for real, so just in case you really mean it: 

    You will soon find out that the "all the code in this file" part is really hard.

    Because it's impossible even in pseudocode (linebreaks removed and escaping ommited for clarity):


    String programCode = "String programCode = "all the code in this file" ; if(input.equals(programCode)) return 1; return 0;" ;

    if(input.equals(programCode))

        return 1;

    return 0;

     

    You can repeat that ad infinitum without getting anywhere. 

    beanbag girl 4ever
  • 05-01-2008 3:35 AM In reply to

    Re: Narcissistic program challenge

    fair enough, for those of us who are too lazy to type to infinity...

    I'd go with the hash solution. Although finding out the hash of the source code where the source code includes said hash, sounds like a fun problem in itself.

     

     

  • 05-01-2008 12:18 PM In reply to

    Re: Narcissistic program challenge

    The Enterpriser:

    fair enough, for those of us who are too lazy to type to infinity...

    I'd go with the hash solution. Although finding out the hash of the source code where the source code includes said hash, sounds like a fun problem in itself.

     

     

    The only way is to construct the source at runtime out of data that is the source without the "source var" populated.  A hash could work if it was reverseable, because you'll need to manipulate the sourcecode var at runtime.  I went with escaping the source to a hex string because you can still perform string parsing on the whole variable without corrupting the value.

    The mind boggles,
    And yet the goggles,
    They do nothing.
  • 05-01-2008 1:12 PM In reply to

    • ammoQ
    • Top 10 Contributor
    • Joined on 04-13-2005
    • Vienna.Austria.Europe.Earth
    • Posts 3,333

    Re: Narcissistic program challenge

    Time to post a really working solution that perfectly matches the challenge...

    Edit: Oops, I haven't seen until now that BeenThere seems to have solved the challenge, too, one day before me...

     

    #include <stdio.h>
    int main(int argc, char **argv ) { char b[999]; char f[999]; char *s="#include <stdio.h>%cint main(int argc, char **argv ) { char b[999]; char f[999]; char *s=%c%s%c; sprintf(b,s,10,34,s,34,10); fread(f,1,451,stdin); putc(48+(feof(stdin) && !memcmp(f,b,450)),stdout); putc(10,stdout); return 0; }%c"; sprintf(b,s,10,34,s,34,10); fread(f,1,451,stdin); putc(48+(feof(stdin) && !memcmp(f,b,450)),stdout); putc(10,stdout); return 0; }

    Runs on Linux, because it depends on LF as line delimiters (as opposed to CR LF on Windows). But you Windows users can easily change that, can you?

    [erich@iTux ~]$ ./narcist <narcist.c
    1
    [erich@iTux ~]$ ls -l narcist.c
    -rw-r--r-- 1 erich erich 450 Mai 1 19:11 narcist.c
    [erich@iTux ~]$  

    Make sure the source is exactly 450 bytes long, no extra linefeeds etc. allowed... 

    Readable (but non-working b/c of the extra whitespace) version of the source code:
    #include <stdio.h>
    int main(int argc, char **argv ) { char b[999]; char f[999];
    char *s="#include <stdio.h>%cint main(int argc, char **argv ) { char b[999]; char f[999]; char *s=%c%s%c; sprintf(b,s,10,34,s,34,10); fread(f,1,451,stdin); putc(48+(feof(stdin) && !memcmp(f,b,450)),stdout); putc(10,stdout); return 0; }%c";
    sprintf(b,s,10,34,s,34,10);
    fread(f,1,451,stdin);
    putc(48+(feof(stdin) && !memcmp(f,b,450)),stdout);
    putc(10,stdout);
    return 0;
    }
    beanbag girl 4ever
  • 05-01-2008 10:50 PM In reply to

    Re: Narcissistic program challenge

    Shameful cheating I know...

    open(PROGRAM,">>narc.pl");
    $input = $ARGV[0];
    $input =~ s/\W//g;
    print PROGRAM "#" . $input;
    close PROGRAM;
    print 0;

  • 05-02-2008 6:43 PM In reply to

    Re: Narcissistic program challenge

    The Enterpriser:
    Shameful cheating I know...

    open(PROGRAM,">>narc.pl");
    $input = $ARGV[0];
    $input =~ s/\W//g;
    print PROGRAM "#" . $input;
    close PROGRAM;
    print 0;

     

    You do realize that "cheat" method has been posted several times over in this very thread, right?   Basically, that's plagerism off a "fail" which...I can't begin to quite understand...

    The mind boggles,
    And yet the goggles,
    They do nothing.
  • 05-03-2008 6:52 AM In reply to

    Re: Narcissistic program challenge

     

    You do realize that "cheat" method has been posted several times over in this very thread, right?   Basically, that's plagerism off a "fail" which...I can't begin to quite understand...

     

    No, where? 

  • 05-05-2008 5:14 PM In reply to

    Re: Narcissistic program challenge

    Three perl solutions, they grown scarier (but also cheat more) as you go

     

    print <<'' x 2 . "\n" eq join'',<STDIN>
    print <<'' x 2 . "\n" eq join'',<STDIN>
    
    --
    use B::Deparse;sub x{
    undef $/;
    print 'use B::Deparse;sub x' . 'B::Deparse'->new->coderef2text(\&x) . "x;\n" eq <STDIN>;
    }x;
    --
    #!perl
    $ENV{PERL5DB}='*DB::DB=sub{}';exec"$^X -d -0777 $0"if!$^P;
    binmode STDIN;print <STDIN>eq join'',@{"_<$0"}[1..3];
  • 05-05-2008 9:52 PM In reply to

    Re: Narcissistic program challenge

    The Enterpriser:

    I'd go with the hash solution. Although finding out the hash of the source code where the source code includes said hash, sounds like a fun problem in itself.

     

    Since you know exactly what the line containing the hash looks like, just keep it out of the hash:

    uuse Digest::MD5;
    $hash = '83b099b39b1679357ceebe2dc394f0ed';
    @data = ;
    $removed = splice @data, 1, 1;
    $result = Digest::MD5::md5_hex( join "", @data );
    print $result eq $hash and $removed eq "\$hash = '$hash';";
  • 05-06-2008 2:32 AM In reply to

    • flop
    • Top 500 Contributor
    • Joined on 04-27-2007
    • Posts 51

    Re: Narcissistic program challenge

    omega0:
    Since you know exactly what the line containing the hash looks like, just keep it out of the hash:

    Nice trick. But I think you forgot the \\n in the $hash-comparision... and @data seems a bit destroyed, too. "uuse" is good as well ;-)

  • 05-07-2008 3:33 PM In reply to

    Re: Narcissistic program challenge

    Attempting for worse abuse of the rules:

     

    #include <stdio.h>

     int main(int argc,char**argv)

    {

    /* since all inputs which could be passed to this program would be copies, rather than the original code itself, nothing matches. */ 

        return 0;

  • 05-08-2008 4:31 PM In reply to

    Re: Narcissistic program challenge

    You could also read in a string, and put a null character somewhere in the source.

    rpar PROTON all
  • 05-08-2008 4:51 PM In reply to

    • ammoQ
    • Top 10 Contributor
    • Joined on 04-13-2005
    • Vienna.Austria.Europe.Earth
    • Posts 3,333

    Re: Narcissistic program challenge

    It's actually not that very difficult to solve that challenge. Just take any one of the quine-type self-replicating programs that are available in large numbers, and redirect the output to a buffer that is finally compared against the input. Adjust the quine part, done.

    beanbag girl 4ever
  • 05-29-2008 5:45 PM In reply to

    Re: Narcissistic program challenge

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char out[ 16000 ];
    int j = 0;
    
    const char* fmt = "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nchar out[ 16000 ];\nint j = 0;\n\nconst char* fmt = \"?\";\n\nint main( int chg )\n{\n    int i;\n    int len = strlen( fmt );\n\n    for ( i = 0; i < len; i++ )\n    {\n        if ( chg > 0 )\n        {\n            if ( fmt[ i ] == \'\\x3f\' )\n               {\n                   main( 0 );\n               }\n               else\n               {\n                   out[ j++ ] = fmt[ i ];\n               }\n               continue;\n         }\n\n         switch ( fmt[ i ] )\n         {\n             case \'\\n\' :\n                 out[ j++ ] = \'\\\\\';\n                 out[ j++ ] = \'n\';\n                 break;\n\n             case \'\\\"\' :\n                 out[ j++ ] = \'\\\\\';\n                 out[ j++ ] = \'\\\"\';\n                 break;\n\n             case \'\\\\\' :\n                 out[ j++ ] = \'\\\\\';\n                 out[ j++ ] = \'\\\\\';\n                 break;\n\n             case \'\\\'\' :\n                 out[ j++ ] = \'\\\\\';\n                 out[ j++ ] = \'\\\'\';\n                 break;\n\n             default :\n                 out[ j++ ] = fmt[ i ];\n         }\n    }\n\n    if ( chg == 0 )\n    {\n        return 0;\n    }\n\n    out[ j++ ] = -1;\n\n    i = 0;\n    while( ! feof( stdin ) )\n    {\n        if ( getchar() != out[ i++ ] )\n        {\n            printf( \"0\\n\" );\n            return 0;\n        }\n\n    }\n\n    printf( \"1\\n\" );\n    return 0;\n}\n";
    
    int main( int chg )
    {
        int i;
        int len = strlen( fmt );
    
        for ( i = 0; i < len; i++ )
        {
            if ( chg > 0 )
            {
                if ( fmt[ i ] == '\x3f' )
                   {
                       main( 0 )