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; }