Program: Rolling display of character snowstorms



STOP PRESS! The full book is now available DIRECTLY from Amazon with lower shipping costs!

This is a variation of the previous snowstorm program.


It displays several rolling snowstorms. Each snowstorm plots a certain number of character symbols, choosing their colour and font-weight (bold or normal) at random.








The main work is performed by the snow function. When called, this is passed a string value that contains the set of possible characters that are available to choose from.


Another function, wipeout, is called to clear the screen. This is simply a call to the snow function, telling it to display spaces at random positions on the screen.


The calls to activate the snow and wipeout functions can be found within an infinite while loop in the main function.


Compile as usual, either from the command line or from within Geany. Full details in the book.


The deluxe version that I use at work has an additional function that can be called display the contents of various text/ASCII art files, producing a retro teletype effect, one character at a time. Watch this space.


Meanwhile, let it snow...



// To compile on Raspberry Pi or in Ubuntu...
// g++ -o rolling rolling.cpp
// This compiles the rolling.cpp source file ans SHOULD make an executable called rolling


// Run with...
// ./rolling

// Phil Gardner - "Learn to Program Using C++ on the Raspberry Pi"


#include <cstdlib>     // Using random numbers - random function
#include <iostream>    // To use the screen output - cout "channel out"
#include <unistd.h>    // To slow things down by parts of a second - usleep function
#include <sstream>     // To convert numbers to character strings when telling the screen where to put the cursor

using namespace std;  // Want to use short abbreviations... cout rather than std::cout

// -------------------------------

// These constants are special "escape characters" that tell your terminal to change colour or switch bold on/off

const string BOLD = "\e[1m";
const string NORM = "\e[0m";
const string RED = "\e[31m";
const string GREEN = "\e[32m";
const string BLUE = "\e[34m";
const string YELLOW = "\e[38;5;226m";


// -------------------------------

void positionCursor( int screenRow, int screenColumn )
{

    // This function sends the cursor to a particular row and column in your terminal window
    // ready to display something at that position.

    string columnString, rowString;

    // Convert the column number to a character string - uses a new stringstream each time, don't need to reset it after use...
    stringstream columnConverter;
    columnConverter << screenColumn;
    columnConverter >> columnString;


    // Convert the row number to a character string
    stringstream rowConverter;
    rowConverter << screenRow;
    rowConverter >> rowString;


    // Put the strings together to make an "escape sequence" that tells screen where to position the cursor
    cout << "\e[" + rowString + ";" + columnString + "H";
}


// -------------------------------

// This function can be called again and again by the main program
// It displays a certain number of symbols in different colours,
// waiting for a split second after displaying each symbol.


void snow( int numToDisplay, string symbols, string ink1, string ink2, int pauseLength )
{
    // Keep count of symbols displayed so far, used to determine whether to display 1 or 0
    int numSoFar = 0;


    // Infinite loop - do this code again and again forever...
    int column, row;  // Loop will repeatedly use these variables
    while ( numSoFar < numToDisplay )
    {
        // Pick a random column number on the screen - standard terminal size is 80 columns
        column = random() % 80;


        // Pick a random row number - standard terminal size is 25 rows
        row = random() % 25;

        positionCursor( row, column );

        // Decide what colour and weight to use when displaying the symbol
        switch ( numSoFar % 4 )
        {
            case 0: cout << NORM << ink1; break;
            case 1: cout << NORM << ink2; break;
            case 2: cout << BOLD << ink1; break;
            case 3: cout << BOLD << ink2; break;
        }
  // End of switch decision


        // Display symbol at the current screen position
        cout << symbols.at( numSoFar  % symbols.length() );


        // Tell the screen to update immediately - don't wait until have a finished line of text
        cout << flush;


        // Delay for part of a second
        usleep( pauseLength );


        // Update counter that records how many symbols have been displayed
        numSoFar++;


    }  // End of infinite while loop section

}

// --------------------------------------------------------

// This function gradually clears the screen by displaying spaces at random locations.
// It activtes (calls) the "snow" function above, telling it to display spaces instead of visible symbols


void wipeout( int pauseLength )
{
    snow( 15000, " ", NORM, NORM, pauseLength );
}


// --------------------------------------------------------

// Program begins execution here...


int main()
{

    // Infinite loop, displays same snowstorms forever
    while ( true )
    {

        // Clear screen with randomly positioned spaces
        wipeout(3);


        // Fill screen with red and yellow + symbols
        snow( 5000, "++", YELLOW, RED, 20 );
        wipeout(3);


        // Fill screen with binary using yellow and red
        snow( 10000, "01", YELLOW, RED, 20 );
        wipeout(3);


        // Say hello, then clear screen
        positionCursor( 13, 36 );
        cout << YELLOW << "H E L L O !" << NORM << endl;
        sleep(3);


        // Fill screen with hexadecimal digits
        snow( 5000, "0123456789ABCDEF", BLUE, GREEN, 20 );


    }  // End of while loop

    return 0;

}  // End of main function


Find out more - buy the book on Amazon...


Further details in Chapter 4: Keyboard input and screen output