in reply to Creating a random generator

Here is the code of another small part of the full generator which will be in a seperate file of which there will be over a dozen. The first 3 scalars have default information in them. I would like to be able to change those values in the array (if necessary). I thought I had it right, but I don't get the expected result when I run on my computer.
#!/usr/bin/perl $b = beholder; $bk = "Monstrous Manual"; #default book $pg = 0; #defalt page number @gen = ( "beholder $b='' $pg=21", "death kiss $pg=21", "eye of the deep $pg=21", "gauth $pg=21", "spectator $pg=21", "undead $pg=21", "hive mother $pg=25", "director $pg=25", "examiner $pg=25", "lensman $pg=25", "overseer $pg=25", "watcher $pg=25" ); print "$gen[rand@gen] $b (<i>$bk</i>, pg $pg)", "\n";
The result I get is...
lensman 0=25 beholder (<i>Monstrous Manual</i>, pg 0)
instead of...
lensman beholder (<i>Monstrous Manual</i>, pg 25)
I tried moving the end quote to before the variables, but that just got me a lot of errors instead.
List of errors (condensed):
Scalar found where operator expected at C:\***\beholder.pl line 7, near ""beholder" $b" (Missing operator before $b?) line 7, near "'' $pg" (Missing operator before $pg?) line 8, near ""death kiss" $pg" (Missing operator before $pg?) line 9, near ""eye of the deep" $pg" (Missing operator before $pg?) line 10, near ""gauth" $pg" (Missing operator before $pg?) line 11, near ""spectator" $pg" (Missing operator before $pg?) line 12, near ""undead" $pg" (Missing operator before $pg?) line 13, near ""hive mother" $pg" (Missing operator before $pg?) line 14, near ""director" $pg" (Missing operator before $pg?) line 15, near ""examiner" $pg" (Missing operator before $pg?) line 16, near ""lensman" $pg" (Missing operator before $pg?) line 17, near ""overseer" $pg" (Missing operator before $pg?) line 18, near ""watcher" $pg" (Missing operator before $pg?) syntax error at C:\***\beholder.pl line 7, near ""beholder" $b" Execution of C:\***\beholder.pl aborted due to compilation errors.

Replies are listed 'Best First'.
Re^2: Creating a random generator
by wfsp (Abbot) on Sep 08, 2007 at 08:19 UTC
    I'm not clear on what you're trying to do. Perhaps putting the page numbers in a lookup table (a hash) would help get us along the road a bit.

    #!/usr/bin/perl use strict; use warnings; my $beholder = 'beholder'; my $book = 'Monstrous Manual'; #default book my @gen = ( 'beholder', 'death kiss', 'eye of the deep', 'gauth', 'spectator', 'undead', 'hive mother', 'director', 'examiner', 'lensman', 'overseer', 'watcher', 'Monstrous Manual', ); my %pg = ( 'beholder' => 21, 'death kiss' => 21, 'eye of the deep' => 21, 'gauth' => 21, 'spectator' => 21, 'undead' => 21, 'hive mother' => 25, 'director' => 25, 'examiner' => 25, 'lensman' => 25, 'overseer' => 25, 'watcher' => 25, ); my $section = $gen[rand @gen]; my $page = $pg{$section}; print "$section $beholder (<i>$book</i>, pg $page) \n";

      The first 3 scalars are default values. If they are not declared differently in the array, then they don't change. If they are declared in the array, then they change to the new value.

      Also, all variables have to be as small as possible. I try to conserve space as much as possible, hence the one and two letter variable names.

      In the array, the name of the monster will be chosen randomly, but the other information such as which book it comes from and what page it is on must be declared, hopefully, within the array. If I have to do separate hashes(?) for each value, it will be way to big. Other random generators with similar variables have up to 10 different variables changed all on one line.

      Hopefully that made sense.

      There is a random generation program that I use for what I am trying to recreate in Perl called TableSmith. If you know of it, that will show you where I am coming from.

        I find a lookup table is the way to go for these situations.
        #!/usr/bin/perl use strict; use warnings; my $beholder_default = 'beholder'; my $param = get_param(); my @keys = ( 'beholder', 'deathkiss', 'eye of the deep', 'gauth', 'spectator', 'undead', 'hive mother', 'director', 'examiner', 'lensman', 'watcher' ); my %lookup = ( 'beholder' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'death kiss' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'eye of the deep' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'gauth' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'spectator' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'undead' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'hive mother' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'director' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'examiner' => { book => 'Monstrous Manual', beholder => 'beholder', page => 21, }, 'lensman' => { book => 'Monstrous Manual', beholder => 'beholder', page => 25, }, 'overseer' => { book => 'Monstrous Manual', beholder => 'beholder', page => 25, }, 'watcher' => { book => 'Monstrous Manual', beholder => 'beholder', page => 25, }, ); my $key; if ($param){ $key = $beholder_default; } else{ $key = $keys[rand @keys]; } my $beholder = $lookup{$key}{beholder}; my $book = $lookup{$key}{book}; my $page = $lookup{$key}{page}; print "beholder: $beholder\n"; print "book: $book\n"; print "page: $page\n"; sub get_param { # get your input from somewhere my $param = undef; return $param; }
        Ah, I didn't see your update before I posted this.
Re^2: Creating a random generator
by Lady_Aleena (Priest) on Oct 11, 2007 at 04:06 UTC

    I was so excited, I found out about exists so I was going to apply it here. Now I can't figure out how to use it, or even if it will work with this.

    #!/usr/bin/perl -w use strict; use warnings; use diagnostics; use CGI; use CGI::Carp qw(fatalsToBrowser); my %Data; #This sub will eventually go into a module. sub random { my ($name) = @_; my $array = $Data{$name}; my $pick = $array->[rand @$array]; if (ref($pick) eq 'CODE') {return $pick->();} else {return $pick;} } $Data{gen} = [ 'beholder' => {b => 1,pg => 21}, 'death kiss' => {pg => 21}, 'eye of the deep' => {pg => 21}, 'gauth' => {pg => 21}, 'spectator' => {pg => 21}, 'undead' => {pg => 21}, 'hive mother' => {pg => 25}, 'director' => {pg => 25}, 'examiner' => {pg => 25}, 'lensman' => {pg => 25}, 'overseer' => {pg => 25}, 'watcher' => {pg => 25}, ]; print random("gen") exists ($gen{$b}) ? '' : ' beholder') exists ($gen{$bk})||exists ($gen{$pg}) ? ( ' ('. exists ($gen{$bk}) ? ($gen{$bk}) : 'Monstrous Manual') exists ($gen{$pg}) ? ', page '.($gen{$pg})) .')' ) ) keys %gen(@_)

    First, the item from the hash needs to be randomly selected.

    Then if the variable b is in the key's hash, then print nothing. If the variable b is not in the hash, print ' beholder'.

    Then if either bk or pg is in the key's hash, then print ' (' and check the following.

    If bk is in the hash, print it's value. If bk is not in the hash, print 'Monstrous Manual'.

    If pg is in the hash, print ', page ' and it's value. If pg is not in the hash, print nothing.

    After those two are done, print a final ')'.

    If neither bk nor pg are in the key's hash, then print nothing after the key.

      I was so excited, I found out about exists so I was going to apply it here. Now I can't figure out how to use it, or even if it will work with this.

      Your problem is not with "exists()" per-se. At the surface, your problem involves punctuation that is incomplete or incorrect, along with insufficient use of parens, when trying to glom together all the steps of your algorithm into a single concatenated string for a "print". Slow down.

      Also, you are getting mixed up about how your data structure is organized. You initialize %Data{gen} with square brackets, which creates a reference to an anonymous array, and the "random" function is set up to get an array ref from this hash element -- that part of the code says "%Data is a HoA structure".

      But the elements of data being assigned to %Data{gen} are laid out as a hash, with the value of each element being another hash, which says "%Data is a HoHoH structure" (e.g.  $Data{gen}{beholder}{pg} == 21). If you want HoHoH, the initialization would use curlies instead of square brackets:

      $Data{gen} = { 'beholder' => {b => 1, pg => 21}, 'death kiss' => {pg => 21}, ... };
      And you would need a different kind of "random()" function in order to select one of those sub-keys ("beholder, "death kiss", etc) at random -- maybe something like:
      sub random { my ( $key ) = @_; my @choices = keys %{$Data{$key}}; my $chosen = $choices[rand @choices]; return $Data{$key}{$chosen}; # or maybe just return $chosen ? }
      So the first thing to do is decide what sort of data structure you really want, and stick with that.

      But let's look at the overall task in terms of the way you describe your algorithm:

      First, the item from the hash needs to be randomly selected.
      my $output = my $randomkey = random( "gen" );
      Then if the variable b is in the key's hash, then print nothing. If the variable b is not in the hash, print ' beholder'.
      $output .= " beholder" unless ( exists( $Data{gen}{$randomkey}{b} ));
      Then if either bk or pg is in the key's hash, then print ' (' and check the following.

      If bk is in the hash, print it's value. If bk is not in the hash, print 'Monstrous Manual'.

      If pg is in the hash, print ', page ' and it's value. If pg is not in the hash, print nothing.

      After those two are done, print a final ')'.

      If neither bk nor pg are in the key's hash, then print nothing after the key.

      That's a bit of tough going, and your sample data doesn't seem to exercise all the contingencies. Still, let's see if I can rephrase it without damaging the intent:

      If either "bk" or "pg" exists in the key's hash, add a parenthesized string containing a book name, with or without a page number; for a "pg" with no "bk", the default book name is "Monstrous Manual":

      my $addon = ''; if ( exists( $Data{gen}{$randomkey}{bk} ) or exists( $Data{gen}{$randomkey}{pg} )) { $addon = $Data{gen}{$randomkey}{bk} || 'Monstrous Manual'; $addon .= ", page $Data{gen}{$randomkey}{pg}" if ( exists( $Data{gen}{$randomkey}{pg} )); } $output .= " ($addon)" if ( $addon );
      The rules for use of brackets (square and/or curly) when working with data structures require careful attention to detail, and a clear understanding of what your particular data structure is. Data::Dumper can help with that, but you need to need to start with a structure that makes sense to you, and organizes the data nicely for the things you need to do with it. When in doubt, go back to perlreftut, perlref and perldsc (Data Structures Cookbook) -- I've done that quite often, and it helps.

      (This thread is getting rather long in the tooth (and just long)... if you continue hitting walls with this pursuit, you might consider focusing on some relatively self-contained issue that is causing trouble, isolate it as a stand-alone problem, and post it as a new thread.)