Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

P2P Golf: MoleSter

by hossman (Prior)
on Dec 15, 2004 at 22:08 UTC ( #415203=obfuscated: print w/ replies, xml ) Need Help??

As seen on slashdot, a fully functional P2P client in a 625 character perl script.

Who wants to take the first crack at golfing this down?

Comment on P2P Golf: MoleSter
Re: P2P Golf: MoleSter
by dragonchild (Archbishop) on Dec 16, 2004 at 14:04 UTC
    It'd be nice to know how to test this w/o requiring another active P2P peer. That said, I found 10 characters, simply from syntax. If we didn't mind it being like 30 lines long, we could take advantage of newlines for another 15ish characters.
    $p=shift;$a=a(shift);i(shift);socket S,2,1,6;bind S,$a;listen S,5;undef$/;while(@ARGV&&($_="$p $a f".shift)||accept(C,S)&&($_=<C>)&& +close C){m!^(.*?) (.*?) ([e-i])([^/]*)/!s&&$1 eq$p&&&$3($2,$4,$')}sub e{open F,'>',$_[1];print F $_[2];close F}sub f{t($_,@_)for keys%k}sub g{open(F,'<',$_[1])&& t($_[0],$a,"e$_[1]",<F>);close F}sub h{t($_[0],$_,'i')for keys%k}sub i{$k{$_[0]}=1}sub a{$_[0]=~/:/;pack'CxnC4x8',2,$',split'\.',$`}sub t{socket X,2,1,6;$w=shift;if(connect X,a($w)){print X "$p $_[0] $_[1]/$_[2]";close X}else{undef$k{$p}}}

    Update: This is what I just submitted back to the author. I think it ends up being 516 characters over 8 lines.

    $/=$_;$(=shift;$a=shift;i(shift);socket S,2,1,6;bind S,a($a);listen S,5;while(@ARGV&&($_="$( $a f".shift)||accept(C,S)&&($_=<C>)&&close C){m!^(.*?) (.*?) ([e-i])([^/]*)/!s&&$(eq$1&&&$3($2,$4,$')}sub f{t($_, +@_)for keys%k}sub a{pop=~/:/;pack'CxnC4x8',2,$',split'\.',$`}sub i{$k{$_[0]}= +1}sub g{open(F,"<$_[1]")&& t($_[0],$a,"e$_[1]",<F>);close F}sub h{t($_[0],$_ +,'i')for keys%k}sub t{socket X,2,1,6;if(connect X,a($w=shift)){print X "$( $_[0] $_[1]/$_[2]";close X}else{undef$k{$w}}}sub e{open F,">$_[1]";print F $_[2];close F}

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      The easiest way to test it is to run it twice, and have each instance run on a different port. Then they can communicate with each other.


      ___________
      Eric Hodges

      You should be able to get rid of at least 4 more characters by getting rid of the " F" after the two "close F"'s. Without an argument, close will close the currently selected filehandle.

      The above is actually 7 lines if you get every line as close to 80 chars as possible.

      -b

        The above is actually 7 lines if you get every line as close to 80 chars as possible.

        True, but you gain characters by doing that. The reason for where the newlines are is to cut spaces from the final tally. You'll notice every newline is after a select, close, sub, or for. That's not coincedence. :-)

        Thanks for the tip on close().

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      You did better than I did (_especially_ with optimizing sub a, and with getting rid of the Socket constants, which I knew was possible but didn't do), although you did miss a couple of opportunities...

      • As someone else also noted, undef$/, while it saves one stroke over the original, is still suboptimal. I have $/=$3. A related situation occurs later with undef$k{$p}, only there $3 might be defined, so I have $k{$p}=$7 in that case. $7 will always be undef in molester. Update: your updated version does this in the first of the two cases.
      • open F,'>',$_[1] is slightly suboptimal. I have open F,">$_[1]", saving one stroke. I saved another stroke doing the same thing when it's opened for reading. Update: your updated version does this too.
      • Because sub a is declared before sub t, you can dispense with the parens when t calls a, saving two characters: (connect X,a$w) Update: your updated version does even better than this.
      • My /. post doesn't _demonstrate_ this, but it mentions it: converting the if/else isn't as fruitful as I'd hoped, due to the need to use and after the print (for precedence reasons), but it does shave off a couple of strokes. Update: I believe this is still good for a couple of strokes.
      • another update: I think we can shave one more stroke by using a statement modifier in sub g. This will cause F to be closed whether it's successfully opened or not, but that should be okay I _think_.
      • Yet Another Update: But I lost that character again fixing what I think is a bug in your regex optimization, having to do with the slashes that separate commands.

      We also both missed the argumentless-close trick that someone else pointed out, although I would have to test that one to be sure it doesn't close the socket also (or that doing so doesn't change the operation of the script). Can someone confirm which close statements need their arguments and, for that matter, whether it's possible to eliminate any of the close statements altogether without breaking something?

      So I threw out my version and worked from yours update: again, and this is what I now have, weighing in at 508 bytes not counting line breaks (522 bytes with a full ASCII CRLF ending every line but the last, or 515 with Unix-style one-character newlines):

      $/=$_;$(=shift;$a=shift;i(shift);socket S,2,1,6;bind S,a($a);listen S,5;while(@ARGV&&($_="$( $a f".shift)||accept(C,S)&&($_=<C>)&&close C){m!^(.*?) (.*?) ([e-i])([^/]*)./!s&&$(eq$1&&&$3($2,$4,$')}sub f{t($_ +,@_)for keys%k}sub a{pop=~/:/;pack'CxnC4x8',2,$',split'\.',$`}sub i{$k{$_[0]}= +1}sub g{t($_[0],$a,"e$_[1]",<F>)if open F,"<$_[1]";close F}sub h{t($_[0],$_, +'i')for keys%k}sub t{socket X,2,1,6;(connect X,a($w=shift))?print X"$( $_[0] $_[1]/$_[2]"and close X:$k{$w}=$7}sub e{open F,">$_[1]";print F $_[2];close F}

      Note that this code is completely, utterly untested.


      "In adjectives, with the addition of inflectional endings, a changeable long vowel (Qamets or Tsere) in an open, propretonic syllable will reduce to Vocal Shewa. This type of change occurs when the open, pretonic syllable of the masculine singular adjective becomes propretonic with the addition of inflectional endings."  — Pratico & Van Pelt, BBHG, p68
        I got a reply from the author and worked a "little" on it this morning. I'm down to 470 characters over 6 lines. There's a few bugs and several security holes fixed. Fixing them cost a few bytes, but I think it's worth it, overall. I mean, what use is showing Python we can beat them in program size if the program sucks? We have to show them we can write secure network software in 6 lines or less. *grins*

        The author is working on revamping the while() loop and moving to use read() instead of <> for the socket. But, I don't have that version, so I'll work with what I have.

        sub f{for$w(keys%k){&t}}$/=$_;($,,$w=$a,%k)=splice@ARGV,0,3;socket S,2 +,1,6;bind S,&a;sub i{$k{$w}=1}sub a{$w=~/:/;pack'CxnC4x8',2,$',split'\.',$`}sub +t{socket X,2,1,6;if(connect X,a){print X "$, $_[0] $_[1]/$_[2]";close}else{dele +te$k{$w}}} listen S,5;while(@ARGV&&($_="$, $a f".shift)||accept(C,S)&&($_=<C>)&&c +lose){ m!(\S*) ([e-i])([^/]*)/!s&&$,eq$`&&&$2($w=$1,$3,$')}sub e{open F,'>',$ +3;print F $';close}sub g{open(F,'<',$3)&&t$a,"e$3", <F>;close F}sub h{t$_,i for +keys%k}

        This code is sooo completely untested. :-) The readable version ...

        Update: After jonadab's suggestions and some reorganization, we save 11 characters (down to 459 over 6 lines):

        sub f{for$w(keys%k){&t}}$/=$_;($,,$w=$a,%k)=splice@ARGV,0,3;socket S,2 +,1,6;bind S,&a;sub i{$k{$w}=1}sub a{$w=~/:/;pack'CxnC4x8',2,$',split'\.',$`}sub +t{socket X,2,1,6;connect(X,a)?print(X "$, $_[0] $_[1]/$_[2]")&&close:delete$k{$ +w}}listen S,5;while(@ARGV&&($_="$, $a f".shift)||accept(C,S)&&($_=<C>)&&close){s +ub h{t$_,i for keys%k}m!(\S*) ([e-i])([^/]*)/!s&&$,eq$`&&&$2($w=$1,$3,$')}sub e{o +pen F,'>',$3;print F $';close}sub g{open(F,'<',$3)&&t$a,"e$3",<F>;close F} }

        Yes, there's a subroutine definition in the while-loop. "perl -MO=Deparse" tells me it's ok.

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: P2P Golf: MoleSter
by blazar (Canon) on Dec 16, 2004 at 15:10 UTC
    Well, the actual code is:
    $p=shift;$a=shift;i(shift);socket S,2,1,6;bind S,&a($a);listen S,5;$/=undef;while(@ARGV&&($_="$p $a f".shift)||accept(C,S)&&($_=<C>)& +&close C){m!^(.*?) (.*?) ([e-i])([^/]*)/!s&&$1 eq$p&&&$3($2,$4,$');}sub e{ope +n F,'>',$_[1];print F $_[2];close F}sub f{&s($_,@_)for keys %k}sub g{open(F,'<',$_[1])&&&s($_[0],$a,"e$_[1]",<F>);close F}sub h{&s($_[0],$_,'i')for keys %k}sub i{$k{$_[0]}=1}sub a{$_[0]=~/:/;pack'CxnC4x8',2,$',split'\.',$`}sub s{socket X,2,1,6;$w=shift;if(connect X,&a($w)){print X "$p $_[0] $_[1]/$_[2]";close X}else{undef $k{$p}}}
    Of course I'm not the one "Who wants to take the first crack at golfing this down" but giving a peek into the first few lines I notice that there's plenty of room for golfing. In fact I'm only a mediocre golfer, but golfers for example generally pop() rather than shift().

    Or, for example, C<undef$/;> takes one keystroke less than C<$/=undef;>. But then (e.g.) C<$/=$_> will do and is even shorter.

    Again, selecting a randomly picked line, I'm a big fan of the three-arguments form of open(), but C<open(F,'<',$_[1])> can be replaced by C<open F,pop>.

    As a side note, since we're talking golf here, well one doesn't generally care much about good programming practices in this context. But the author of the original code's systematic (&-form of) calling of subs clearly tells what his programming skills can be...

      • You actually cannot use pop instead of shift in the first line unless you rearrange the argument list order. The same goes for most of the subroutines.
      • You cannot use open F,pop; because there are 3 args coming in, not 2.
      • The &x() syntax is actually the golfed version in several places, particularly &$3($2,$4,$');. Now, in others, it can be removed. But, I sincerely doubt it has anything to do with the author's skills as a programmer. Personally, I'm impressed with a P2P client in under 1000 characters.

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        You actually cannot use pop instead of shift in the first line unless you rearrange the argument list order.

        If there's no ordering dependencies between things (in this case &a and &i don't seem to depend on one being called before the others, and neither references $p) you can if you just reverse the order you pop rather than the argument order . . .

        i(pop);$a=a(pop);$p=pop;...

        Update: D'oh, missed the @ARGV later on. Never mind me.

        You actually cannot use pop instead of shift in the first line unless you rearrange the argument list order. The same goes for most of the subroutines.
        WOW! Thank you so much for having pointed out so: I would have never imagined myself...

        What I wanted to stress is that even for a mediocre golfer like me at a first glance the code, despite some evident conciseness still was largely suboptimal from this point of view for just applying a standard golfing technique like using pop() instead of shift() (and reversing the order of the arguments - pointing out the obvious, just to keep you satisfied) wherever applicable would have saved quite a lot charachters.

        But then it's well known that experienced golfers use any sort of more refined tricks. For example I can remember one case in which there were four arguments to take from the cmd line and it was practically mandatory to assign these to variables so they used something along the lines of this (since the golf rules did not require strictures or warnings): $$_=pop for a..d;

        You cannot use open F,pop; because there are 3 args coming in, not 2.
        Huh?!?
        The &x() syntax is actually the golfed version in several places, particularly &$3($2,$4,$');. Now, in others, it can be removed. But, I sincerely doubt it has anything to do with the author's skills as a programmer. Personally, I'm impressed with a P2P client in under 1000 characters.
        Well, indeed if we're talking symrefs then you're right. It may also save some chars in other situations. Generally with modern enough perls the &-syntax does not do what one expects, and as a matter of a fact unless there's a really good reason to adopt it (and indeed in golfing and obfuscation games there may be some well beyond "regular" ones), code that abuses it reveals that he/she who wrote it is still programming Perl4. I'm not sure if this is the case with this particular program, but this is the impression I got at a quick glance.
Re: P2P Golf: MoleSter
by bgreenlee (Friar) on Dec 16, 2004 at 16:30 UTC

    I missed this post yesterday, as I was deep into writing my own perl P2P app, after someone posted the challenge to the Fun With Perl mailing list. Mine is slightly bigger (717 characters, including newlines), but still 9 lines. I worked under the assumption that any modules in the standard perl distro were fair game (hence IO::Socket)

    I tried to emulate the operation of the original python version as closely as possible. I did add one feature that i thought was essential, though: the ability to view files on the network without actually downloading them.

    I'm sure better golfers than I could knock this down a bit.

    Anyway, mine is used like so:

    Server:
    perl tinyp2p.pl server <passwd> <listenhost:listenport> [<peerhost:peerport>]

    Client:
    perl tinyp2p.pl client <passwd> <serverhost:serverport> list|get <pattern>

    Note that when entering a pattern, you need to escape the backslash. So to search for .mp3 files, the pattern would be \\.mp3$

    use IO::Socket;($t,$s,$u,$p,$x)=@ARGV;if($t eq"server"){$p&&($p{$p}++, +map{$_ ne $u&&$p{$_}++}f($p,2,$u));while($c=new IO::Socket::INET(LocalAddr=>$u,R +euse=>1, Listen=>9)->accept()){if(<$c>eq"$s\n"){($r=<$c>)>1?do{print$c "$_\n"fo +r keys%p; chomp($a=<$c>);$a&&$p{$a}++;}:do{chomp($x=<$c>);for(grep/$x/,<*>){$z=( +stat)[7]; print$c "$_/$z\n";if($r>0){open G,$_;read G,$b,$z;close;print$c $b}}}} +close$c}} for$v($u,f($u,2,0)){printf"%s (%s)\n",@$_ for f($v,$p eq"get",$x)}sub +f{($h,$q, $m)=@_;$k=new IO::Socket::INET($h)||return;print$k "$s\n$q\n$m",define +d$m?"\n": '';$q>1?chomp(@r=<$k>):do{@r=();while(<$k>){chomp;($f,$e)=split'/';pus +h@r,[$f,$e ]if!$q|!-e$f;next if!$q|-e$f;read$k,$b,$e;open F,">$f";print F$b;close +}};@r}

    -b

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: obfuscated [id://415203]
Approved by kutsu
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2014-07-12 02:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (238 votes), past polls