Skip to content
Advertisement

The first character in the output stream is replaced with the last character of that stream which is removed. Why is that so?

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:

  1. Running the program in a lower standard (11) from 14.
  2. Online compiler from tutorialspoint.
  3. 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() );
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement