We were assigned a game of hangman for our Perl class. In this Perl script, we must use an html page to get the user's name. I feel like I'm getting awfully close, but I can't quite seem to get the userName value to print after each time the user clicks a letter within the game. I would appreciate any help someone could provide!

HTML

<form action="hangman3.pl" method="post">
<h1>Welcome to Hangman!</h1>
<p>Please enter your name</p>
<input type="text" name="userName" />
<input type="submit" value="Submit" />
</form>

PERL

#!/usr/bin/perl

use CGI ':standard';
use Switch;

print header();

@unusedLetters = (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);
@usedLetters = ();
$letterChosen = param('letterChosen');
$numWrong = param('numWrong');
$wordNumber = param('wordNumber');
@usedLetters = split(' ',param('usedLetters'));

$userName = param('player');

if (!defined($letterChosen)) {
	$word = getNewWord();
	$numWrong = 0;
	@unusedLetters = (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);
	@usedLetters = ();
}
else {
    $word = getWord();
    $numWrong ++;

    push(@usedLetters, $letterChosen);
}



$numLetters = length($word);

print "The word is $word with $numLetters characters <br>";
print "The letter chosen is $letterChosen<br>";
foreach $letter (@usedLetters) {
	print "The used letters so far are '$letter' <br>";
}

print "<hr>";
print "<h1><center><a href='player.html'>Enter your name</a></center></h1><br>";
print "<br>";
print "Player's name: $userName<br>";

print "<hr>";

startOverButton();



#lab 5 stuff
printImage();

printWord();

print "<br>";

printUnusedLetters();

exit(0);
#
#Subroutines
#

sub getNewWord {
	#stub
	#We know there are 5 words in the file
	$wordNumber = int(rand(5));
	return getWord();
}

sub getWord {
	open (FILE,"wordfile.txt");

	for ($i=0; $i<$wordNumber; $i++) {
		$newWord = <FILE>;
	}

	chomp($newWord);
	
	close FILE;
	
	return $newWord;
}

sub printUnusedLetters {
	print "<table align=center>";
	print "<tr>";
	print "<form method=get>";
	foreach $letter (@unusedLetters) {
		print "<td>";
		#print
		if ( !inUsedList($letter) ) {
			print "<input type=submit name='letterChosen' value='$letter' />";
		}
		else {
			print "";
		}
		print "</td>";
		if ($letter eq 'M') {
			print "</tr>";
			print "<tr>";
		}
	}
	print "<input type=hidden name=usedLetters value='@usedLetters' />";
	print "<input type=hidden name=numWrong value='$numWrong' />";
	print "<input type=hidden name=wordNumber value='$wordNumber' />";
	print "<input type=hidden name=userName value='$userName' />";
	print "</form>";
	print "</tr>";
	print "</table>";
}

sub startOverButton {
	print "<form><input type=submit value='Start Over'></form>";
}
sub printWord {
	print "<table align=center>";
	print "<tr>";
	for ($pos = 0; $pos < $numLetters; $pos ++) {
		print "<td>";
		if ($letter = inList($pos)) {
			print " ", $letter, " ";
		}
		else {
			print "____ ";
		}
		print "</td>";
	}
	print "</tr>";
	print "</table>";
}

sub printImage {
	switch ($numWrong) {
		case 0 {
			print "<img src='hang0.gif'>";
		}	
		case 1 {
			print "<img src='hang1.gif'>";
		}
		case 2 {
			print "<img src='hang2.gif'>";
		}
		case 3 {
			print "<img src='hang3.gif'>";
		}
		case 4 {
			print "<img src='hang4.gif'>";
		}
		case 5 {
			print "<img src='hang5.gif'>";
		}
		case 6 {
			print "<img src='hang6.gif'>";
		}
		case 7 {
			print "<img src='hang10.gif'>";
			print "<br><br>You LOSE";
		}
	}
}

sub inList {
	my ($pos) = @_; #$pos equals whatever was passed
	@letters = split (//, $word);
	$letter = $letters[$pos];

	foreach $usedLetter (@usedLetters) {
		if ($letter eq $usedLetter) {
			return $letter;
		}
	}
	return 0;
}

sub inUsedList {
	my ($letter) = @_;
	
	foreach $usedLetter (@usedLetters) {
		if ($letter eq $usedLetter) {
			return $letter;
		}
	}
	return 0;
}

You are using 2 different keys in the form and the code:

<input type="text" name="userName" />
$userName = param('player');

They have to match and your problem will probably be solved.

Thanks for taking the time to look into it, but that doesn't change anything. I'm not sure how to get this to work.

So, if you change:

$userName = param('player');

to

$userName = param('userName');

It doesn't work?

Nope. You'd think it would though. I've tried so many different things, but can't quite seem to get it to work. I'm at a complete loss here...

When you submit a letter... you are using a GET request, so all of the parameters will be on the URL line. Perhaps you could post the URLs here to see what is set and how. Also, I notice you have a link to "player.html" - what is that?

I loaded your script into my apache server. When I change this line:

$userName = param('player');

to this line:

$userName = param('userName');

It works fine for me.

If I enter "mike" (my name) in your form and post it to the hangman3.pl script, I get this:

Player's name: mike

Then if I click on a letter, I get this for the URL:

hangman3.pl?letterChosen=A&usedLetters=&numWrong=0&wordNumber=2&userName=mike

Of course the "new word" thing doesn't seem to work, but the userName is set.

Does it keep that userName value after every time you click on a letter? Again, thanks for your help.

Yes, it works for me after making the change Mike suggested. It keeps the userName after I click on various letters.

Does it lose its value for you the first time you click a letter, or only after you click a specific sequence of letters?

You appear to have an elusive run-time bug that occurs only sporadically. I don't know how to fix it, but I do recommend you add use strict; near the start of your perl script. It will cause several error messages that you can fix by declaring your variables and not using bare words for letters. In the process of satisfying the requirements of the strict module you may solve your problem, or not. But your instructor would probably agree that you should use strict for any non-trivial program.

"You should use the strict pragma for any Perl script more than a few lines long, and for all CGI scripts."

This question has already been answered. Start a new discussion instead.