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

Dear PelrMonks, All of your answers have been really helful. Your time is much appreciated. I think that my code now is better but still not accurate. My array is succesfully printed into a text file. I want my array though to be printed vertically (each line of the file to contain only one word of the array) and that's why I used the "$_\n". Now though, I am facing another problem. Each word needs one extra letter in the end. I used the chomp(); but maybe not correct. Any ideas? I created now this:
#!/usr/bin/perl -w @words = qw( internet answers printer program ); @guesses=(); $wrong=0; $line=0; my @words = qw( internet answers printer program ); open my $fh, '>', "words.txt" or die "Cannot open words.txt: $!"; foreach (@words) { print $fh "$_\n"; #Because I want each word in a separate line +. chomp($fh); #maybe something wrong with chomp();? } close $fh; srand; open MYFILE, "<words.txt" or die "Could not open words.txt: $!\n"; rand($.)<1 and ($line=$_) while <MYFILE>; close MYFILE; $choice=$line; $hangman="0-|--<"; @letters=split(//, $choice); @hangman=split(//, $hangman); @blankword=(0) x scalar(@letters); OUTER: while ($wrong<@hangman) { foreach $i (0..$#letters) { if ($blankword [$i]) { print $blankword [$i]; } else { print "-"; } } print "\n"; if ($wrong) { print @hangman[0..$wrong-1] } print "\n Your Guess: "; $guess=<STDIN>; chomp $guess; foreach(@guesses) { next OUTER if ($ _ eq $guess); } $guesses[@guesses]=$guess; $right=0; for ($i=0; $i<@letters; $i++) { if ($letters[$i] eq $guess) { $blankword[$i]=$guess; $right=1; } } $wrong++ if (not $right); if (join('', @blankword) eq $choice) { print "You got it right!\n"; exit; } } print "$hangman\nSorry, the word was $choice.\n";

Replies are listed 'Best First'.
Re: hangman game
by marto (Cardinal) on May 18, 2015 at 11:51 UTC
Re: hangman game
by Athanasius (Archbishop) on May 18, 2015 at 12:59 UTC

    Hello mbgbioinfo,

    There is another problem with the code shown — in this snippet:

    open(MYFILE, "<words") or die "Opening words: $!"; print MYFILE @words; close(MYFILE);

    the file “words” is opened for reading, but you attempt to write to it.

    BTW, there is no need to close the filehandle and then re-open it. Open it once, for reading and writing, write to it, then reposition the filehandle to the beginning of the file before reading:

    my $filename = 'words'; open(my $myfile, '+>', $filename) or die "Cannot open file '$filename' for writing and reading: $!"; print $myfile @words; seek($myfile, 0, SEEK_SET); srand; rand($.) < 1 and $line = $_ while <$myfile>; close $myfile or die "Cannot close file '$filename': $!";

    Notes:

    • Prefer the 3-argument form of open.
    • Prefer a lexical filehandle (my $myfile) to a global (MYFILE).
    • It is more common to open a file for reading and writing using the mode +<, but in this case, if the file is not already empty, you want to clobber (erase) its contents before writing to it; hence the mode +>.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Dear Athanasius, Thank you for your time. When I put in my code your solution it writes this "Argument "SEEK_SET" isn't numeric in seek at testh line 13.". Furthermore, it is using all the words of the list @words as one. Instead of what you said, I put this, but I cannot remove the /n character. In the output, is is always asking for one extra character in the end of each word.
      my @words = qw( internet answers printer program ); open my $fh, '>', "words.txt" or die "Cannot open words.txt: $!"; foreach (@words) { print $fh "$_\n"; chomp; } close $fh; srand; open MYFILE, "<words.txt" or die "Could not open words.txt: $!\n"; rand($.)<1 and ($line=$_) while <MYFILE>; close MYFILE;

        Hello mbgbioinfo,

        It’s a pity you haven’t followed Marto’s advice to use strict and to properly indent your code. You are making it much harder on yourself by not doing so. :-(

        To use SEEK_SET, you need to add use Fcntl ':seek'; at the top of your script. See seek and Fcntl. Now to the main issue:

        foreach (@words) { print $fh "$_\n"; chomp; }

        There is no point in adding chomp here, it accomplishes nothing. It is the variable $choice which has a terminal newline that needs to be removed:

        my $choice = $line; chomp $choice;

        I notice also that the following logic is wrong:

        for ($i=0; $i<@letters; $i++) { if ($letters[$i] eq $guess) { $blankword[$i]=$guess; $right=1; } }

        $letters[$i] is a single character, but $guess is a string of characters. You need to compare each letter of $choice with the corresponding letter in $guess. (And when you re-write that loop, be careful to ensure that $i never exceeds the index of the last letter in the shorter of the two strings.)

        P.S. Whenever you update a post (in this case, your OP), please leave the original intact and clearly mark additions as updates, so that monks coming to this thread in the future will be able to make sense of the replies.

        Hope that helps,

        Update: Re-wrote the P.S. to make it clear that when updates are added, the original should not be removed.

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: hangman game
by GotToBTru (Prior) on May 18, 2015 at 13:19 UTC

    It helps to use an editor that highlights opening and closing parentheses, brackets, braces, etc., and show the scope of blocks. This kind of error can be prevented, or easily found and fixed. I use Notepad++ on Windows because it has many features and is free; there are many other options.

    Dum Spiro Spero
Re: hangman game
by ww (Archbishop) on May 18, 2015 at 16:22 UTC

    Generally, posting the minimal snippet that illustrates your problem or question is a good idea but when you're planning to cite Line numbers, best to mark those lines with a comment -- to make it easy for the Monks to ascertain the source of the error without having to re-invent your wheel.

Re: hangman game
by laosland (Initiate) on May 18, 2015 at 14:39 UTC
    Seems a semicolon is missing at:  print join( "\n", @hangman[0..$wrong-1] )
      It is optional (but recommended). From Simple Statements:
      Every simple statement must be terminated with a semicolon, unless it is the final statement in a block, in which case the semicolon is optional. But put the semicolon in anyway if the block takes up more than one line, because you may eventually add another line.
        I sit corrected. I'm relatively new to Perl myself, but like to keep from using some of the shortcuts for readability. Most of my previous experience is with C, C++, COBOL, and a few others...
        I'm trying to remember the other language where the final semicolon is wrong. Drove me nuts. (Or was this a really old version of Perl? I can't remember.)

        Reminds me of the Comma Operator, which in hindsight seems like a mistake. I've never understood why it's needed, when a semicolon will do. Perhaps someone can point up an example where it's helpful?

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: hangman game
by vinoth.ree (Monsignor) on May 18, 2015 at 13:30 UTC

    Hangman


    All is well. I learn by answering your questions...