Program’s Aim:
The program is a hangman game which get a list of planets from our solar system, saves it to an array then randomly selects one word from the array and subsequently prints two letters of the word on the board. The program runs perfectly in a windows environment, but fails in runtime on linux.
Problem:
The program replaces the first character in the output stream with the last character of that stream. That happens when printing the word on the board and also when the word is displayed when it is correctly or wrongly guessed.
e.g.: word = Mars
For 6 wrong guess it’s supposed to print, Too bad you didn’t guess right. It was “mars”.
Instead, it prints: “oo bad you didn’t guess right. It was “mars
Here are the files:
wordlist.yx:
Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
Hangman.h:
#pragma once #include <iostream> using namespace std; // Check for OS #ifdef _WIN32 #define SYS "MS" #else #define SYS "LINUX" #endif class Hangman { private: int version = 3; string release_date = "01/05/2016"; int &v = version; string &r = release_date; static const int WORDLIST_SIZE = 10; string wordlist[WORDLIST_SIZE]; string word, hidden_word, wordfile = {"wordlist.yx"}; int word_length, tries_left; bool is_match; public: Hangman(); ~Hangman(); //attributes string user_input, arch; char choice; // Game functionality methods void printMenu(Hangman &); void info(Hangman &) const; void startGame(Hangman &); void reset(); void getWordlist(); void getWordAndSetHidden(); int getTries(); void printHangman(int); void printBoard(); void getInput(Hangman &); int validateInput(char); void decideFate(Hangman &); void decision(Hangman &); // Invalid input and screen clearing methods void invalidInput1(Hangman &, char &); void invalidInput2(Hangman &, string &); void cls() const; };
Hangman.cpp:
#include <iostream> #include <cstdlib> #include <ctime> #include <fstream> #include <limits> #include <algorithm> #include <string> #include "Hangman.h" using namespace std; //Constructor Hangman::Hangman(){ //Get's OS // Microsoft if(SYS == "MS"){ arch = "cls"; } else{ //linux, unix, OSX arch = "clear"; } hidden_word = ""; tries_left = 6; } // De-constructor Hangman::~Hangman(){ //Destroy objects } // Menu Options void Hangman::printMenu(Hangman &s){ cls(); cout << " _____Hangman (v7)_____ " << endl; cout << "| |" << endl; cout << "| Play - P |" << endl; cout << "| Info - I |" << endl; cout << "| Quit - Q |" << endl; cout << "------------------------" << endl; cout << "Choice: "; getline(cin, user_input); // Pass first character of string to char choice = user_input[0]; switch(choice){ case 'p': case 'P': startGame(s); break; case 'i': case 'I': info(s); break; case 'q': case 'Q': cls(); cout << "Thank you for playing..." << endl; exit(EXIT_SUCCESS); break; default: invalidInput1(s, choice); } } void Hangman::info(Hangman &m) const{ string ic; cls(); cout << "+--------------------------------------------------------------------+n" << "| Hangman Instructions |n" << "+--------------------------------------------------------------------+n" << "| This Hangman game is played by entering a guessed letter at a time.|n" << "| 6 wrong guesses are given by default and decrements by 1 (one) on |n" << "| each wrong guess. |n" << "+--------------------------------------------------------------------+n" << "| In-game options |n" << "+--------------------------------------------------------------------+n" << "| restart - Start a new game |n" << "| menu - Display main menu |n" << "| quit - Exit game |n" << "+--------------------------------------------------------------------+n" << "| Game Information |n" << "+--------------------------------------------------------------------+n" << "| Version: " << v << " |n" << "| Date: " <<r<< " |n" << "+--------------------------------------------------------------------+n" << "| Author |n" << "+--------------------------------------------------------------------+n" << "| Philan James (Zoutiyx) |n" << "| zoutiyx@gmail.com |n" << "+--------------------------------------------------------------------+nn"; cout << "Press enter to close... "; getline(cin, ic); m.printMenu(m); } void Hangman::startGame(Hangman &h){ cls(); h.reset(); h.getWordlist(); h.getWordAndSetHidden(); h.decideFate(h); do { h.printHangman(h.getTries()); h.printBoard(); h.getInput(h); h.decideFate(h); } while(h.getTries() != 0); } //Gets the wordlist from a file and stores it into an array void Hangman::getWordlist(){ fstream in_words(wordfile, ios::in); if(!in_words.is_open()){ cerr << "Error 0: " << wordfile << " isn't found in current directory!n"; } else{ for(int i = 0; (i < WORDLIST_SIZE - 1) && !in_words.eof(); i++){ getline(in_words, *(wordlist + i), 'n'); } } in_words.close(); } void Hangman::getWordAndSetHidden(){ srand(time(NULL)); int word_index, p1, p2; word_index = rand() % (WORDLIST_SIZE - 1) + 0; word = wordlist[word_index]; // Sets the hidden word letters to underscores for(unsigned int i = 0; i < word.length(); i++){ if(word[i] == ' ') { hidden_word.push_back(' '); } else { hidden_word.push_back('_'); } } //selecting the random two indexes of the word p1 = rand() % word.length(); p2 = rand() % word.length(); while (p1 == p2 || p2 == p1){ p1 = rand() % word.length(); p2 = rand() % word.length(); } // Assigning the letter to the corresponding index for(int i = 0; i < (int)word.length(); i++){ if (i == p1){ hidden_word[i] = word[i]; } else if( i == p2){ hidden_word[i] = word[i]; } // If a certain letter is the same as the on at the p1 or p2, // It is also printed on the board, making it more than (2) default letters if (tolower(word[p1]) == tolower(word[i])){ hidden_word[i] = word[i]; } if (tolower(word[p2]) == tolower(word[i])){ hidden_word[i] = word[i]; } } } // Get lives remaining int Hangman::getTries(){ return tries_left; } // Print's hangman state based on lives left void Hangman::printHangman(int ll){ cls(); cout << "Planets in our solor system...nn"; cout << "Tries left: " << tries_left << endl; switch (ll){ case 6: cout << " |----| " << endl; cout << " | " << endl; cout << " | " << endl; cout << " | " << endl; cout << " | " << endl; cout << "____|____ " << endl; cout << endl; break; case 5: cout << " |----| " << endl; cout << " | 0 " << endl; cout << " | " << endl; cout << " | " << endl; cout << " | " << endl; cout << "____|____ " << endl; cout << endl; break; case 4: cout << " |----| " << endl; cout << " | 0 " << endl; cout << " | | " << endl; cout << " | | " << endl; cout << " | " << endl; cout << "____|____ " << endl; cout << endl; break; case 3: cout << " |----| " << endl; cout << " | 0 " << endl; cout << " | /| " << endl; cout << " | | " << endl; cout << " | " << endl; cout << "____|____ " << endl; cout << endl; break; case 2: cout << " |----| " << endl; cout << " | 0 " << endl; cout << " | /|\ " << endl; cout << " | | " << endl; cout << " | " << endl; cout << "____|____ " << endl; cout << endl; break; case 1: cout << " |----| " << endl; cout << " | 0 " << endl; cout << " | /|\ " << endl; cout << " | | " << endl; cout << " | / " << endl; cout << "____|____ " << endl; cout << endl; break; case 0: cout << " |----| " << endl; cout << " | 0 " << endl; cout << " | /|\ " << endl; cout << " | | " << endl; cout << " | / \ " << endl; cout << "____|____ " << endl; cout << endl; break; } } // Display hidden word void Hangman::printBoard(){ for(unsigned int i = 0; i < hidden_word.length(); i++){ if(word[i] == ' '){ cout << word[i]; } else if(i != hidden_word.length()){ cout << hidden_word[i] << " "; } else{ cout << hidden_word[i]; } } cout << endl << endl; } // Get letter choice and assign position 0 to character void Hangman::getInput(Hangman &c){ cout << "Letter choice: "; getline(cin, user_input); transform(user_input.begin(), user_input.end(), user_input.begin(), ::tolower); if(user_input == "restart"){ c.reset(); c.startGame(c); } else if(user_input == "menu"){ printMenu(c); } else if(user_input == "quit"){ cout << "nThank you for playing...n"; exit(EXIT_SUCCESS); } else{ choice = user_input[0]; user_input = ""; validateInput(choice); } } // test character for validity int Hangman::validateInput(char choice){ for(unsigned int i = 0; i < hidden_word.length(); i++){ //Checks if entered character is already on the board if(toupper(choice) == hidden_word[i] || tolower(choice) == hidden_word[i]){ --tries_left; return 0; } // Checks if character is a valid input if(toupper(choice) == word[i] || tolower(choice) == word[i]){ hidden_word[i] = word[i]; is_match = true; } // If end of loop and character is invalid, lives left -=1 if(i == hidden_word.length() -1 && is_match != true){ --tries_left; return 0; } } is_match = false; return 0; } // Checks if the word was found or not void Hangman::decideFate(Hangman &f){ if(hidden_word == word){ cls(); cout << "Congrats, "" << word << "" it is.nn"; f.decision(f); } if(tries_left == 0 && hidden_word != word){ cin.ignore(); f.printHangman(f.getTries()); cout << "Too bad you didn't guess right. It was "" << word << """ << endl << endl; f.decision(f); } } void Hangman::decision(Hangman &c) { cout << "+----------------------+" << endl; cout << "| Alternatives |" << endl; cout << "+----------------------+" << endl; cout << ""restart" or a new gamen" << ""help" for help informationn" << ""quit" to exitnnChoice: "; getline(cin, user_input); transform(user_input.begin(), user_input.end(), user_input.begin(), ::tolower); if(user_input == "restart"){ c.startGame(c); } else if(user_input == "help"){ info(c); } else if(user_input == "quit"){ cls(); cout << "Thank you for playing..." << endl; exit(EXIT_SUCCESS); } else{ invalidInput2(c,user_input); } } void Hangman::invalidInput1(Hangman &i1, char &i){ //cin.clear(); cerr << "' " << i << " ' is not a valid input." << " Press <Enter> to try again."; getline(cin, user_input); Hangman::printMenu(i1); } void Hangman::invalidInput2(Hangman &i2, string &i){ //cin.clear(); cerr << "" " << i << " " is not a valid input." << " Press <Enter> to try again."; getline(cin, user_input); cls(); Hangman::decision(i2); } // Reset game void Hangman::reset(){ tries_left = 6; hidden_word = ""; } // Calls clear screen command void Hangman::cls() const{ // passes cls or clear string as character pointer system(arch.c_str()); }
main.cpp:
#include "Hangman.h" int main() { Hangman hangman; hangman.printMenu(hangman); }
Tried:
- Running the program in a lower standard (11) from 14.
- Online compiler from tutorialspoint.
- Manually setting the word.
Observation:
I observed that if I manually set the word, that situation is resolved. How do I narrow in on this issue further?
Edit:
Added wordlist and removed a stray backslash which prevented compiling..
Advertisement
Answer
Try running dos2unix on your wordlist.yx file. If it was created on Windows, the newlines are probably rn, not just n. And if that r is interpreted literally, that will return to the beginning of the line prior to continuing to output to cout, thus overwriting your first character.
Reference to dos2unix can be found here.
To avoid using dos2unix, you could strip the r characters from your wordlist array. One approach would be to loop through each word in the array and processing them like so:
currWord.erase( std::remove(currWord.begin(), currWord.end(), 'r'), currWord.end() );