Keep It Simple, Stupid PerlMonks

### Homework help

 on Oct 29, 2004 at 18:41 UTC Need Help??

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

Thank everyone! I got it working now. I learn just as much from the monks as I do from class.
Hello,
I'm taking a class in perl and this is my first time working in detail with hashes. One of my assignments is to prompt the user for a word, and then output the Scrabble score for that word. I'm using grep to find the letter in the hash and then give me the output but it doesn't seem to be working. Any advise on this would be helpful.
Thanks

Here is my code so far
```my %pay = ( A => 1,  F => 4,  K => 5,  P => 3,   U => 1,  Z => 10,
B => 2,  G => 2,  L => 1,  Q => 10,  V => 4,
C => 3,  H => 4,  M => 3,  R => 1,   W => 4,
D => 2,  I => 1,  N => 1,  S => 1,   X => 8,
E => 1,  J => 8,  O => 1,  T => 1,   Y => 4
);

my \$word;
my @word;
my @result;
print "Enter word to calculate.\n";
print "\nPress 'q' to quit\n";

while (){
print "\nWord?\n";
chomp (\$word = <STDIN>);
@word = split("", \$word);  # split up \$word
if (\$word eq 'q'){
print "Quiting program";
last;
}
foreach my \$w (@word){
@result = grep {defined \$w} @pay{@word};
}
for my \$r (@result){
print "[\$_]\n";
}
}

Replies are listed 'Best First'.
Re: Homework help
by radiantmatrix (Parson) on Oct 29, 2004 at 19:15 UTC

Firstly, grep is excessive. Since your keys are upper-case, simply use uc to upper-case things before matching.

```#!/usr/bin/perl
use strict;
use warnings;

my @words;
while (<STDIN>) { push @words, split /\s/ }
my %wordscore = scrabble_score(@words);
for (sort keys %wordscore) {
print qq/"\$_" = \$wordscore{\$_} points\n/;
}

sub scrabble_score {
my %value = ( A => 1,  F => 4,  K => 5,  P => 3,   U => 1,  Z => 1
+0,
B => 2,  G => 2,  L => 1,  Q => 10,  V => 4,
C => 3,  H => 4,  M => 3,  R => 1,   W => 4,
D => 2,  I => 1,  N => 1,  S => 1,   X => 8,
E => 1,  J => 8,  O => 1,  T => 1,   Y => 4
);

my %score;
for (@_) {
my @letter = split "", uc \$_;
my \$word = \$_;
\$score{\$word} = 0;
for (@letter) { \$score{\$word}+=\$value{\$_} }
}

return %score;
}
Note that it reads STDIN until EOF -- Ctrl-D on Unix/Linux and Ctrl-Z on Windows (followed by Enter on some of both types of systems). Or you can pipe in a word list... but you needn't have one word per line, as long as you use space between them.

Also, because of how hashes function, it will only print one instance of each word.

By the way, you aren't checking to make sure the word is possible in Scrabble: there are a limited quantity of each letter... :)

require General::Disclaimer;
"Users are evil. All users are evil. Do not trust them. Perl specifically offers the -T switch because it knows users are evil." - japhy
Re: Homework help
by ikegami (Patriarch) on Oct 29, 2004 at 19:23 UTC

I found two problems:

You're printing \$_, but \$r contains what you want to print.

You should uppercase the input (using uc()). Hash lookups are case-sensitive.

I also have two recommendations:

It would make more sense if if (\$word eq 'q'){ appeared before the split.

Something's really odd with your foreach+grep. In fact, there's no need for a foreach at all. Get rid of the foreach loops and use just @result = grep {defined \$_} @pay{@word}; (which simplifies to @result = grep defined, @pay{@word};). You'd be smart if you went and reread some examples using grep, and make sure you know what @hash{list} returns.

Now you just have to sum up the elements of @result with something like my \$sum = 0; \$sum += \$_ foreach @result;.

You could even remove the grep, replace it with a for/foreach loop that does both the validation and the summing. In fact, that's probably a good idea.

Here's how I'd do it:

```my %scores = (
map { \$_ =>  1 } qw( A E I L N O R S T U ),
map { \$_ =>  2 } qw( B D G               ),
map { \$_ =>  3 } qw( C M P               ),
map { \$_ =>  4 } qw( F H V W Y           ),
map { \$_ =>  5 } qw( K                   ),
map { \$_ =>  8 } qw( J X                 ),
map { \$_ => 10 } qw( Q Z                 ),
);

print("Find the Scrabble value of a word.\$/\$/");

for (;;) {
print("Enter a word (or just Enter to quit): ");
local \$_ = <STDIN>;
last unless defined;
chomp;
last unless length;
\$_ = uc(\$_);

my \$sum = 0;
\$sum += \$scores{\$1} while (/([A-Z])/g);

print("Scrabble value: \$sum\$/\$/");
}

I was playing around with this and noticed a harmless but problematic side-effect of the way you construct the hash.

```%scores = (
map { \$_ =>  1 } qw( A E I L N O R S T U ),
map { \$_ =>  2 } qw( B D G               ),
map { \$_ =>  3 } qw( C M P               ),
map { \$_ =>  4 } qw( F H V W Y           ),
map { \$_ =>  5 } qw( K                   ),
map { \$_ =>  8 } qw( J X                 ),
map { \$_ => 10 } qw( Q Z                 ),
);
print join(\$", sort keys %scores), \$/;

__END__
10 2 3 4 5 8 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Since you're filtering for letters, the numbers don't get picked up, but the maps are having a side-effect mapping of the other maps below them. Parens around the maps seems to fix it.

I also learned something from your example. I would have predicted that the last unless defined would not work right on empty input b/c \$_ still contains a "\n" which would be defined. I would have been wrong.

I would have predicted that the last unless defined would not work right on empty input b/c \$_ still contains a "\n"
It doesn't work on empty input. It works on eof/error. It's there to prevent the next two lines from giving "undefined value" warnings under use warnings. The last unless length that follows is what detects the empty string (since chomp removed the "\n" by then).

Wow, your %scores isn't defined correctly at all.

```# perl -l
my %scores = (
map { \$_ =>  1 } qw( A E I L N O R S T U ),
map { \$_ =>  2 } qw( B D G               ),
map { \$_ =>  3 } qw( C M P               ),
map { \$_ =>  4 } qw( F H V W Y           ),
map { \$_ =>  5 } qw( K                   ),
map { \$_ =>  8 } qw( J X                 ),
map { \$_ => 10 } qw( Q Z                 ),
);
print "\$_ => \$scores{\$_}" for keys %scores;
__END__
S => 1
T => 1
N => 1
K => 1
Y => 1
2 => 1
E => 1
Z => 1
J => 1
W => 1
B => 1
H => 1
D => 1
I => 1
10 => 1
G => 1
U => 1
F => 1
V => 1
Q => 1
M => 1
C => 1
L => 1
A => 1
O => 1
3 => 1
X => 1
P => 1
8 => 1
4 => 1
R => 1
5 => 1

Perhaps this is a good time for parentheses?

```my %scores = (
map( { \$_ =>  1 } qw( A E I L N O R S T U ) ),
map( { \$_ =>  2 } qw( B D G               ) ),
map( { \$_ =>  3 } qw( C M P               ) ),
map( { \$_ =>  4 } qw( F H V W Y           ) ),
map( { \$_ =>  5 } qw( K                   ) ),
map( { \$_ =>  8 } qw( J X                 ) ),
map( { \$_ => 10 } qw( Q Z                 ) ),
);
print "\$_ => \$scores{\$_}" for keys %scores;
__END__
Re: Homework help
by Popcorn Dave (Abbot) on Oct 29, 2004 at 19:33 UTC
The other monks have given you some good advice, however you mgiht also want to look in to the graphic debugger for Perl. This would allow you to watch what the variables hold while the program is executing. It's saved my rear numerous times.

You can find it here .

Good luck!

Useless trivia: In the 2004 Las Vegas phone book there are approximately 28 pages of ads for massage, but almost 200 for lawyers.
Re: Homework help
by FoxtrotUniform (Prior) on Oct 29, 2004 at 18:45 UTC
Re: Homework help
by waswas-fng (Curate) on Oct 29, 2004 at 19:27 UTC
```use strict;
use warnings;
my %pay = ( A => 1,  F => 4,  K => 5,  P => 3,   U => 1,  Z => 10,
B => 2,  G => 2,  L => 1,  Q => 10,  V => 4,
C => 3,  H => 4,  M => 3,  R => 1,   W => 4,
D => 2,  I => 1,  N => 1,  S => 1,   X => 8,
E => 1,  J => 8,  O => 1,  T => 1,   Y => 4
);

my \$word;
my @word;
print "Enter word to calculate.\n";
print "\nPress 'q' to quit\n";

while (){
my \$total_points = 0;
print "\nWord: ";
chomp (\$word = uc(<STDIN>));
die "Quiting program...\n" if (\$word eq 'Q');
foreach my \$letter (split("", \$word)){
\$total_points +=  \$pay{"\$letter"} if defined \$pay{"\$letter"} ;
printf "Letter \"%s\" = %d points. Total points: %d\n", \$lette
+r,\$pay{"\$letter"}, \$total_points;
}
}
Output:

```Enter word to calculate.

Press 'q' to quit

Word: test
Letter "T" = 1 points. Total points: 1
Letter "E" = 1 points. Total points: 2
Letter "S" = 1 points. Total points: 3
Letter "T" = 1 points. Total points: 4

Word: q
Quiting program...

-Waswas

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://403868]
Approved by FoxtrotUniform
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (2)
As of 2023-05-31 22:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found

Notices?