Skip to content

Instantly share code, notes, and snippets.

@SibTiger
Created April 5, 2018 03:12
Show Gist options
  • Save SibTiger/ee178f4399ede48f3d49906588c29832 to your computer and use it in GitHub Desktop.
Save SibTiger/ee178f4399ede48f3d49906588c29832 to your computer and use it in GitHub Desktop.
This program is designed to simulate the Locker Door Problem by 'n' passes. This program will output what locker doors are open after 'n' passes.
// =====================================================
// Programmer: Nicholas Gautier
// Class: CS3713; Algorithm Analysis
// Assignment #: 1
// Due Date: 18. February. 2018
// Instructor: Mr. Moinian, Feridoon
// Description: This program is designed to perform the Locker Door Simulator.
// In which, this program will simulate how many doors are open
// and how many are closed by performing how many 'n' passes toggled
// the locker doors.
// For example:
// | PASSES | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
// | 1 | O | O | O | O | O | O | O |
// | 2 | O | X | O | X | O | X | O |
// | 3 | O | X | X | X | O | O | O |
// | 4 | O | X | X | O | O | O | O |
// | 5 | O | X | X | O | X | O | O |
// | 6 | O | X | X | O | X | X | O |
// | 7 | O | X | X | O | X | X | X |
// Number of lockers is: 7
// Number of doors opened: 2
// Number of doors closed: 5
// Locker Doors that are open: 1, 4
//
// NOTE: I am using Visual Studio 2017.
// ----
// COMPILING NOTES FOR G++
// You will reach an error "error: ‘to_string’ is not a member of ‘std’"
// To combat this error, just use this command-line argument:
// $ g++ -std=c++11 ./main.cpp
// Source: https://stackoverflow.com/questions/19122574/to-string-isnt-a-member-of-std/19122592
// ----
// Return Codes:
// 0 = Successful Operation
// !0 = See Operating System Documentation
// =====================================================
#pragma region Inclusions
#include <iostream> // For input and output
#include <string> // Allow the usage for string data type and for I/O stream.
#include <iomanip> // Required for the 'setw()' and 'setfill' in cout function
#pragma endregion
#pragma region Function Prototypes
void ResetLockers(bool[], int); // Resets the locker array to zero.
int FetchLockerSize(); // Fetch locker array size from user (that is requested).
void LockerDoorSimulation(bool[], int); // Locker Door Simulation Algorithm
int CountOpenDoors(bool[], int); // Count how many locker doors are open
void DisplayResults(int, int, // Display the results to the user
std::string);
void DrawHeader(); // Display the program information header.
void DrawInstructions(); // This will display instructions to the user.
void DrawAbout(); // Display what this program is about.
bool AskRunProgramAgain(); // Ask the user to close the program or run another task.
void BorderSeparator(); // Display border for readability
std::string ArrayIndexesResults(bool[], // This will provide information as to what array
int); // indexes contain open doors.
void ArrayIndexesVisualResults(bool[], // Display the results visually to the end-user
int);
#pragma endregion
#pragma region Macros
#define _NAME_ "Ghosts are Opening Our Lockers!"// Program name
#define _VERSION_ "1.0" // Program Version
#define _VERSION_NAME_ "Hathor" // Version Name
#define _ARRAY_MAX_SIZE_ 1000 // Maximum Array (locker) Size
// This was defined in the Requirements
#define _ARRAY_MIN_SIZE_ 2 // Minimum Array (locker) Size [default is 10]
#define _STDIN_PROMPT_ ">>>>>> " // Prompt message; Python'ish prompt
#define _DEBUG_STATE_ false // When true, this will provide extra messages during
// the Locker Door Simulation algorithm.
#pragma endregion
// Main
// ------------------------------------
// Main program entry.
int main()
{
// Declarations and Initializations
// --------------------------------
bool lockerArray[_ARRAY_MAX_SIZE_+ 1];// Lockers in Array form
// GROSS-HACK; the code will NOT play nicely if the array
// size is not EXACTLY the max number. This is merely a
// limitation of the code I have provided and how the
// algorithm functions.
bool userChoice = true; // Run the program again-loop
int lockerRequestSize = 0; // User-Provided Size of Locker Array
int openDoors = 0; // How many locker doors are open
std::string lockerDoorOpenResults; // This will hold 'nice' results regarding
// which doors are open.
// --------------------------------
// Program loop
do
{
// Display the program header
DrawHeader();
std::cout << std::endl; // Provide some spacing on the terminal buffer
// Display the program's about message
DrawAbout();
std::cout << std::endl << std::endl; // Provide some spacing on the terminal buffer
// Display the instructions
DrawInstructions();
std::cout << std::endl; // Provide some spacing on the terminal buffer
// (Re)Initialize the lockers to 0 or False
ResetLockers(lockerArray, _ARRAY_MAX_SIZE_);
// Ask user how many lockers to use in array
lockerRequestSize = FetchLockerSize();
// Perform the Locker Door Simulation
LockerDoorSimulation(lockerArray, lockerRequestSize);
// Find out how many locker doors that are currently opened
openDoors = CountOpenDoors(lockerArray, lockerRequestSize);
// Retrieve a list of locker doors that are open
lockerDoorOpenResults = ArrayIndexesResults(lockerArray, lockerRequestSize);
std::cout << std::endl << std::endl; // Provide some spacing on the terminal buffer
// Visually show the locker door status to the end-user
ArrayIndexesVisualResults(lockerArray, lockerRequestSize);
std::cout << std::endl << std::endl; // Provide some spacing on the terminal buffer
// Display the results to the user
DisplayResults(openDoors, lockerRequestSize, lockerDoorOpenResults);
std::cout << std::endl << std::endl; // Provide some spacing on the terminal buffer
// Ask the user if they want to close the program or do another operation
userChoice = AskRunProgramAgain();
// If running another operation, help the user's readability by
// shifting the old content away from the new content.
// This is merely only for readability sakes, nothing more.
if (userChoice)
{
// Display the content border
BorderSeparator();
// Provide some white space to help the user for readability.
std::cout << std::endl
<< std::endl
<< std::endl
<< std::endl
<< std::endl
<< std::endl
<< std::endl;
} // if :: Running Again
} while (userChoice);
// Prepare the termination process
std::cout << std::endl << "Terminating program. . ." << std::endl;
return 0;
} // main()
// Array Indexes Results
// ------------------------------------
// This function will scan the array and determine which indexes
// contain an open door. The results will be saved in such a way
// that it will contain an easy list. The results will be returned
// the calling function.
// ------------------------------------
// Parameters
// lockers[] (BOOL)
// The locker that contains open doors and to be analyzed
// size (INT)
// Size of the array that is to be scanned
// ------------------------------------
// Output
// Locker results in _nice_ values
// Will contain the results of which locker doors are 'open'.
std::string ArrayIndexesResults(bool lockerArray[], int size)
{
// Declarations and Initializations
// --------------------------------
std::string niceList = "";
// --------------------------------
for (int i = 1; i <= size; i++)
{
if (lockerArray[i])
niceList = niceList + std::to_string(i) + ", "; // Convert the int datatype value into a string
}
// Remove the last space and comma chars
niceList.pop_back();
niceList.pop_back();
// Return the results to the calling function
return niceList;
} // ArrayIndexesResults()
// Array Indexes Visual Results
// ------------------------------------
// This will provide a visual representation of the lockers,
// which are open and which are closed.
// Do note that there is a maximum restriction as to how many
// rows will be will be generated in the visual representation.
// If there is too many rows, the visual generator will just
// out-right refuse to render the visual representation.
// Try to keep the locker size relatively small.
// ------------------------------------
// Parameters
// lockers[] (BOOL)
// The locker that contains open doors and to be analyzed
// size (INT)
// Size of the array that is to be scanned
void ArrayIndexesVisualResults(bool lockerArray[], int size)
{
// Declarations and Initializations
// --------------------------------
const int MAX_ARRAY_SIZE = 15; // Maximum rows we are allowed
// to display. Anything that
// exceeds this will not be
// rendered.
char doorStatus; // This will supply easy to read
// information to the user, such
// as - 'X' or 'O' in relation
// to the locker door status.
// --------------------------------
// Check to make sure that we are able to visually render the array information
// if not, display a warning message instead and exit the function.
if (size > MAX_ARRAY_SIZE)
{
std::cout << "!ERR: Too many lockers, unable to visually draw locker door status information!" << std::endl;
return;
} // IF : Array size too large
// Render the Locker Array
// ===================================
// HEADER
std::cout << "\t=====================" << std::endl;
std::cout << "\t| Locker # | STATUS |" << std::endl;
// BODY
// Scan through the entire array and display the door status
for (int i = 1; i <= size; i++)
{
// Try to make the status easier to understand
if (lockerArray[i])
doorStatus = 'O'; // Locker door is open
else
doorStatus = 'X'; // Locker door is closed
// Render the result for this particular column.
std::cout << "\t|" << std::setw(5) << std::right << i << std::setw(6) << std::right
<< "|" << std::setw(5) << std::right << doorStatus << std::setw(5) << " | " << std::endl;
// Undo the formatting
std::cout << std::setw(0) << std::setfill(' ');
// if there is another row, add a separator to make
// reading this table easier
if (i < size)
{
// Supply a separator in between each individual row
std::cout << "\t" << std::setw(21) << std::setfill('-') << "" << std::endl;
// undo the formatting
std::cout << std::setw(0) << std::setfill(' ');
} // if : Not finished
} // for
// FOOTER
std::cout << "\t=====================" << std::endl;
} // ArrayIndexesVisualResults()
// Reset Lockers
// ------------------------------------
// This function will reset all of the lockers within
// the array to zero. All previous information stored
// within the array will be lost.
// ------------------------------------
// Parameters
// lockers[] (BOOL)
// Locker array that will be reset to 'zero'.
// size (INTEGER)
// Size of the locker array that will be reset.
void ResetLockers(bool lockerArray[], int size)
{
// Reset the array by size length.
for (int i = 0; i < size; i++)
lockerArray[i] = false;
} // ResetLockers()
// Fetch Locker Size
// ------------------------------------
// This function will ask the user how many lockers
// we are allowed to utilize in the algorithm.
// This function, in addition, will restrict the user
// to choose a number between the minimum and maximum
// boundaries.
// WARNING:
// We will trust the user to input a valid number. Anything other
// than a number WILL CAUSE complications. Since this is supposed
// to be a simple program, I won't bother fixing that issue here.
// ------------------------------------
// Output
// Integer
// Requested Locker Array Size
// How many lockers we are allowed to use within the array.
int FetchLockerSize()
{
// Declarations and Initializations
// --------------------------------
int requestedSize = 0; // Size of the locker array
// as requested by the end-user
bool validSizeErr = true; // If the user's input was valid
// --------------------------------
do
{
// Display the question on screen
std::cout << "How many lockers should we play around with?" << std::endl
<< "Pick a number between " << _ARRAY_MIN_SIZE_ << " and " << _ARRAY_MAX_SIZE_ << std::endl
<< _STDIN_PROMPT_;
// Retrieve the STDIN from end-user
std::cin >> requestedSize;
// Make sure that the input is valid
if ((requestedSize <= _ARRAY_MAX_SIZE_) &&
(requestedSize >= _ARRAY_MIN_SIZE_))
// The input fits within the range
validSizeErr = false;
else
// The input was not valid; outside of the ranges
std::cout << std::endl
<< "ERROR: The provided input [ " << requestedSize << " ] was _NOT_ valid!"
<< std::endl << std::endl;
} while (validSizeErr);
// Provide the size to the calling function
return requestedSize;
} // FetchLockerSize()
// Locker Door Simulation
// ------------------------------------
// This function will perform the Locker Door Simulation
// algorithm.
// Algorithm:
// Using a for loop to iterate through the initial size of the array,
// then use another array as an incremental counter for the first loop.
// Using the first and second loop product, we will use the result and
// flip the bit within that specified index from the product.
// Meaning:
// for i as 1 to size - 1
// for j as 1 to size - 1
// array at i * j = flip bit
// NOTES:
// 0 (or false) = Door is closed
// 1 (or true) = Door is open
// ------------------------------------
// Parameters
// lockers[] (BOOL)
// Locker array that will be altered during the algorithm.
// size (INTEGER)
// Size of the locker array.
void LockerDoorSimulation(bool lockerArray[], int size)
{
// Declarations and Initializations
// --------------------------------
int cache = 0; // Avoid redundancy calculation
// --------------------------------
// Scan through the entire array
for (int i = 1; i <= size; i++)
// Product
for (int j = 1; j * i <= size; j++)
{
cache = i * j; // Calculate the product once to avoid redundancy
lockerArray[cache] = // Flip the bit
!lockerArray[cache];
if (_DEBUG_STATE_) // Because I want to make sure that this algorithm works
std::cout << "Outter-Loop Key [ " << i << " ], Inner-Loop Key [ " << j << " ], Product [ " << cache << " ] " << std::endl
<< "\tAccessing Index with Key: " << cache << ".\tValue is now: " << lockerArray[cache] << std::endl << std::endl;
} // inner-for
} // LockerDoorSimulation()
// Count Locker Doors that are Open
// ------------------------------------
// This function will merely count how many locker doors
// that are open. This function should be called once
// the LockerDoorSimulation() algorithm has already took
// effect and not before.
// NOTES:
// 0 (or false) = Door is closed
// 1 (or true) = Door is open
// ------------------------------------
// Parameters
// lockers[] (BOOL)
// Locker array that will be scanned.
// size (INTEGER)
// Size of the locker array.
// ------------------------------------
// Output
// Integer
// How many locker doors are open from the locker array.
int CountOpenDoors(bool lockerArray[], int size)
{
// Declarations and Initializations
// --------------------------------
int openDoors = 0; // Counter of all locker doors that are open
// --------------------------------
// Scan through the array and find all doors that are open.
for (int i = 0; i < size; i++)
if (lockerArray[i]) // Is the locker door open?
openDoors++; // Increment the counter
// Return the number to the calling function
return openDoors;
} // CountOpenDoors()
// Display Results
// ------------------------------------
// This function is dedicated to presented the results to the end-user
// via terminal buffer.
// ------------------------------------
// Parameters
// openedDoors (INTEGER)
// How many locker doors were open after the algorithm.
// totalLockers (INTEGER)
// How many lockers total were part of this algorithm.
// indexesKey (STRING)
// What indexes contain an open locker door
void DisplayResults(int openedDoors, int totalLockers, std::string indexesKey)
{
std::cout << "\t>> Total number of lockers that are present: "
<< totalLockers << std::endl
<< "\t>> Number of locker doors that are presently open: "
<< openedDoors << std::endl
<< "\t>> Number of locker doors that are presently closed: "
<< totalLockers - openedDoors << std::endl
<< "\t>> Locker Doors that are open: "
<< indexesKey << std::endl;
} // DisplayResults()
// Draw Header
// ------------------------------------
// This function will provide a header to the top-most space on
// the terminal buffer.
void DrawHeader()
{
std::cout << _NAME_ << " - Version: " << _VERSION_ << std::endl
<< "Version Name: " << _VERSION_NAME_ << std::endl
<< "--------------------------------------------" << std::endl;
} // DrawHeader()
// Draw Instructions
// ------------------------------------
// This function will provide instructions to the end-user, along
// with how this program works.
void DrawInstructions()
{
std::cout << "Instructions" << std::endl
<< "-----------------------------" << std::endl
<< "Enter in how many lockers will be 'simulated' within this program." << std::endl
<< "You will be restricted from a minimum number of: " << _ARRAY_MIN_SIZE_ << " and a maximum number of: " << _ARRAY_MAX_SIZE_ << std::endl
<< "=========================================" << std::endl;
} // DrawInstructions()
// Draw About
// ------------------------------------
// This function is merely designed to display what this program is about and its primary purpose.
void DrawAbout()
{
std::cout << "The simulation will pretend to open the locker doors but by the number of passes that will depict what door is open and what is closed." << std::endl;
// Extra spacing
std::cout << std::endl << std::endl;
// Lets provide a visual example
// HEADER
std::cout << " LOCKER SIMULATION EXAMPLE" << std::endl;
// COLUMS
std::cout << " " << std::setw(28) << std::setfill('-') << "" << std::endl; // Bordering
std::cout << std::setw(0) << std::setfill(' '); // Undo the border settings
// ----
std::cout << " | PASS | 0 | 1 | 2 | 3 | 4 |" << std::endl;
// ----
std::cout << " " << std::setw(28) << std::setfill('-') << "" << std::endl; // Bordering
std::cout << std::setw(0) << std::setfill(' '); // Undo the border settings
// ROWS
std::cout << " | 1 | O | O | O | O | O |" << std::endl
<< " | 2 | O | X | O | X | O |" << std::endl
<< " | 3 | O | X | X | X | O |" << std::endl
<< " | 4 | O | X | X | O | O |" << std::endl
<< " | 5 | O | X | X | O | X |" << std::endl;
std::cout << " " << std::setw(28) << std::setfill('-') << "" << std::endl; // Bordering
std::cout << std::setw(0) << std::setfill(' '); // Undo the border settings
// Extra spacing
std::cout << std::endl;
// EXAMPLE RESULTS:
std::cout << " Total number of lockers (provided from the user): 5" << std::endl
<< " Number of locker doors currently opened (O): 2" << std::endl
<< " Number of locker doors currently closed (X): 3" << std::endl;
} // DrawAbout()
// Separator
// ------------------------------------
// This function will only display a border on the terminal buffer.
// This is ideally for separating content that will help the user
// to read.
void BorderSeparator()
{
// Display the border on the terminal buffer
std::cout << std::setw(100) << std::setfill('*') << " " << std::endl;
// Undo the customized settings we just used
std::cout << std::setw(0) << std::setfill(' ');
} // BorderSeparator()
// Run Program Again
// ------------------------------------
// This function will merely ask the end-user if they wish to perform
// another run with this program.
// WARNING:
// We will trust the user to input a valid character. Anything other
// than a character WILL CAUSE complications. Since this is supposed
// to be a simple program, I won't bother fixing that issue here.
// ------------------------------------
// Output:
// BOOL
// true = Run the program again
// false = terminate the program
bool AskRunProgramAgain()
{
// Declarations and Initializations
// --------------------------------
char userSTDIN; // Fetch user's request
bool runRequest; // User's request to be returned
// True = Run again
// False = Terminate the program
bool askLoop = true; // Ask the user (loop) if input was invalid.
// --------------------------------
do
{ // For checking user's input was valid
// Ask the user if they want to quit or run again
std::cout << "Run another operation?" << std::endl
<< "Type either: [Y]es or [N]o" << std::endl
<< _STDIN_PROMPT_;
// Fetch the input from the user
std::cin >> userSTDIN;
// Try to determine if the result was valid or not
// If valid, also perform the bit conversion.
if (tolower(userSTDIN) == 'y')
{
runRequest = true; // User wants to run program again
askLoop = false; // Input was valid
} // IF :: Run Program Again
else if (tolower(userSTDIN) == 'n')
{
runRequest = false; // User wants to leave the program
askLoop = false; // Input was valid
} // IF :: Destroy Program Instance
else
// Bad Input
std::cout << std::endl << "ERROR! Input was not valid! Type either 'Y' or 'N'" << std::endl << std::endl;
} while (askLoop);
// Return the user's request to the calling function
return runRequest;
} // AskRunProgramAgain()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment