1

I have read in multiple places that \n does not flush the buffer when used however in my code, which I will add at the end of this question, it seems to be doing just that or at least it seems that way from the output (maybe something else is going on in the background due to how I am executing my couts?).

Expected Output:

Mining Laser 1 cycle will complete in x seconds...

Mining Laser 2 cycle will complete in x seconds...

Mining Laser 3 cycle will complete in x seconds...

Mining Laser 4 cycle will complete in x seconds...

What I Get in the CLI:

Mining Laser 1 cycle will complete in x seconds...

Mining Laser 2 cycle will complete in x seconds...

Mining Laser 3 cycle will complete in x seconds...

Mining Laser 4 cycle will complete in x seconds...

Mining Laser 1 cycle will complete in x seconds...

Mining Laser 2 cycle will complete in x seconds...

Mining Laser 3 cycle will complete in x seconds...

Mining Laser 4 cycle will complete in x seconds...

Mining Laser 1 cycle will complete in x seconds...

Mining Laser 2 cycle will complete in x seconds...

Mining Laser 3 cycle will complete in x seconds...

Mining Laser 4 cycle will complete in x seconds...

What I want the output to do is remain in place, like those in the expected output example, and just update itself every the time loop in my code executes.

Here is my code:

#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>

using namespace std; //Tacky, but good enough fo a poc D:

class mLaser
{
public:
    mLaser(int clen, float mamt, int time_left)
    {
        mlCLen = clen;
        mlMAmt = mamt;
        mCTime_left = time_left;
    }

    int getCLen()
    {
        return mlCLen;
    }

    float getMAmt()
    {
        return mlMAmt;
    }

    void setMCOld(int old)
    {
        mCTime_old = old;
    }

    void mCycle()
    {
        int mCTime_new = GetTickCount(); //Get current tick count for comparison to mCOld_time

        if (mCTime_old != ((mCTime_new + 500) / 1000)) //Do calculations to see if time has passed since mCTime_old was set
        {
            //If it has then update mCTime_old and remove one second from mCTime_left.
            mCTime_old = ((mCTime_new + 500) / 1000);
            mCTime_left -= 1000;
        }

        cur_time = mCTime_left; 
    }

    int getCTime()
    {
        return cur_time;
    }

    int getCTLeft()
    {
        return mCTime_left;
    }


private:
    int mlCLen; //Time of a complete mining cycle
    float mlMAmt; //Amoung of ore produced by one mining cycle (not used yet)
    int cur_time; //The current time remaining in the current mining cycle; will be removing this as it is just a copy of mCTime_left that I was going to use for another possiblity to make this code work
    int mCTime_left; //The current time remaining in the current mining cycle
    int mCTime_old; //The last time that mCycle was called
};

void sMCycle(mLaser& ml, int i1, thread& _thread); //Start a mining cycle thread

//Some global defines
random_device rd;
mt19937 gen(rd());

uniform_int_distribution<> laser(1, 3); //A random range for the number of mlaser entities to use
uniform_int_distribution<> cLRand(30, 90); //A random time range in seconds of mining cycle lengths
uniform_real_distribution<float> mARand(34.0f, 154.3f); //A random float range of the amount of ore produced by one mining cycle (not used yet)

int main()
{
    //Init some variables for later use
    vector<mLaser> mlasers; //Vector to hold mlaser objects
    vector<thread> mthreads; //Vector to hold threads
    vector<shared_future<int>> futr; //Vector to hold shared_futures (not used yet, might not be used if I can get the code working like this)

    int lasers; //Number of lasers to create
    int cycle_time; //Mining cycle time
    int active_miners = 0; //Number of active mining cycle threads (one for each laser)
    float mining_amount; //Amount of ore produced by one mining cycle (not used yet)

    lasers = laser(gen); //Get a random number
    active_miners = lasers; //Set this to that random number for the while loop later on

    //Create the mlaser objects and push them into the mlasers vector
    for (int i = 0; i < lasers; i++)
    {
        int clength = cLRand(gen);

        mlasers.push_back(mLaser(clength, mARand(gen), (clength * 1000)));
        
        //Also push thread obects into mthreads for each laser object
        mthreads.push_back(thread());
    }

    //Setup data for mining cycles
    for (int i = 0; i < mlasers.size(); i++)
    {
        int mCTime_start = GetTickCount(); //Get cycle start time
        mlasers.at(i).setMCOld(((mCTime_start + 500) / 1000));
    }

    //Print initial display for mining cycles
    for (int i = 0; i < mlasers.size(); i++)
    {
        cout << "Mining Laser " << i+1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds...\n";
    }

    while (active_miners > 0)
    {   
        for (int i = 0; i < mlasers.size(); i++)
        {
            //futr.push_back(async(launch::async, [mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }));
            async(launch::async, [&mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }); //Launch a thread for the current mlaser object
            //mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
        }

        //Output information from loops
        cout << " \r" << flush; //Return cursor to start of line and flush the buffer for the next info

        for (int i = 0; i < mlasers.size(); i++)
        {
            if ((mlasers.at(i).getCTLeft() != 0) //If mining cycle is not completed
            {
                cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds...\n";
            }

            else //If it is completed
            {
                cout << "Mining Laser " << i + 1 << " has completed its mining cycle!\n";
                active_miners -= 1;
            }
        }
    }

    
    /*for (int i = 0; i < mthreads.size(); i++)
    {
        mthreads.at(i).join();
    }*/


    //string temp = futr.get();
    //float out = strtof(temp.c_str(),NULL);

    //cout << out << endl;

    system("Pause");
    return 0;
}

void sMCycle(mLaser& ml, int i1,thread& _thread)
{
    //Start thread
    _thread = thread(bind(&mLaser::mCycle, ref(ml)));
    
    //Join the thread
    _thread.join();
}

Per Ben Voigt, it seems that \r cannot be used in the way I am attempting to use it. Does anyone have any other suggestions apart from Matthew's suggestion of clsing the command window each update? Maybe something in Boost or something new to c++11?

Thanks.

Community
  • 1
  • 1
Geowil
  • 624
  • 1
  • 12
  • 36
  • 1
    This has nothing to do with flushing, and everything to do with unrealistic expectations about `\r`. – Ben Voigt Jan 05 '15 at 03:43
  • 1
    (In particular, when `'\r` gets processed, you've just moved to a brand-new line, so moving back to the beginning of that line isn't doing anything useful) – Ben Voigt Jan 05 '15 at 03:47
  • @BenVoigt Ah, so \r down not work properly if there is a \n OR a endl; present within the cout? I had this working properly when there was only one printed line. Did not know that. I may have to go with Matthew's suggestion then. I will also change my Q title for better accuracy. Thanks. – Geowil Jan 05 '15 at 05:33
  • 1
    Your remaining options are mostly non-standard. Windows has the Console Functions such as `SetConsoleCursorPosition` which can be used to move to a previous line. Linux and other Unix variants may support ANSI escape sequences for cursor motion. Usually you'd use a library such as ncurses to manage this for you and give you some level of portability (I'm pretty sure there's a usable curses library for Windows too). – Ben Voigt Jan 05 '15 at 05:41
  • @BenVoigt Was just looking at nCurses a bit ago. I might take a look at it for later versions of my text-based game but I think I am going to go with Matthew's suggestion for the interm as it is fairly low cost development time wise. Thanks for the suggestions. – Geowil Jan 05 '15 at 05:47
  • Closely related: http://stackoverflow.com/q/10401724/103167 – Ben Voigt Jan 05 '15 at 05:47

1 Answers1

0

You could try clearing the console after every execution with something like system("cls"); here is a link to a post [How can I clear console

Community
  • 1
  • 1
  • this can be a comment – Pramod Yadav Jan 05 '15 at 04:51
  • I wanted to try and stay away from clsing the output if at all possible as I want this to look seamless so that it is not so jarring (text-based games so often are in situations like these). Is there anything in c++11 or Boost that is capable of achieving what I am trying to do? I will resort to clsing if I can't find anything else. – Geowil Jan 05 '15 at 05:37