Ok, here's the re-written code in English as Eric suggested. I also added comments to try and explain my logic, and re-wrote variables to things that actually made sense . I added the "my" in front of variables and its not working. But if you take them off, the program runs perfectly fine, as long as only one user is playing. When two or more users play, the script mixes up words. Please go easy on the flaming, Im learning here!
Code:
<br />#ahorcado.pl (hangman)<br />#Anibal Tamacas (www.ayvevos.com)<br />#AthenaBot<br />#Nov 2004<br />if ($msg eq "hangman")<br />{<br /> &send($self, "instructions: blah blah");<br />}<br />if ($msg =~ /^hangman/) <br />{<br /> if (!exists $self->{callback})<br /> {<br /> my $hash->{$user}=undef;<br /> #counter keeps a record of wrong guesses<br /> my $hash->{$user}->{counter}=0;<br /> my $path="/path/to/wordfile.dat";<br /> my @filearray=undef;<br /> my @wordarray=undef;<br /> my $fileref=undef;<br /> my $wordref=undef;<br /> my $hash->{$user}->{file}=undef;<br /> my $hash->{$user}->{word}=undef;<br /> open (FH, $path);<br /> <br /> #put all the words from the file into an array<br /> my @filearray=<FH>;<br /> my $fileref=\@filearray;<br /> close FH;<br /> <br /> my $hash->{$user}->{file}=$fileref;<br /> my $hash->{$user}->{endflag}=0;<br /> my $hash->{$user}->{learnflag}=0;<br /> my $arraysize=@filearray;<br /> #grab a random word from the array<br /> my $randomword=int(rand ($arraysize));<br /> my $hash->{$user}->{wordtoguess}=$filearray[$randomword];<br /> <br /> #prepare word<br /> $hash->{$user}->{wordtoguess}=~s/\s//;<br /> chomp ($hash->{$user}->{wordtoguess});<br /> <br /> my $hash->{$user}->{lengthofword}=length($hash->{$user}->{wordtoguess});<br /> <br /> #hangman pictures<br /> $zangief=" |=====\n |\n |\n |\n[|] ";<br /> $bison=" |=====\n | :S\n |\n |\n[|] ";<br /> $vega=" |=====\n | :S\n | |\n |\n[|] ";<br /> $sagat=" |=====\n | :S\n | ~|\n |\n[|] ";<br /> $balrog=" |=====\n | :'(\n | ~|~\n |\n[|] ";<br /> $deejay=" |=====\n | :'(\n | ~|~\n | /\n[|] ";<br /> $honda=" |=====\n | (6)\n | ~|~\n | / \\\n[|] ";<br /><br /> #split the word in an array<br /> my @wordarray= split(//, $hash->{$user}->{wordtoguess});<br /> my $wordref=\@wordarray;<br /> my $hash->{$user}->{word}=$wordref;<br /> my @guessedlettersarray=undef;<br /> my $guessedlettersref=\@guessedlettersarray;<br /> my $hash->{$user}->{guessedletters}=$guessedlettersref;<br /> my $hash->{$user}->{stringtodisplay}=undef;<br /> <br /> #prepare for first game<br /> for ($hash->{$user}->{i}=0; $hash->{$user}->{i}<$hash->{$user}->{lengthofword}; $hash->{$user}->{i}++)<br /> {<br /> $hash->{$user}->{guessedletters}->[$hash->{$user}->{i}]="_ ";<br /> $hash->{$user}->{stringtodisplay}.="_ ";<br /> }<br /> my $hash->{$user}->{picture}=$zangief;<br /> &send ($self, "Game Starts... good luck!".$hash->{$user}->{picture}.$hash->{$user}->{stringtodisplay});<br /> $self->{callback}='hangman';<br /> return;<br /> }<br /> else<br /> {<br /> &send ($self, "There seems to be a game in process");<br /> }<br /><br />}<br /><br />else <br />{<br /> if ($msg eq "exit")<br /> {<br /> delete $self->{callback};<br /> &send ($self, "Game over. Thanks for playing");<br /> $hash=undef;<br /> return;<br /> }<br /> elsif ((length($msg))==1 && $hash->{$user}->{endflag}==0)<br /> {<br /> #if the letter is contained in the word<br /> if ($hash->{$user}->{wordtoguess}=~/$msg/)<br /> {<br /> $hash->{$user}->{stringtodisplay}=undef;<br /> #notice, here i'm even putting the counter variables ($j) for the "for loop" in the hash...<br /> #it seems weird to me, do i need this?<br /> for ($hash->{$user}->{j}=0; $hash->{$user}->{j}<$hash->{$user}->{lengthofword}; $hash->{$user}->{j}++)<br /> {<br /> <br /> if ($hash->{$user}->{word}->[$hash->{$user}->{j}] eq $msg)<br /> {<br /> #insert guessed letter in the guees letters array<br /> $hash->{$user}->{guessedletters}[$hash->{$user}->{j}]=$hash->{$user}->{word}[$hash->{$user}->{j}];<br /> #prepare the display string<br /> $hash->{$user}->{stringtodisplay}.=$hash->{$user}->{word}[$hash->{$user}->{j}];<br /> }<br /> else<br /> {<br /> $hash->{$user}->{stringtodisplay}.=$hash->{$user}->{guessedletters}[$hash->{$user}->{j}];<br /> }<br /> } <br /> <br /> }<br /> else<br /> {<br /> #wrong guess, add 1 to counter<br /> $hash->{$user}->{counter}++;<br /> }<br /> #decide what display to use based on wrong guesses (counter)<br /> if ($hash->{$user}->{counter}==0)<br /> {<br /> $hash->{$user}->{picture}=$zangief;<br /> } <br /> elsif ($hash->{$user}->{counter}==1)<br /> {<br /> $hash->{$user}->{picture}=$bison;<br /> }<br /> elsif ($hash->{$user}->{counter}==2)<br /> {<br /> $hash->{$user}->{picture}=$vega;<br /> }<br /> elsif ($hash->{$user}->{counter}==3)<br /> {<br /> $hash->{$user}->{picture}=$sagat;<br /> }<br /> elsif ($hash->{$user}->{counter}==4)<br /> {<br /> $hash->{$user}->{picture}=$balrog;<br /> }<br /> elsif ($hash->{$user}->{counter}==5)<br /> {<br /> $hash->{$user}->{picture}=$deejay;<br /> }<br /> elsif ($hash->{$user}->{counter}==6)<br /> {<br /> $hash->{$user}->{picture}=$honda;<br /> } <br /> <br /> #if the wrong guesses < 6, display and keep on playing<br /> if ($hash->{$user}->{counter} != 6)<br /> {<br /> &send ($self, $hash->{$user}->{picture}.$hash->{$user}->{stringtodisplay}); <br /> $self->{callback}='hangman';<br /> return;<br /> }<br /> #else, game over, request for a word to be learned for use in the game later on<br /> elsif ($hash->{$user}->{counter} == 6)<br /> {<br /> &send ($self, $hash->{$user}->{picture}."You lost, the answer was $wordtoguess, suerte para la proxima.");<br /> &send ($self, "Please inout a word to be learned in my vocabulary");<br /> $hash->{$user}->{endflag}=1;<br /> $self->{callback}='hangman';<br /> $hash=undef;<br /> return;<br /> <br /> }<br /> }<br /> else<br /> {<br /> #if the game is over, check the word to be learned<br /> if ($hash->{$user}->{endflag}==1)<br /> {<br /> chomp($msg);<br /> $hash->{$user}->{lengthnewword}=length($msg);<br /> #letters only, larger than 3 letters <br /> if (($msg=~m/^[a-zA-Z]+$/) && ($hash->{$user}->{lengthnewword}>3))<br /> {<br /> #check word<br /> for ($hash->{$user}->{x}=0; $hash->{$user}->{x}<$arraysize; $hash->{$user}->{x}++)<br /> {<br /> chomp $hash->{$user}->{file}[$hash->{$user}->{x}];<br /> if ($msg eq $hash->{$user}->{file}[$hash->{$user}->{x}])<br /> {<br /> #set the learn flag to true if word was already in file<br /> $hash->{$user}->{learnflag}=1;<br /> }<br /> }<br /> #if word was not in file, then learn it.<br /> if ($hash->{$user}->{learnflag} != 1)<br /> {<br /> <br /> &send ($self, "$msg will be learned");<br /> delete $self->{callback};<br /> $hash->{$user}->{endflag}=0;<br /> &send ($self, " Game over. Gracias por jugar conmigo(f)");<br /> $hugo=">>/path/to/newwordfile";<br /> open (QUOTE, $hugo);<br /> print QUOTE $msg."\n"; <br /> close QUOTE;<br /> $hash=undef;<br /> return;<br /> }<br /> else<br /> {<br /> &send ($self, "Word was already in file. Thanks anyway");<br /> delete $self->{callback};<br /> $hash->{$user}->{endflag}=0;<br /> &send ($self, "Game Over, kthnks");<br /> $hash=undef;<br /> return;<br /> }<br /> }<br /> #if word<3 or has non -alphabetical chars, then say goodbbye<br /> else<br /> {<br /> &send ($self, "Not a valid word");<br /> delete $self->{callback};<br /> $hash->{$user}->{endflag}=0;<br /> &send ($self, "Game over fool");<br /> $hash=undef;<br /> return;<br /> }<br /> }<br /> #guessed word!<br /> if ($msg eq $hash->{$user}->{wordtoguess})<br /> { <br /> &send ($self, "YOU WIN! YO GUESSED THE WORD");<br /> &send ($self, "Please input a word to be learned for future games");<br /> $hash->{$user}->{endflag}=1;<br /> $self->{callback}='hangman';<br /> $hash=undef;<br /> return;<br /> }<br /> #wrong word guessed<br /> else<br /> {<br /> &send ($self, "Nope, the word was not $msg");<br /> $self->{callback}='hangman';<br /> $hash->{$user}->{counter}++;<br /> if ($hash->{$user}->{counter}==0)<br /> {<br /> $hash->{$user}->{picture}=$zangief;<br /> }<br /> elsif ($hash->{$user}->{counter}==1)<br /> {<br /> $hash->{$user}->{picture}=$bison;<br /> }<br /> elsif ($hash->{$user}->{counter}==2)<br /> {<br /> $hash->{$user}->{picture}=$vega;<br /> }<br /> elsif ($hash->{$user}->{counter}==3)<br /> {<br /> $hash->{$user}->{picture}=$sagat;<br /> }<br /> elsif ($hash->{$user}->{counter}==4)<br /> {<br /> $hash->{$user}->{picture}=$balrog;<br /> }<br /> elsif ($hash->{$user}->{counter}==5)<br /> {<br /> $hash->{$user}->{picture}=$deejay;<br /> }<br /> elsif ($hash->{$user}->{counter}==6)<br /> {<br /> $hash->{$user}->{picture}=$honda;<br /> }<br /> if ($hash->{$user}->{counter} == 6)<br /> {<br /> &send ($self, $hash->{$user}->{picture}."You lose");<br /><br /> $hash->{$user}->{endflag}=1;<br /> $self->{callback}='hangman';<br /> $hash=undef;<br /> return;<br /> }<br /> else<br /> {<br /> &send ($self, $hash->{$user}->{picture}.$hash->{$user}->{stringtodisplay});<br /> $self->{callback}='hangman';<br /> $hash=undef;<br /> return;<br /> }<br /> <br /> }<br /> }<br /><br />}<br /><br />
Im really trying to learn new things here, so feel free to comment on anything. Thanks in advance!
This code would not work. If you notice the variable was declared inside the if statement, so it's scope is only in that if statement. Once, you close the bracket for that if statement, the variable is gone.
I hope that helped explain it to you and didn't confuse you any more. I'll take a look at your code now and see what I can fix.
You don't really need to do this, you can initialize and fill an array from a file in 3 lines:
Code:
open (FH, "./file/path/here");<br />my @filearray = <FH>;<br />close (FH);
Code:
my $hash->{$user}->{file}=undef;
While not exactly bad practice...you can easily just add your value to the hashref when youre ready, instead of initializing them as undefined first. So...when you have the value you need for $hash->{$user}->{file}, just add it to the hash like you do later in the code:
Code:
my $hash->{$user}->{file}=$fileref;
.
You don't have to always set values as undefined first. You can initialize and add values to arrays, variables, and hashrefs the moment you want to.
Code:
my @filearray=<FH>;<br /> my $fileref=\@filearray;<br /> close FH;
Refer to what I said before about opening a file and adding it's contents to an array. Why are you assigning a scalar variable as the contents if you just want something random from the array? You also have a syntax error there. Can be done as:
Code:
open (FH, "./path/to/file");<br />my @filearray = <FH>;<br />close (FH);
Code:
chomp ($hash->{$user}->{wordtoguess});<br />
If the wordtoguess is coming from an array, you can chomp the array first when you load it, then you dont have to chomp the hashref unless you needed to for some reason.
Your hangman picture variables are still all global.
Code:
my $arraysize=@filearray;<br /> #grab a random word from the array<br /> my $randomword=int(rand ($arraysize));<br /> my $hash->{$user}->{wordtoguess}=$filearray[$randomword];
This is not very well written. ..you can easily load an array and get something at random this way:
I stopped here, so someone else can have fun with the second half, happy coding. _________________ Check out Botworld! A dev resource for things bot.
Downloads, articles, news, fourm and more.
http://botworld.marzopolis.com
Hmm, are you sure about that? As far as I know, the -e operator works on files only.
As for intializing variables at the top of code blocks, alienz is right that you don't need to initialize a variable if it definitely is set later in the code. The only time you might want to initialize them is if you have conditional code that sets them later, since you don't know if the code will be called.
One other thing that is good practice no matter what language you are programming in, is to declare variables close to where you use them. Old programming style and actually some old languages require you to declare them at the top of functions, but the new style is to delcare them where they are used. This helps people who are trying to read your code, because they don't have to keep referring up many lines to see what value a variable has. In particular, you want loop variables right where you use them, like:
Code:
for( my $i=0; $i<10; $i++ ) { ... }
Not only is that more readable and safer (my making it local to the loop), but anyone looking at this code knows that $i is used only in the loop.
Hmm, are you sure about that? As far as I know, the -e operator works on files only.
Eh, I could be wrong..I was thinking about a file when I wrote that, my fault. _________________ Check out Botworld! A dev resource for things bot.
Downloads, articles, news, fourm and more.
http://botworld.marzopolis.com
Joined: 22 Feb 2004 Posts: 121 Location: Richmond, VA
Posted: Mon Nov 29, 2004 8:36 am Post subject:
Well this code needs a lot of work. I've worked on it for a few minutes and at least got it formatted nicely! I'll spend a little moretime on it tomorrow and hopefully have it fixed up some more.
Well this code needs a lot of work. I've worked on it for a few minutes and at least got it formatted nicely! I'll spend a little moretime on it tomorrow and hopefully have it fixed up some more.
so pretty....
thanks for the reply guys... This is the best way to learn I guess... from people that actually know what theyre doing!
Joined: 22 Feb 2004 Posts: 121 Location: Richmond, VA
Posted: Mon Nov 29, 2004 8:06 pm Post subject:
I think this will work. I couldn't get morphius bot to work right so i couldn't test it... let me know if it does and exactly what errors it has.
Code:
#ahorcado.pl (hangman)<br />#Anibal Tamacas (www.ayvevos.com)<br />#AthenaBot<br />#Nov 2004<br />#fixed by thomashp<br />my $pictures = \( " |=====\n |\n |\n |\n[|] ",<br /> " |=====\n | :S\n |\n |\n[|] ",<br /> " |=====\n | :S\n | |\n |\n[|] ",<br /> " |=====\n | :S\n | ~|\n |\n[|] ",<br /> " |=====\n | :'(\n | ~|~\n |\n[|] ",<br /> " |=====\n | :'(\n | ~|~\n | /\n[|] ",<br /> " |=====\n | (6)\n | ~|~\n | / \\\n[|] "<br /> );<br /><br />#someone starting a game...<br />if ($msg eq "hangman") #being sensitive<br />{<br /> if (!exists $self->{callback})<br /> {<br /> #send them some intructions when they start<br /> &send($self, "Instructions: Guess letters to the secret word. When you think you know it, guess the whole word. All guesses count against you.");<br /> <br /> #basic place where we will store data<br /> $self->{hangman} = undef;<br /> $self->{hangman}->{$username} = $username;<br /> <br /> #counter keeps a record of wrong guesses<br /> $self->{hangman}->{counter} = 0;<br /> <br /> #open file, get words, close file, get a random word, clean it up<br /> open (FH, "/path/to/wordfile.dat");<br /> my @filearray = <FH>;<br /> close(FH);<br /> $self->{hangman}->{word} = $filearray[int(rand(scalar(@filearray)))];<br /> $self->{hangman}->{word} =~ s/\s//g;<br /> chomp ($self->{hangman}->{word});<br /> <br /> #set some variables for something...<br /> $self->{hangman}->{endflag} = 0;<br /> #$self->{hangman}->{learnflag} = 0; got rid of this, didn't need it<br /> <br /> #split the word in an array<br /> $self->{hangman}->{wordarray} = \split(//, $self->{hangman}->{word});<br /> $self->{hangman}->{guessedletters} = \();<br /> <br /> my $stringtodisplay;<br /> #the wonderful foreach loop!<br /> foreach my $i (0..$#{$self->{hangman}->{wordarray}})<br /> {<br /> $self->{hangman}->{guessedletters}->[$i] = "_ ";<br /> $stringtodisplay .= "_ ";<br /> }<br /> &send ($self, "Game Starts... good luck!".$pictures->[$self->{hangman}->{counter}].$stringtodisplay);<br /> $self->{callback}='hangman';<br /> return;<br /> }<br /> else<br /> {<br /> &send ($self, "There seems to be a game in process.\nType 'exit' to stop the game or guess some letters.");<br /> }<br />}<br />#the game should already being played<br />elsif ($self->{callback} eq 'hangman' && $self->{hangman}->{$username} eq $username)<br />{<br /> #if they want to leave the game, then leave the game<br /> if ($msg =~ /^exit$/i) #jsut to give it some case insensitivity, we all need to be sensitive to users needs<br /> {<br /> &send ($self, "Game over. Thanks for playing");<br /> #$hash = undef; <--this line was here, this would have reset all games being played.<br /> delete $self->{hangman};<br /> delete $self->{callback};<br /> return;<br /> }<br /> #if the game isn't over<br /> elsif ($self->{hangman}->{endflag} != 0)<br /> {<br /> #if they guessed a letter<br /> if ($msg =~ /^{a-zA-Z]$/i)<br /> {<br /> #if the letter is contained in the word<br /> if ($self->{hangman}->{word} =~ /$msg/i) #you must be sensitive!<br /> {<br /> #notice, here i'm even putting the counter variables ($j) for the "for loop" in the hash...<br /> #it seems weird to me, do i need this?<br /> #no, you don't<br /> #and use foreach<br /> foreach my $j (0..$#{$self->{hangman}->{wordarray}})<br /> {<br /> #if this is the letter they guessed<br /> if ($self->{hangman}->{wordarray}->[$j] =~ /$msg/i)<br /> {<br /> &send ($self, "You guessed $msg correctly!");<br /> #insert guessed letter in the guessed letters array<br /> $self->{hangman}->{guessedletters}[$j] = $self->{hangman}->{wordarray}[$j];<br /> }<br /> }<br /> }<br /> else<br /> {<br /> &send ($self, "$msg is not in the secret word.");<br /> #wrong guess, add 1 to counter<br /> $self->{hangman}->{counter}++;<br /> }<br /> }<br /> #they must be taking a stab at the whole word<br /> else<br /> {<br /> if ($self->{hangman}->{word} =~ /^$msg$/i) #being sensative, again<br /> {<br /> &send ($self, "YOU WIN! YOU GUESSED THE WORD\nPlease input a word to be learned for future games");<br /> $self->{hangman}->{endflag} = 1;<br /> #$hash=undef; there it is again... you only want to kill it for that user not all users. and you're killing the endflag you jsut set 2 lines up<br /> }<br /> #wrong word guessed<br /> else<br /> {<br /> &send ($self, "Nope, the word was not $msg.");<br /> #wrong guess, add 1 to counter<br /> $self->{hangman}->{counter}++;<br /> }<br /> }<br /> #decide what display to use based on wrong guesses (counter)<br /> my $picture = $pictures->[$self->{hangman}->{counter}];<br /> <br /> #the string of guessed and not guessed letters<br /> my $stringtodisplay;<br /> $stringtodisplay .= $_ foreach (@{$self->{hangman}->{guessedletters}});<br /> <br /> #if the wrong guesses < 6, display and keep on playing<br /> if ($self->{hangman}->{counter} < 6)<br /> {<br /> &send ($self, $picture.$stringtodisplay);<br /> $self->{callback} = 'hangman';<br /> return;<br /> }<br /> #else, game over, request for a word to be learned for use in the game later on<br /> else<br /> {<br /> &send ($self, $picture."You lost!\nThe answer was: ".$self->{hangman}->{word}.", suerte para la proxima.");<br /> &send ($self, "Please inout a word to be learned in my vocabulary.");<br /> $self->{hangman}->{endflag}=1;<br /> $self->{callback}='hangman';<br /> #$hash=undef; AHAHAHSHAHSHAHASHASAHhhh<br /> return;<br /> }<br /> }<br /> #game is over, they should be giving us a new word to learn<br /> else<br /> {<br /> #letters only, larger than 3 letters<br /> if ($msg =~ /^[a-zA-Z][a-zA-Z][a-zA-Z]+$/i )<br /> {<br /> #notice how i'm opening the file again to get the words, someone could have been playing and added new words since we last looked at the file, it's best to jsut read it again, i guess.<br /> open (FH, "/path/to/wordfile.dat");<br /> my @filearray = <FH>;<br /> close(FH);<br /> #check word<br /> my $doiknowit = 0; #<-learnflag<br /> foreach my $word (@filearray)<br /> {<br /> chomp $word;<br /> $word =~ s/\s//g;<br /> if ($word =~ /^$msg$/i)<br /> {<br /> #set the learn flag to true if word was already in file<br /> $doiknowit = 1;<br /> }<br /> }<br /> #if word was not in file, then learn it.<br /> if ($doiknowit != 1)<br /> {<br /> &send ($self, "$msg will be learned.\nGame over. Gracias por jugar conmigo(f)");<br /> open (QUOTE, ">>/path/to/newwordfile");<br /> print QUOTE $msg."\n";<br /> close QUOTE;<br /> #$hash=undef; wow, this code could never have worked like it was at least not for more than one user<br /> }<br /> else<br /> {<br /> &send ($self, "Word was already in file. Thanks anyway");<br /> $self->{hangman}->{endflag}=0;<br /> &send ($self, "Game Over, kthnks");<br /> #$hash=undef; what is this like #6 worse things you could do to your game<br /> }<br /> }<br /> #if word < 3 or has non -alphabetical chars, then say goodbbye<br /> else<br /> {<br /> &send ($self, "Not a valid word.\nGame over fool!");#it's always great to mock your users<br /> #$hash=undef; again this line woudl stop all games<br /> }<br /> delete $self->{callback};<br /> delete $self->{hangman};<br /> return;<br /> }<br />}<br />1;
mmm.... It just prompts you with the instructions and then stops. I'm reading the code trying to find where the error is.... It took me a while to get morphius to work correctly, but changing MSN.pm 2 was fairly easy.