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() );