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

Dipseydoodle has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perlmonks. A while ago I began work on a Multi User Dungeon, but since then I have decided to cut out the "Dungeon" elements and go with a purely survival theme.

#!/usr/bin/perl use warnings; if ($diff = easy){ $wood = 120; } elsif ($diff = hard){ $wood = 75; } if ($diff = easy){ $food = 50; } elsif ($diff = hard){ $food = 20; } $maxRNG = 6; $RNG = rand($maxRNG); NAME: print "May I have your name please?\n"; chomp($name = <>); print "Thank you $name.\n"; sleep 1; system("clear"); goto DIFFICULTY; DIFFICULTY: print "Please enter a difficulty level: easy, or hard.\n"; chomp($diff = <>); print "you chose $diff.\n"; sleep 1; system("clear"); goto BEGIN; BEGIN: print "You have crash landed on a strange alien planet and must find a + way to get back to earth.\n"; goto PTURN; PTURN: print "\n"; print "You have $wood wood and $food food.\n"; print "You can:\n"; if($wood = 10){ print "BUILD a HUT with 10 wood\n"; }

As you can see I have set the amount of $wood to a selection in $diff. But this is not working. When I run it, I enter hard and it keeps the amount at 120. What am I doing wrong?

Replies are listed 'Best First'.
Re: SImulation of an Inventory.
by ww (Archbishop) on Jun 23, 2012 at 01:28 UTC

    Your script causes my perl (AS 5.14) to throw multiple messages... had you included use strict (as you should have), it would have filled the screen with your problems. But these are what you should have told us about, at a minimum, rather than tossing them into the "not working" garbage pile:

    Unquoted string "easy" may clash with future reserved word at D:\_Perl +_\pl_test\977910.pl line 6. Unquoted string "hard" may clash with future reserved word at D:\_Perl +_\pl_test\977910.pl line 9. Found = in conditional, should be == at D:\_Perl_\pl_test\977910.pl li +ne 13. Unquoted string "easy" may clash with future reserved word at D:\_Perl +_\pl_test\977910.pl line 13. Unquoted string "hard" may clash with future reserved word at D:\_Perl +_\pl_test\977910.pl line 16. Found = in conditional, should be == at D:\_Perl_\pl_test\977910.pl li +ne 20. Found = in conditional, should be == at D:\_Perl_\pl_test\977910.pl li +ne 47. Name "main::RNG" used only once: possible typo at D:\_Perl_\pl_test\97 +7910.pl line 21. D:\_Perl_\pl_test\977910.pl syntax OK
    • = makes an assignment; you want == in your conditional to test for (numeric equality or -- in this case -- eq or a regex to test the alpha entry you invite.
    • BUT even when you correct your ifs, you still have work to do. The Monastery is rife with examples of collecting input, so with the exception of the implicit hint there, learning how to fix it is yours to do.
    • Among other things, just using a more idiomatic way to deal with input won't make your code "good;" you also need to add some error handling: what should your script do if the user merely hits enter when asked for a name?
    • The gotos are utterly unnecessary in this script. You can take them out and have execution simply fall thru from one named section to another.
    • Your lines 5-17 attempt to execute before a value is assigned to $diff. (Think reordering your code or stuffing those lines into a sub, called after the other input is received).

    Try another iteration... show us how you solved these.

Re: SImulation of an Inventory.
by frozenwithjoy (Priest) on Jun 23, 2012 at 01:48 UTC

    In addition to ww's suggestions, you may want to choose an easier to read and more maintainable way for allocating resources according to difficulty level. Instead of all those ifs/elsifs, maybe try something like:

    #!/usr/bin/env perl use v5.10; # or later! use warnings; use strict; my ( $diff, $wood, $food ); $diff = "easy"; #consider given/when instead of ifs... given ($diff) { when (/easy/) { $wood = 120 ; $food = 50; } when (/hard/) { $wood = 75 ; $food = 20; } } say "I have $wood sticky sticks!"; say "I have $food delicious morsels!"; __END__ I have 120 sticky sticks! I have 50 delicious morsels!

    Adding a new difficulty level or resource-type into this structure is $diff eq "easy"; (of course, if you add more resources, you should probably adjust the formatting so they aren't all on one unreadable line...)

Re: SImulation of an Inventory.
by frozenwithjoy (Priest) on Jun 23, 2012 at 02:49 UTC
    If you'd like to incorporate dice rolls beyond using rand(), you should take a look at Games::Dice. For example roll '3d6+1' will return a value from 4 to 19.

      Thank you all. I'll go ahead and fix those then, I didn't know there was a need for eq, or a different call (I am totally self-taught here). I like the idea of the givens to by the way.

      @Superdoc That would make perfect sense, however I used the rand() for a reason. I need only a roll of 6 at max, and this is simply for random events.

      Thanks.

Re: SImulation of an Inventory.
by cavac (Parson) on Jun 24, 2012 at 20:16 UTC

    While this is technically Perl code, you might want to stop reading AMIGA BASIC books ;-)

    First of all, you should use strict; and use warnings;, so perl can help you find obvious errors.

    Second, please stop using goto for normal code flow (there are special cases where goto is an obvious choice, but this isn't one of those). Use subs.

    Third, instead of a multitide of named variables, look into using a hash. This will make further processing easier without too much work when you are expanding your inventory system.

    Fourth, from your program flow, you never enter a value for the difficulty before setting the other values

    Now that i have rambled about your code quality, let's try to improve it, shall we?

    First of all, we have to make it work in the first place. So let's reorder stuff and fix the numerous basic problems other monks already explained. And since we don't need all the flow control just yet, we'll temporarly remove it. We also remove the system() calls, because they are OS dependant and might not even work in every terminal.:

    #!/usr/bin/perl use strict; use warnings; my ($diff, $wood, $food); my $maxRNG = 6; my $RNG = rand($maxRNG); print "May I have your name please?\n"; chomp(my $name = <>); print "Thank you $name.\n"; print "Please enter a difficulty level: easy, or hard.\n"; chomp($diff = <>); print "you chose $diff.\n"; if ($diff eq "easy"){ $wood = 120; } elsif ($diff eq "hard"){ $wood = 75; } if ($diff eq "easy"){ $food = 50; } elsif ($diff eq "hard"){ $food = 20; } print "You have crash landed on a strange alien planet and must find a + way to get back to earth.\n"; print "\n"; print "You have $wood wood and $food food.\n"; print "You can:\n"; if($wood >= 10){ print "BUILD a HUT with 10 wood\n"; }

    Ok, that works. More or less. The inputs are not checked, it's still spagetti code and you have a lot of named variables that should be part of a system. Oh, and yes, you do the easy/hard IF operation twice. Let's tackle the two IF blocks first, we'll just turn them into a single (formatted) one:

    if ($diff eq "easy"){ $wood = 120; $food = 50; } elsif ($diff eq "hard"){ $wood = 75; $food = 20; }

    Much better, isn't it? Next, we'll put the inventory (wood and food) into a single hash. We'll also check the inputs of both questions:

    #!/usr/bin/perl use strict; use warnings; my %inventory; my $maxRNG = 6; my $RNG = rand($maxRNG); my $name = ""; while($name eq "") { print "May I have your name please? "; chomp($name = <>); } print "Thank you $name.\n"; while(1) { print "Please enter a difficulty level: easy or hard? "; chomp(my $diff = <>); if ($diff eq "easy"){ $inventory{wood} = 120; $inventory{food} = 50; last; } elsif ($diff eq "hard"){ $inventory{wood} = 75; $inventory{food} = 20; last; } else { next; } print "You chose $diff.\n"; } print "You have crash landed on a strange alien planet and must find a + way to get back to earth.\n"; print "\n"; print "You have:\n"; foreach my $item (sort keys %inventory) { print " $inventory{$item} $item\n"; } print "You can:\n"; if($inventory{wood} >= 10){ print "BUILD a HUT with 10 wood\n"; }

    Now, as a final cleanup step, let's take the two initialization functions (playername and difficulty) out of the bulk of the program and into a separate file (a perl module). No object orientation, just to show you how to separate functions so you wont end a with a hundred-thousand-lines file.

    After this final edit, we have two files. The main program (i called it alien.pl) reads:

    #!/usr/bin/perl use strict; use warnings; use AlienInit; my $maxRNG = 6; my $RNG = int(rand($maxRNG)+1); my $name = AlienInit::getUsername(); my ($diff, %inventory) = AlienInit::getInventory(); print "You have crash landed on a strange alien planet and must find a + way to get back to earth.\n"; print "\n"; print "You have:\n"; foreach my $item (sort keys %inventory) { print " $inventory{$item} $item\n"; } print "You can:\n"; if($inventory{wood} >= 10){ print "BUILD a HUT with 10 wood\n"; }
    and the file with the initialization functions called AlienInit.pm:
    package AlienInit; use strict; use warnings; sub getUsername { my $name = ""; while($name eq "") { print "May I have your name please? "; chomp($name = <>); } print "Thank you $name.\n"; return $name; } sub getInventory { my ($diff, %inventory); while(1) { print "Please enter a difficulty level: easy or hard? "; chomp($diff = <>); if ($diff eq "easy"){ $inventory{wood} = 120; $inventory{food} = 50; last; } elsif ($diff eq "hard"){ $inventory{wood} = 75; $inventory{food} = 20; last; } else { next; } print "You chose $diff.\n"; } return ($diff, %inventory); } 1;

    That's it. If we ever meet in person, i expect you to buy me a coffee (i use the same system with all my apprentices ;-)

    "You have reached the Monastery. All our helpdesk monks are busy at the moment. Please press "1" to instantly donate 10 currency units for a good cause or press "2" to hang up. Or you can dial "12" to get connected directly to second level support."

      Thanks. I think you solved two problems now.

      Oh and you totally got my by the way, I do love my BASIC languages, I guess I was trying to achive the same goal with this, thanks

Re: SImulation of an Inventory.
by 2teez (Vicar) on Jun 23, 2012 at 01:41 UTC

    "..What am I doing wrong?"
    Several! Please, use use strict; you will catch some.

    In your if statements you assign. I think what you intended was

    if($diff == 'hard'){...}

    You also have several barewords in your code..

      if($diff == 'hard'){...}

      That isn't right either, because it does a numeric comparison.

      It should be

      if($diff eq 'hard'){...}

        Oops! Thanks Eliya for catching that, you are right !