note
jonadab
<p>Well, I figured someone else would deobfuscate this, but
since nobody else has, here's an explantion for
posterity. First off, there are really very few
clever or sneaky "tricks" in this one to hide what's
going on, other than removing the comments and
renaming the variables tersely; most of it's just
straightforward dense logic and a little golf...
</p>
<readmore>
<code>
#!/usr/bin/perl
sub r{int rand pop} # Random integer generator, used quite a bit...
$|++; # Causes output autoflush, but also $| is used below for its new value, 1
@g=map{[map{' '}0..$=]}0..25; # sets $g[z][x] to a space for all x and all z, so we're starting with a blank grid.
my$j=pop||2+r(3); # Number of stickmen: user-specified or else at least two but not more than five.
@f=map{ # Each element of @f holds one stickman.
# Each stickman has some private variables:
my$k=my$n=$b++; # $n is the number of this stickman. $k is the number of his current "opponent".
my$z=1; # $z is his height off the ground.
my$x=r$=; # $x is the stickman's horizontal position.
# $= is used for its default value (60) and is the width of the field.
my($q,$v,$e)=my@l=(0,0,0,0);
# @l holds numbers corresponding to the positions of the stickman's four limbs.
# (leftarm, rightarm, leftleg, rightleg).
# 0 means the limb is down, 1 means out, 2 means up.
# $q and $v are velocities (horizontal and vertical respectively).
# $e is this stickman's "state": 0 = resting, 1 = attacking, 2 = fleeing.
my$h=r(9); # $h is "health", a.k.a. "breath", i.e., how long before the dude needs a breather.
$w= {# The variable $w is a decoy; what matters is that this assignment is the
# last thing in the sub and therefore this has reference is the value that
# is returned from the map. i.e., @f is an array of hashrefs, each one
# containing the closures that make the stickman work.
i=>sub {
# i stands for "iteration". This stuff happens once per "turn", for each stickman.
$k=r($j) while($k==$n or!$f[$k]); # Make sure stickman has a valid "opponent".
my$o=$f[$k]; # Prefetch the opponent hashref, for easy access.
$h+=($e?-1:1); # Resting regains breath; attacking and fleeing exhaust it.
if($h<1){$e=0;$k=$n} # If exhausted, rest, and choose a new opponent next iteration.
if($h>6){$e=1} # If we have enough breath, attack.
if(!$z){ # If we're at ground level, we can make decisions about movement...
my$u=($x<$$o{x}->()?1:-1); # Sets $u to the direction toward our opponent.
$u*=(($e>1)?-1:1); # Reverse that direction if we're fleeing.
$q=$e?($u*(r(7))):0; # Set horizontal velocity (0 if resting).
if($e>1){$q||=4} # If we're fleeing, we can't have a 0 horiz. velocity.
if($e and(r(7)>3)){$v=r(6)} # If not resting, there's a chance we might leap.
}
my$t=($$o{z}->()cmp$z)+1; # Target limb position. Up if opponent is up, down if down, out if neither.
$t=0 if($x==$$o{x}->()); # But if we're at the same horizontal position as opponent, put limbs down.
my$s=(($x<$$o{x}->())?1:0); # Selects left or right limbs, depending on opponent's relative position.
for(0,2){ # 0 is the base index into @l for arms; 2 is the base index for legs.
$l[$_+$s]+=($t cmp$l[$_+$s])} # Sets limb positions based on target position ($t) and side ($s).
for(0,2){
$l[$_+($s?0:1)]=0} # Put down the limbs on the other side.
if($z){$v-=2} # Gravity.
$x+=$q;$z+=$v; # Moves horiz. and vert. position based on the velocities.
$z=0 if$z<0; # Nobody falls below the ground.
if($x<2){$x=2;$q*=-1 if $q<0} # Nobody goes past the left edge...
if($x>$=-2){$x=$=-2;$q*=-1 if $q>0} # ... or the right edge.
if ((abs($x-($$o{x}->()))+1)*
(1+abs($z+1-($$o{z}->())))<9) # If we're "pretty close" to our opponent...
{
r(2)?($$o{c}->($n) or $e=1):${$f[$n]}{c}->($k);
# This triggers a conflict. Who "wins" is randomized.
# In the first case, we win and the opponent's collision
# routine is called with our number, and our state is set
# to attack. In the other case, our own collision
# routine is called with our opponent's number.
}
},
d=>sub {
# Draw routine. Places chars on the grid representing this stickman.
$g[20-$z][$x]="O"; # Head
$g[21-$z][$x]="+"; # Torso
$g[22-$z][$x]="|"; # Abdomen
for(0..1){ # 0 and 1 represent the two sides (left and right).
my@c=($_?('/','-',"\\"):("\\",'-','/'));
# On the left, / is down, - out, \ up. On the right it's the reverse.
$g[21-$z][$x+($_?1:-1)] # Upper arm:
=$l[$_]?'-':$c[2]; # - if arm is not at rest; down position otherwise.
$g[22-$z-$l[$_]][$x+($_?2:-2)] # Lower arm:
=$c[2-$l[$_]]; # up, out, or down if arm is up, out, or down.
$g[23-$z][$x+($_?1:-1)] # Upper leg:
=$l[2+$_]>1?'-':$c[2]; # - if limb is up, down view otherwise.
$g[24-$z-($l[2+$_]>1?1:0)][$x+($_?2:-2)] # Lower leg:
=$c[$l[2+$_]>1?1:2]; # - if up, down view otherwise.
}
},
z=>sub{$z}, # the z and x accessors are so that
x=>sub{$x}, # stickmen can get their opponents' positions.
n=>sub{$n=pop}, # Renumbers this stickman; used in cases of collision.
c=>sub { # Collision-recovery routine.
$h=0;$e=2; # Exhausted and fleeing...
$k=pop; # ... from the stickman who just collided with us.
$q=0; # No horizontal motion (initially).
if(!r(7)){ # But there's a small chance the stickman will no longer fight...
splice@f,$n,1; # In which case he's removed from the list,
for(@f){$$_{n}->($h++)} # and the list is renumbered.
}
}
}
}1..$j; # We put one of these stickmen in @f for each number from 1 to $j
while(1){ # Then we loop...
++$iter;# This was a holdover from debugging that I forgot to remove.
if(@f==1){exit 0} # If there's only one stickman left, he wins and we're done.
for$m(@f){ # Each stickman must
$$m{i}->();# do his once-per-loop stuff (an iteration)
$$m{d}->() # and then draw himself onto the grid.
}
print$/x$=; # This is a crude way of clearing the screen.
for $a(1..25){ # We're going to print 25 lines of the grid, starting at the top.
print$/,"|",@{$g[$a]},"|"; # The vertical bars are the left and right edges.
# The array in $g[$a] holds whatever characters the d routines of the stickmen have drawn there.
@{$g[$a]}=map{' '}0..$=; # This resets the line to blank for next
# time around, so the stickmen don't
# leave trails.
}
sleep 1 # I like [diotalevi]'s [select] much better, as the 1-second delay is really too long.
}#Optional command-line argument selects how many ninja stickmen.
</code>
</readmore>
<div class="pmsig"><div class="pmsig-230012">
<hr></hr>
<code>$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/</code>
</div></div>
297319
297319