LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Using hash value as key for other hash in Perl (https://www.linuxquestions.org/questions/programming-9/using-hash-value-as-key-for-other-hash-in-perl-414663/)

scuzzman 02-12-2006 04:40 PM

Using hash value as key for other hash in Perl
 
I'm having a fit with this. I have the following hashes set up:
Code:

my %fleet_def = ( # defenders fleet
  "sc" => Ship -> new(),
  "lc" => Ship -> new(),
  "lf" => Ship -> new(),
  "hf" => Ship -> new(),
  "cr" => Ship -> new(),
  "bs" => Ship -> new(),
  "cs" => Ship -> new(),
  "rc" => Ship -> new(),
  "ep" => Ship -> new(),
  "bm" => Ship -> new(),
  "ss" => Ship -> new(),
  "de" => Ship -> new(),
  "rip" => Ship -> new(),
  "ml" => Ship -> new(),
  "sl" => Ship -> new(),
  "hl" => Ship -> new(),
  "gc" => Ship -> new(),
  "ic" => Ship -> new(),
  "pc" => Ship -> new(),
  "ssd" => Ship -> new(),
  "lsd" => Ship -> new(),
);
my %rand_hash = ( # hash for random number gen. to determine ship
  "1" => "sc",
  "2" => "lc",
  "3" => "lf",
  "4" => "hf",
  "5" => "cr",
  "6" => "bs",
  "7" => "cs",
  "8" => "rc",
  "9" => "ep",
  "10" => "bm",
  "11" => "ss",
  "12" => "de",
  "13" => "rip",
  "14" => "ml",
  "15" => "sl",
  "16" => "hl",
  "17" => "gc",
  "18" => "ic",
  "19" => "pc",
  "20" => "ssd",
  "21" => "lsd",
);

What I want to do using these, is call a random number, and use it to call a variable in the Ship struct that is set up, like this:
Code:

$rand = ( int(rand(13)) + 1 );
until ( defined( $fleet_att{$rand_hash{$rand}} -> quantity ) { #test if ship exists
  $rand = ( int(rand(13)) + 1 ); #if not, reinitialize the variable with a new rand
}

But, for some reason, every time I execute this, I get these errors:
Code:

[scuzzy@slackdell /home/scuzzy/ogame/perlsim/PerlSim]$ ./PerlSim.pl
syntax error at ./PerlSim.pl line 464, near ") {"
syntax error at ./PerlSim.pl line 470, near ") {"
syntax error at ./PerlSim.pl line 475, near "}"
Execution of ./PerlSim.pl aborted due to compilation errors.
[scuzzy@slackdell /home/scuzzy/ogame/perlsim/PerlSim]$

And yes, I'm doing this multiple times (hence the similar errors). What I don't understand, is that ") {" never appears in the code, so I can't isolate the problem, and I have trouble believing Perl cannot do this. Just in case it's needed, here is the entire section of code in which these are used:
Code:

  foreach $ship ( keys %fleet_def ) {
    $rand = ( int(rand(13)) + 1 );
    until ( defined($fleet_att{$rand_hash{$rand}} -> quantity) { #test if ship exists
      $rand = ( int(rand(13)) + 1 ); #if not, reinitialize the variable with a new rand
    }
    &shoot($ship, $rand_hash{$rand}, 2); # call &shoot function
    while ( &rf($ship, $rand) ) { # call &rf function to see if ship shoots again
      $rand = ( int(rand(13)) + 1 );
      until ( defined( $fleet_att{$rand_hash{$rand}} -> quantity ) { #test if ship exists
        $rand = ( int(rand(13)) + 1 ); #if not, reinitialize the variable with a new rand
      }
      &shoot($ship, $rand_hash{$rand}, 2); # call &shoot function
    }
  }


chrism01 02-12-2006 10:34 PM

Actually, the 1st line of your last quoted code block is:

foreach $ship ( keys %fleet_def ) {

which includes ") {" as per the error msg you are getting ...
Hopefully you are using:

#!/usr/bin/perl -w

and

use strict;

at the top of your code ?

scuzzman 02-13-2006 11:16 AM

OK - I got that problem solved - missed a parentheses :D

But I have other problems now. When I go to execute it, I get these errors:
Code:

[scuzzy@slackdell /home/scuzzy/ogame/perlsim/PerlSim]$ ./PerlSim.pl
Global symbol "$hull" requires explicit package name at ./PerlSim.pl line 139.
Global symbol "$weapon" requires explicit package name at ./PerlSim.pl line 140.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 140.
Global symbol "$hull" requires explicit package name at ./PerlSim.pl line 141.
Global symbol "$weapon" requires explicit package name at ./PerlSim.pl line 141.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 141.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 146.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 146.
Global symbol "$weapon" requires explicit package name at ./PerlSim.pl line 146.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 147.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 147.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 148.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 148.
Global symbol "$hull" requires explicit package name at ./PerlSim.pl line 150.
Global symbol "$hull" requires explicit package name at ./PerlSim.pl line 151.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 157.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 158.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 158.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 159.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 160.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 160.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 164.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 165.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 165.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 166.
Global symbol "$target" requires explicit package name at ./PerlSim.pl line 167.
Global symbol "$shield" requires explicit package name at ./PerlSim.pl line 167.
Global symbol "%rf_hash" requires explicit package name at ./PerlSim.pl line 221.
Global symbol "%rf_hash" requires explicit package name at ./PerlSim.pl line 222.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 446.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 449.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 450.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 451.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 452.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 453.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 454.
Global symbol "$desc" requires explicit package name at ./PerlSim.pl line 455.
Execution of ./PerlSim.pl aborted due to compilation errors.
[scuzzy@slackdell /home/scuzzy/ogame/perlsim/PerlSim]$

I think this might be a problem with the scoping, but there has to be a more elegant way of fixing that then explicitly saying $main:: on every variable. That said, the current code is here: http://www.scuzzman.org/perl/PerlSim.pl

Edit: I just made all the variables global, and now that's not happening... I shouldn't do this though, should I? http://www.scuzzman.org/perl/PerlSimv2.pl

chrism01 02-13-2006 04:54 PM

A few pts; feel free to ignore ...

1. Perl is not shell ie you do not have to pre-declare all your fns before you use them. Try the C method ie after any global declarations (see below), start with a main or ctrl fn and physically put the other subs below that. Perl is sort-of compiled before it's run.

2. Try to only declare variables as 'my' within the sub they are used. Pass as params where needed.
My guideline is that if you need a var in a lot of subs, declare a 'global' pkg and put them in there eg:

<code>
# Declare Config pkg so we can refer to it anywhere
{
package cfg;

# Config file params
%cfg::params = ();

# Database handle
$cfg::dbh = '';
}
</code>

3. Put a proper header for each sub, so you and/or anyone else can work out what's happening. here's an example of the way I do it:
<code>
#******************************************************************************
#
# Function : process_cc_rows
#
# Description : Main ctrl sub to delete cc rows older than eg 6 mths.
#
# Params : none
#
# Returns : none
#
#******************************************************************************
sub process_cc_rows
{
my (
$error_msg # log/email error if any
);

# Create a txn wrapper in case we have to rollback
db_start_txn();

# Delete all rows older than cfg specified
db_delete_cc_rows();
}
</code>

4. Personally, rather than require the user to re-enter all params each time, I'd create a (plain text) config or data file they can edit, so they can only change the values they want to (& change their minds easily).
Then just read the file at startup.

5. As you say, try not to use (unqualified) globals & try to minimise the num that you do you use. How different subs a var is used in constitute justification for putting a var into a global pkg is a personal judgement call. ;-)

6. No need to prefix subs with '&' when calling them. (unless passing as a ref ie \&sub_name). That's old-school Perl v4.

HTH

chrism01 02-13-2006 04:56 PM

PS : Note to moderators: why can't I edit my post??? I am logged in ...

scuzzman 02-14-2006 04:51 AM

Thanks for the pointers - my little project is starting to come together now :D
I have yet to implement your suggestions (though, I likely will). I'm waiting until I at least get it to work right once... then, I'm going to worry about pretty code vs. functional code. One thing though, it is VERY slow - would making the variables local speed it up?

chrism01 02-14-2006 05:08 PM

No, speed is generally due to bad design at some level eg unnecessary loops, wrong algorithms or badly written algorithms.
As for 'pretty' vs 'working', as someone whose been doing this for xxxxx yrs, take it from me, if you don't make it look right as you go, you'll never have time/inclination to go back and correct it later, esp in commercial env.
Also, it makes it easier to debug as you go.
:)


All times are GMT -5. The time now is 05:19 AM.