Skip to main content
Loading...

More C++ Posts

//===============Header File==================
#include <iostream>
#include <sstream> //stringbuf
#include <utility> //exchange

//Couple rules:
//Characters given through the getter functions have to be removed from the buffer.
    //This is so that bufferEmpty() == buffer.in_avail() > 0 basically always.
    //skipWhitespace doesn't remove the text from the buffer, but it does return the number of characters.
//nextWord will trim whitespace before the word
//nextInt will trim non-numbers before the number
//hasNextInt and hasNextWord will trim the whitespace. If you think you need it, you should get nextWhitespace before doing any of those.
//Whitespace after a word or an int is left on the buffer.
//nextWhitespace will (get and) remove whitespace until the end of the line, including the newline character, but stops before the next line.
    //nextWhitespace won't read the next line when called before the end of the line, and it won't prompt the user for the next line if interactive.
        //If nextWhitespace is called after reading the end of the line, then it will read a new line into the buffer, which will prompt the user.
    //It acts like nextLine, but if there's something non-whitespace on the current line it stops there.
class Scanner {
    public:
        std::stringbuf buffer;
        std::istream& input;
        
        Scanner(std::istream& in = std::cin) : buffer(), input(in) {}
        
    //Buffer debugging
        bool fillBuffer();
    
        bool bufferEmpty();
        void printBufferEmpty();
        std::string getBuffer();
        size_t bufferLength();
        void printBufferStats();
    
    //Int
        bool hasNextInt();
        int nextInt();
    
    //Word
        bool hasNextWord();
        std::string nextWord();
    
    //Line
        bool hasNextLine();
    
    //Whitespace
        size_t skipWhitespace();    //Prob should be private, but I don't believe in that private shit.
        bool hasNextWhitespace();
        std::string nextWhitespace();
        std::string nextWhitespaceAll();
        std::string nextLine();
};

//===============Source File==================
bool Scanner::fillBuffer() {    //Returns if it had to get the next line from the input.
    const bool badInput = input.eof() || input.bad();
    const bool shouldFillBuffer = bufferEmpty() && !badInput;
    if (shouldFillBuffer) {
        std::string line;
        if (std::getline(input, line)) {
            buffer.str(buffer.str() + line + "\n");
        }
    }
    return shouldFillBuffer;
}

bool Scanner::bufferEmpty(){
    return buffer.str() == "";
}
void Scanner::printBufferEmpty(){
    std::cout << "The buffer is " << (bufferEmpty()? "" : "not") << " empty." << std::endl;
}

std::string Scanner::getBuffer(){
    return buffer.str();
}
size_t Scanner::bufferLength(){
    return buffer.str().length();
}
void Scanner::printBufferStats(){
    if(bufferEmpty()){
        std::cout << "The buffer is \"\"" << std::endl;
        return;
    }
    std::cout << "The length of the buffer is " << bufferLength() << std::endl;
    if(buffer.sgetc() == '\r'){
        std::cout << "The buffer is \\r\\n" << std::endl;
    }else if(buffer.sgetc() == '\n'){
        std::cout << "The buffer is \\n" << std::endl;
    }
}

bool Scanner::hasNextInt() {
    return hasNextWord() && (std::isdigit(buffer.sgetc()) || buffer.sgetc() == '-');
}

int Scanner::nextInt() {
    if (!hasNextInt()) {   //Will fill the buffer if not filled. Will also trim whitespace.
        return 0;
    }
    
    std::string num;
    size_t charactersRead = 0;
    while (buffer.in_avail() > 0 && (std::isdigit(buffer.sgetc()) || buffer.sgetc() == '-')) {
        num += buffer.sbumpc();
        ++charactersRead;
    }
    buffer.str(buffer.str().erase(0, charactersRead));
    return std::stoi(num);
}

bool Scanner::hasNextWord() {
    nextWhitespaceAll();
    return buffer.in_avail() > 0;
}

std::string Scanner::nextWord() {
    if (!hasNextWord()) {   //Will fill the buffer if not filled. Will also trim whitespace.
        return "";
    }
    
    std::string word;
    size_t charactersRead = 0;
    while (buffer.in_avail() > 0 && !std::isspace(buffer.sgetc())) {
        word += buffer.sbumpc();
        ++charactersRead;
    }
    buffer.str(buffer.str().erase(0, charactersRead));
    return word;
}

bool Scanner::hasNextLine() {
    return (!bufferEmpty()) || fillBuffer();
}

size_t Scanner::skipWhitespace() {   //Returns characters read
    size_t charactersRead = 0;
    while (buffer.in_avail() > 0 && std::isspace(buffer.sgetc())) {
        buffer.sbumpc();
        ++charactersRead;
    }
    return charactersRead;
}
bool Scanner::hasNextWhitespace(){
    fillBuffer();
    return buffer.in_avail() > 0 && std::isspace(buffer.sgetc());
}
std::string Scanner::nextWhitespace() {
    if (!hasNextWhitespace()) {   //Will fill the buffer if not filled
        return "";
    }
    const size_t charactersRead = skipWhitespace();
    std::string whitespace = buffer.str().substr(charactersRead);
    buffer.str(buffer.str().erase(0, charactersRead));
    return whitespace;
}
std::string Scanner::nextWhitespaceAll(){
    std::string whitespace;
    while(hasNextWhitespace()){
        std::string gottenWhiteSpace = nextWhitespace();
        whitespace += gottenWhiteSpace;
    }
    return whitespace;
}
std::string Scanner::nextLine(){
    if (!hasNextLine()) {
        return "";
    }
    
    fillBuffer();
    //Swap out the old buffer with an empty buffer, and get the old buffer as a variable.
    std::string line = std::exchange(buffer, std::stringbuf()).str();
    
    //Remove the newline.
    if(line[line.length() - 1] == '\n' || line[line.length() - 1] == '\r' ) line.pop_back();
    if(line[line.length() - 1] == '\r' || line[line.length() - 1] == '\n' ) line.pop_back();
    return line;
}


//=================Word and Int test=================
while(bruh.hasNextInt() || bruh.hasNextWord()){
    std::cout << "started loop" << std::endl;
    if(bruh.hasNextInt()){
        std::cout << "Int: " << bruh.nextInt() << " " << std::endl;
    }else{
        std::cout << "Word: " << bruh.nextWord() << " " << std::endl;
    }
    bruh.nextWhitespace();
}
//===================Line test======================
for(int count = 1; bruh.hasNextLine(); ++count){
    std::string line = bruh.nextLine();
    std::cout << "Line " << count << ": " << line << std::endl;
}
#include <iostream>
#include <vector>
#include <limits>

#define DEBUG_TRIAL false

class Trial{
    public:
        const size_t HEIGHT;
        std::string record;
        
        //Breaking height is the index of the floor, so 0 is the bottom floor, height-1 is the top floor.
        //Eggs is the eggs remaining.
        //Start is the bottom floor.
        //End is one above the top floor.
        const size_t BREAKING_HEIGHT;
        size_t eggs;
        size_t start;
        size_t end;
        
        
        size_t floorsLeft(){
            return (end-start);
        }
        
        size_t middle(){
            return start + (floorsLeft()/2UL);
        }
        
        size_t drops = 0;
        Trial(const size_t BREAKING_HEIGHT, size_t eggs, size_t start, size_t end): BREAKING_HEIGHT(BREAKING_HEIGHT), eggs(eggs), start(start), end(end), HEIGHT(end), record(end, '_'){
            record[BREAKING_HEIGHT] = 'B'; //Marking the breaking point
        }
        
        bool foundAnswer(){
            return ((record[0] == 'X') || (record.find("OX")!=std::string::npos));
        }
        
        //returns true if the egg broke.
        //height is the index of the floor, so 0 is the bottom floor, height-1 is the top floor.
        bool drop(size_t height){
            
            #if DEBUG_TRIAL
                std::cout << "Start: " << start << ". End: " << end << ". Floors Left: " << floorsLeft() << ". Middle Index: " << middle() << std::endl;
            #endif
            
            drops++;
            bool cracked = height >= BREAKING_HEIGHT;
            if(cracked) --eggs;
            
            //Update the record
            record[height] = (height >= BREAKING_HEIGHT)? 'X' : 'O';
            
            #if DEBUG_TRIAL
                //Print the record
                std::cout << record << std::endl;
            #endif
        
            return cracked;
        }
        
        size_t nowWhat(){
            if(foundAnswer()){
                return drops;
            }else if(eggs <= 0){ //Ran out of eggs
                throw "Algorithm failed! No more eggs!";
                return 1UL;
            }else if(eggs > 1){
                return wrecklessSearch();
            }else{
                return safeSearch();
            }
        }
        
        size_t safeSearch(){
            if(drop(start)){
                --end;
            }else{
                ++start;
            }
            
            return nowWhat();
        }
        
        size_t wrecklessSearch(){
            //If the egg breaks
            if(drop(middle())){
                end -= (floorsLeft()/2UL);
            }else{ //egg doesn't crack
                start += (floorsLeft()/2UL);
            }
            
            return nowWhat();
        }
        
        //returns the amount of drops needed to find the answer
        size_t search(){
            return nowWhat();
        }
};

//Height is the height of the building in floors.
//Breaking height is the index of the floor, so 0 is the bottom floor, height-1 is the top floor.
//Eggs is the eggs given.
//returns the amount of drops needed to find the answer
size_t search(const size_t height, const size_t BREAKING_HEIGHT, size_t eggs){
    Trial trial(BREAKING_HEIGHT, eggs, 0, height);
    return trial.search();
}

class TrialStats {
    public:
        size_t min = std::numeric_limits<size_t>::max();
        size_t max = 0;
        double mean = -1.0;
        
        void printStats(){
            // Print the results
            std::cout << "Minimum drops: " << min << std::endl;
            std::cout << "Maximum drops: " << max << std::endl;
            std::cout << "Mean drops: " << mean << std::endl;
        }
};

//Benchmarks all the possible breaking points of a single building height with a number of eggs.
TrialStats trial(const size_t HEIGHT, const size_t eggs){
    
    TrialStats stats;
    int totaldrops = 0;

    //Test every possible breaking point
    //Breaking height is the index of the floor, so 0 is the bottom floor, height-1 is the top floor.
    for (int breakingHeight = 0; breakingHeight < HEIGHT; ++breakingHeight) {
        size_t drops = search(HEIGHT, breakingHeight, eggs);

        stats.min = std::min(stats.min, drops);
        stats.max = std::max(stats.max, drops);
        totaldrops += drops;
    }

    // Calculate the mean number of drops
    stats.mean = static_cast<double>(totaldrops) / HEIGHT;
    
    return stats;
}

//Benchmarks a single building height from 1 egg to MAX_EGGS
void testTower(const size_t height, const size_t MAX_EGGS){
    //Drop every amount of eggs that you'd need.
    for (int eggs = 1; eggs <= MAX_EGGS; ++eggs) {
        std::cout << "Building height: " << height << ". Num eggs: " << eggs << std::endl;
        
        TrialStats stats = trial(height, eggs);
        stats.printStats();
        
        std::cout << std::endl << std::endl;
    }
}

//Benchmarks all buildings from 0 to MAX_HEIGHT
void benchmark(const size_t MAX_HEIGHT){
    const size_t MAX_EGGS = 2;
    //Test every building
    for (size_t height = 1; height <= MAX_HEIGHT; ++height) {
        testTower(height, std::min(height, MAX_EGGS));
    }
}

int main() {
    constexpr size_t MAX_HEIGHT = 36;
    
    benchmark(MAX_HEIGHT);

    return 0;
}