http://qs321.pair.com?node_id=84005


in reply to Daft text adventure project

Several comments:
References are Scalars
Perl has a few data types, the most common of which are lists, hashes, and scalars. A reference is a scalar. It "refers" to any data type. This is advantagious, because it allows you to put a non-scalar data type where you would normally store a scalar. For example, A hash is a collection of scalars. You can't make $foo{Bar} hold a hash, but you can make it hold a reference to a hash. This means you can have nested data types.

Let's try a simple example for your program. Let's just say that you wanted to have multiple characters. You could have %characters hold them, with their name as the key, so that $characters{'Bob the Fighter'} would hold Bob's info. What is Bob's info? well, he'll have Attributes, Feats, Skills, Level, and so forth. Each of those could be a hash storing more detailed info. Let's initialize a sample:

$characters{'Bob the Fighter'} = { #The brackets create a reference t +o an anonymous hash. 'Attributes' => { # We're nesting a second hash 'Str' => 10, 'Dex' => 10 }, #Done with that hash 'Level' => 1, #Storing a normal scalar 'Feats' => { #Another hash! 'Light_Armor' => 1 #Treating as a boolean } #done with Feats Hash }; #done with hash that is stored in $characters{'Bob the Fighter' +}
To access some of Bob's data, we de-reference the reference with the arrow operator: $character{'Bob the Fighter'}->{'Attributes'}->{'Str'} would equal 10.

References are key to any complicated data manipulation in Perl. I suggest experimenting.

Replies are listed 'Best First'.
Re: Re: Daft text adventure project
by Tiefling (Monk) on May 30, 2001 at 16:19 UTC
    Thanks!

    I have looked at the existing state of play, and the conclusion I draw is that if I were only ever going to be interested in writing an RPG or IF I would certainly get, learn and use Inform. However, I am doing this with the two equally strong interests of writing an RPG and getting really good at Perl, OOP, etc. So I'm determined to do it the hard way, so that at the end (if there is an end), I can say 'thus did Tiefling', and understand every bit of my code. Also, I'm not sure how receptive Inform (for example) would be to an attempt to build all the core D&D character classes and several prestige classes.

    As a note, I will be producing (in the end) a modern-setting version of the game which will lack the specific copyrighted identities, and be a bit more in the whimsical line of early text adventures. This will be posted here on PM, in all likelihood.

    As for your explanation of references - thanks! This looks like the way to implement the first Perl version of my project. One question: is the long string in your penultimate line a single scalar for all purposes?

    Oh, and another: Could I include lists in that hash by reference? (Storing feats, spells, etc. as booleans is not efficient, IMHO. I want to be able to brew a new feat and not have to go and set the bit in all the PCs.)

    And another: If, for example, $character{'Bob'}->{'Class'} holds 'Ftr', and $class{'Ftr'}->{'Base Attack'} holds 'Good' (to indicate that fighters have Good attack bonuses, which are generated by a short procedure in the combat module), what would be the code to retrieve Bob's Base Attack type? I may be being dense here, but I'd rather be clear.

    Thanks again!

    Tiefling
      So I'm determined to do it the hard way, so that at the end (if there is an end),

      Doing it the hard way is a time-honored tradition :) I just suggested you check out how the others work so that you can steal good ideas & interfaces.

      is the long string in your penultimate line a single scalar for all purposes?

      You mean $character{'Bob the Fighter'}->{'Attributes'}->{'Str'}? Yes, because in the end it is just a value stored in a hash, and only scalars can be thus stored. By dereferencing part of that mess, you can get a hash. For example, %{ $character{'Bob the Fighter'}->{'Attributes'} } is the Attributes hash. (The scalar value $characters{'Bob the Fighter'}->{'Attributes'} is a reference to a hash. the %{ } dereferences the reference.

      Could I include lists in that hash by reference?

      Absolutely. A reference to anything is a scalar, and a hash can store a scalar. An anonymous list can be created by [], or you can use the backslash reference. So:

      $characters{'Bob the Fighter'}->{'Feats'}= [ 'Strong Spit', 'Perl Guru +']; # or @feats = ('Strong Spit', 'Perl Guru'); $characters{'Bob the Fighter'}->{'Feats'} = \@feats;
      both work just fine. You can then access them like:
      $characters{'Bob the Fighter'}->{'Feats'}->[1]; #is equal to 'Perl Guru'
      Remember that although we're using a hash as our "base" variable here, we could use any other data type that is appropriate. A list could work:
      $characters[3]->{'Attributes'}->{'Str'};
      as could a scalar:
      $characters->{'Bob the Fighter'}->{'Attributes'}->{'Str'};
      (Assuming you had stored the data in that fashion.)

      If, for example, $character{'Bob'}->{'Class'} holds 'Ftr', and $class{'Ftr'}->{'Base Attack'} holds 'Good' (to indicate that fighters have Good attack bonuses, which are generated by a short procedure in the combat module), what would be the code to retrieve Bob's Base Attack type?

      Well, $class{$character{'Bob'}->{'class'}}->{'Base Attack'} would be equal to $class{'Ftr'->{'Base Attack'} (actually, it would _BE_ the same, since all that happens is $character{'Bob'}->{'Class'} resolves to 'Ftr') However, this assumes that Bob's class will ALWAYS have an entry in %class.

      Storing feats, spells, etc. as booleans is not efficient, IMHO. I want to be able to brew a new feat and not have to go and set the bit in all the PCs.)

      Just so you know, Perl handles non-existant hash keys quite nicely, and it's quite common to see code that would be like:

      if($char{Bob}->{Feats}->{'Good With Pointy Objects'}){ Kill_Bad_Guy(); } else { Die_Hideous_Death(); }
      If Bob doesn't have that feat, you don't have to set it to 0, you simply don't set it to a true value, and it will evaluate False. (Well, undefined, which in turn is false)