This program is the result of another afternoon of boredom. It's a number guessing game that uses multiple POE sessions to guess many numbers at once. It's not really a game since POE gets to have all the fun but oh well. It keeps you informed of the progress as it goes at least.

This program needs two parameters, an upper bound and lower bound. The random number will be between these bounds inclusive.

===LOOK BELOW THIS PROGRAM FOR AN EVEN COOLER VERSION===

#!/usr/bin/perl
# http://poe.perl.org/?POE_Cookbook/Multitasking_Solutions
#
# Android 18's ELITE POE parallel number guessing program!
# Provide two arguments on the command line:
#  the lower/upper bounds in that order that the random number
#  can be.
# Due to the use of "Bitch" in this program it has been rated PG-13 by the POE
# rating association of america (i.e. Android18).
# YES! I'm quite aware this can be done in a two liner like:
# my $num = rand(int(rand($ARGV[1] - $ARGV[0] + 1)) + $ARGV[0];)
# foreach($ARGV[0] .. $ARGV[1]) {print "Number is $_\n" if($_ == $num)}
use strict;
use warnings;
use Carp;
use POE;
@ARGV == 2
  or croak(
  "\$ARGV[0] and \$ARGV[1] must be" . "lower and upper bounds respectively");
our ($L_BOUND, $U_BOUND) = @ARGV;
$| = 1;

# Secret session that knows what the number
# "NumberKeeper"
POE::Session->create(
  inline_states => {

    # _start event will store the bounds and a random number into the heap,
    # set an alias so that other sessions can refer to it as
    # 'NumberKeeper'
    _start => sub {
      my ($kernel, $heap, $lb, $ub) = @_[KERNEL, HEAP, ARG0, ARG1];
      $heap->{NUM} = int(rand($ub - $lb + 1)) + $lb;
      $heap->{UB}  = $ub;
      $heap->{LB}  = $lb;
      $kernel->alias_set('NumberKeeper');
      print "NumberKeeper Session Started.\n";
    },

    # Other sessions send a 'guess' event with a guess in ARG0, this
    # session responds by either sending a corresponding 'correct' or
    # 'incorrect' event
    guess => sub {
      my ($kernel, $sender, $heap, $guess) = @_[KERNEL, SENDER, HEAP, ARG0];
      if ($guess == $heap->{NUM}) {
        $kernel->post($sender, 'correct');
      }
      else {
        $kernel->post($sender, 'incorrect');
      }
    },

    # Other sessions send a 'request_bounds' event to obtain the boundries
    # of the secret number. This session returns the lower bound and upper
    # bound in ARG0 and ARG1 respectively.
    request_bounds => sub {
      $_[KERNEL]->post($_[SENDER], 'bounds', @{$_[HEAP]}{'UB', 'LB'});
    },

    # It's always useful to know when a session meets its end. So this
    # session prints out a message when its about to die.
    _stop => sub {
      print "NumberKeeper Session dying.\n";
      print "Number was: $_[HEAP]->{NUM}\n";
      }
  },

  # arguments to _start will include the two boundries
  args => [$L_BOUND, $U_BOUND]
);

# User Session
# "User"
POE::Session->create(
  inline_states => {

    # The _start event for the User session will enqueue a 'request_bounds'
    # event. In this situation, it's kind of stupid because it enqueues an
    # event whose only task is to enqueue another. I did things this way
    # for two reasons: one, I wrote it really fast and wasn't thinking
    # clearly; two, I had a mindset of getting all the sessions set up
    # first and THEN sending stuff back and forth. This event also sets a
    # session alias, 'User'.
    _start => sub {
      my $kernel = $_[KERNEL];
      $kernel->yield('request_bounds');
      print "User session started.\n";
      $kernel->alias_set('User');
    },

    # When this session receives a 'request_bounds' event (from _start),
    # it will faithfully send another 'request_bounds' event to the
    # mysterious NumberKeeper session.
    request_bounds => sub {
      my $kernel = $_[KERNEL];
      $kernel->post('NumberKeeper', 'request_bounds');
      print "Requesting bounds.\n";
    },

    # The NumberKeeper session will answer with a 'bounds' event. ARG0 and
    # ARG1 are the lower bound and upper bound respectively. It takes these
    # and stores them onto the heap, then enqueues a 'solve' event
    bounds => sub {
      my ($kernel, $heap, $ub, $lb) = @_[KERNEL, HEAP, ARG0, ARG1];
      ($heap->{UB}, $heap->{LB}) = ($ub, $lb);
      $kernel->yield('solve');
      print "Retrieved bounds $lb .. $ub\n";
    },

    # The 'solve' event is bound to the Solve() subroutine, documented
    # later.
    solve => \&Solve,

    # When this session receives a 'solved' event, it means something
    # somewhere found the correct number and sent it to this session
    # (as ARG0). So it takes the answer and pushes it onto the heap.
    solved => sub {
      print "User session received solved number: $_[ARG0]\n";
      $_[HEAP]->{NUM} = $_[ARG0];
    },

    # When this session is on its death bed, it will finally decide to
    # share with the world it's accomplishment as it unveils the secret
    # number it has worked so hard to obtain. If what it thought the
    # secret number was turns out to be nothing more than an empty string,
    # something somewhere else has gone terribly wrong and the poor session
    # will die without ever knowing the secret it has spent its life
    # finding.
    _stop => sub {
      print "User Session dying.\n";
      if ($_[HEAP]->{NUM} ne '') {
        print "Number was: $_[HEAP]->{NUM}\n";
      }
      else {
        print "User session doesn't have correct number!\n";
      }
      }
  },
);
$poe_kernel->run();

# Elite sub that systematically creates bitch solver sessions
# I use the term 'bitch' because these child sessions act like nice little
# bitches that do their job and go away without ever asking why.
sub Solve {
  print "Solving for secret number.\n";

  # Get references to the kernel and heap.
  my ($kernel, $heap) = @_[KERNEL, HEAP];

  # Get the upper bound and lower bounds into nice variables so we don't need
  # to type all that $heap->{UB} nonsense.
  my ($ub, $lb) = @{$heap}{'UB', 'LB'};

  # Start a foreach loop to create bitches. Each bitch will guess one number
  foreach my $num ($lb .. $ub) {
    POE::Session->create(
      inline_states => {

        # Upon bitch creation, it will store the number it's meant to
        # guess onto its heap, ask the NumberKeeper session if it's
        # right, and print out that it has asked. The NumberKeeper
        # responds with a 'correct' or 'incorrect' event.
        _start => sub {
          $_[HEAP]->{NUM} = $num;
          $_[KERNEL]->post('NumberKeeper', 'guess', $num);
          print "Bitch " . $_[SESSION]->ID() . " created for guessing: $num\n";
        },

        # If the NumberKeeper session responds with a 'correct' event,
        # then the bitch sends the good news to the User session and
        # dies since nothing else has events queued for it and vise
        # versa.
        correct => sub {
          $_[KERNEL]->post('User', 'solved', $_[HEAP]->{NUM});
          print "Bitch " . $_[SESSION]->ID() . " received correct number!\n";
        },

        # If the NumberKeeper session responds with an 'incorrect'
        # event, so sorry tough luck, die like the little bitch you are!
        incorrect => sub {
          print "Bitch " . $_[SESSION]->ID() . " received incorrect number!\n";
        },

        # Right before you die let us know.
        _stop => sub {
          print "Bitch " . $_[SESSION]->ID() . " hath been slain!\n";
          }
      },
    );
  }
}

VERSION 2

This versoin is cool because it uses a variable number of minions working together to find the number. It also uses a new protocol so to speak, the NumberKeeper gives hints as to if the guess was too low, high, or correct. It takes the same 2 arguments with an option of a 3rd, the number of minions. If no third argumetn is given, a default of 5 will be used. This one doesn't have nearly as many comments. But since it's similar to the first it shouldn't be too tough to figure out. Email webmaster@android18.net if you have any questions.

#!/usr/bin/perl
# http://poe.perl.org/?POE_Cookbook/Multitasking_Solutions
#
# Android 18's ELITE POE parallel number guessing program!
# Version 2
use strict;
use warnings;
use POE;
use Carp;
our $DEFAULT_MINIONS = 5;
@ARGV >= 2
  or croak(
  "\$ARGV[0] and \$ARGV[1] must be" . "lower and upper bounds respectively\n");

# NUMBER KEEPER
POE::Session->create(
  args          => [$ARGV[0], $ARGV[1]],
  inline_states => {
    _start => sub {
      my ($kernel, $heap, $lb, $ub) = @_[KERNEL, HEAP, ARG0, ARG1];
      my $number = int(rand($ub - $lb + 1)) + $lb;
      $heap->{NUM} = $number;
      $heap->{UB}  = $ub;
      $heap->{LB}  = $lb;
      $kernel->alias_set('NumberKeeper');
      print "NumberKeeper born.\n";
    },
    guess => sub {
      my ($kernel, $sender, $heap, $guess) = @_[KERNEL, SENDER, HEAP, ARG0];
      if ($guess < $heap->{NUM}) {
        $kernel->post($sender, 'higher');
        print "NumberKeeper responds to guess: $guess (HIGHER)\n";
      }
      elsif ($guess > $heap->{NUM}) {
        $kernel->post($sender, 'lower');
        print "NumberKeeper responds to guess: $guess (LOWER)\n";
      }
      else {
        $kernel->post($sender, 'correct');
        print "NumberKeeper responds to guess: $guess (CORRECT)\n";
      }
    },
    request_range => sub {
      my ($kernel, $sender, $heap) = @_[KERNEL, SENDER, HEAP];
      $kernel->post($sender, 'range', $heap->{LB}, $heap->{UB});
    },
    _stop => sub {
      print "NumberKeeper slain.\n";
      }
  }
);

# NUMBER GUESSER
# Keeps track of most recent information and gives orders to its minions
POE::Session->create(
  inline_states => {
    _start => sub {
      my ($kernel, $heap) = @_[KERNEL, HEAP];
      my $MINIONS = 0;
      if (defined $ARGV[2] && $ARGV[2] > 0) {
        $MINIONS = $ARGV[2];
      }
      else {
        $MINIONS = $DEFAULT_MINIONS;
      }
      foreach (1 .. $MINIONS) {
        push(@{$heap->{Minions}}, CreateMinion("Minion$_"));
      }
      $kernel->post('NumberKeeper', 'request_range')
        ;    #responds with 'range' event
      $kernel->alias_set('Master');
      print "Number guesser born. $MINIONS minions created.\n";
    },
    range => sub {
      my ($kernel, $heap, $lb, $ub) = @_[KERNEL, HEAP, ARG0, ARG1];
      $heap->{LB} = $lb;
      $heap->{UB} = $ub;
      print "Recieved Range $lb .. $ub\n";

      # Start off by giving each of its minions a random number
      foreach my $minion (@{$heap->{Minions}}) {
        $kernel->post($minion, 'guess', RandInt($lb, $ub));
      }
    },
    response => sub {    #Minions send response events back
      my ($kernel, $sender, $heap, $guess, $response) =
        @_[KERNEL, SENDER, HEAP, ARG0, ARG1];
      return if (exists $heap->{NUM});

      # Used to test alias_list in scalar context
      my ($alias) = $kernel->alias_list($sender);
      my $newguess;
      if ($response eq 'higher') {
        print "$alias reports that $guess is too low.\n";
        if ($guess >= $heap->{LB}) {
          $heap->{LB} = $guess + 1;
          print "Adjusting lower bound to new value: $heap->{LB}\n";
        }
        else {
          print "No adjustment.\n";
        }
        $newguess = RandInt($heap->{LB}, $heap->{UB});
        print "Giving $alias new orders: guess $newguess\n";
        $kernel->post($sender, 'guess', $newguess);
      }
      elsif ($response eq 'lower') {
        print "$alias reports that $guess is too high.\n";
        if ($guess <= $heap->{UB}) {
          $heap->{UB} = $guess - 1;
          print "Adjusting upper bound to new value: $heap->{UB}\n";
        }
        else {
          print "No adjustment.\n";
        }
        $newguess = RandInt($heap->{LB}, $heap->{UB});
        print "Giving $alias new orders: guess $newguess\n";
        $kernel->post($sender, 'guess', $newguess);
      }
      else {
        print "$alias reports correct value at: $guess\n";
        $heap->{NUM} = $guess;

        # No more jobs, let the minion die off
      }
    },
    _stop => sub {
      print "Guesser session dying.\n";
      print "Value found: $_[HEAP]->{NUM}\n";
    },
  }
);
$poe_kernel->run();

# CreateMinion() returns a reference to a new minion session
# Minion sessions guess numbers, send updates to their parent and die when more
# orders are left to give
sub CreateMinion {    # (name)
  my $alias = shift;
  return POE::Session->create(
    inline_states => {
      _start => sub {
        $_[KERNEL]->alias_set($alias);
      },
      guess => sub {
        $_[HEAP]->{GUESS} = $_[ARG0];
        $_[KERNEL]->post('NumberKeeper', 'guess', $_[HEAP]->{GUESS});
      },
      higher => sub {
        $_[KERNEL]->post('Master', 'response', $_[HEAP]->{GUESS}, 'higher');
      },
      lower => sub {
        $_[KERNEL]->post('Master', 'response', $_[HEAP]->{GUESS}, 'lower');
      },
      correct => sub {
        $_[KERNEL]->post('Master', 'response', $_[HEAP]->{GUESS}, 'correct');
      },
      _stop => sub {
        print "$alias hath been slain!\n";
        }
    }
  );
}

sub RandInt {    # (lower, upper)
  my ($lb, $ub) = @_;
  return int(rand($ub - $lb + 1)) + $lb;
}