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;
}
//Leif Messinger
//Finds all sets of 5 5 letter words that don't have duplicate letters in either themselves or each other.
//First it reads the words in and puts them in groups of their bitmasks
//After that, we recurse on each group. Before doing that, we remove the group from the set of other groups to check it against.
#include <cstdio> //getchar, printf
#include <cassert> //assert
#include <vector>
#include <set>
#include <algorithm> //std::copy_if
#include <iterator> //std::back_inserter

#define CHECK_FOR_CRLF true
#define MIN_WORDS 5
#define MAX_WORDS 5
#define WORD_TOO_LONG(len) (len != 5)

const unsigned int charToBitmask(const char bruh){
	assert(bruh >= 'a' && bruh <= 'z');
	return (1 << (bruh - 'a'));
}

void printBitmask(unsigned int bitmask){
	char start = 'a';
	while(bitmask != 0){
		if(bitmask & 1){
			putchar(start);
		}

		bitmask >>= 1;
		++start;
	}
}

//Pointer needs to be deleted
const std::set<unsigned int>* getBitmasks(){
	std::set<unsigned int>* bitmasksPointer = new std::set<unsigned int>;
	std::set<unsigned int>& bitmasks = (*bitmasksPointer);

	unsigned int bitmask = 0;
	unsigned int wordLength = 0;
	bool duplicateLetters = false;
	for(char c = getchar(); c >= 0; c = getchar()){
		if(CHECK_FOR_CRLF && c == '\r'){
			continue;
		}
		if(c == '\n'){
			if(!(WORD_TOO_LONG(wordLength) || duplicateLetters)) bitmasks.insert(bitmask);
			bitmask = 0;
			wordLength = 0;
			duplicateLetters = false;
			continue;
		}
		if((bitmask & charToBitmask(c)) != 0) duplicateLetters = true;
		bitmask |= charToBitmask(c);
		++wordLength;
	}

	return bitmasksPointer;
}

void printBitmasks(const std::vector<unsigned int>& bitmasks){
	for(unsigned int bruh : bitmasks){
		printBitmask(bruh);
		putchar(','); putchar(' ');
	}
	puts("");
}

//Just to be clear, when I mean "word", I mean a group of words with the same letters.
void recurse(std::vector<unsigned int>& oldBitmasks, std::vector<unsigned int> history, const unsigned int currentBitmask){
	//If there's not enough words left
	if(oldBitmasks.size() + (-(history.size())) + (-MIN_WORDS) <= 0){
		//If there's enough words
		if(history.size() >= MIN_WORDS){
			//Print the list
			printBitmasks(history);
		}
		return;
	//To make it faster, we can stop it after 5 words too
	}else if(history.size() >= MAX_WORDS){
		//Print the list
		printBitmasks(history);
		return;
	}

	//Thin out the array with only stuff that matches the currentBitmask.
	std::vector<unsigned int> newBitmasks;
	std::copy_if(oldBitmasks.begin(), oldBitmasks.end(), std::back_inserter(newBitmasks), [&currentBitmask](unsigned int bruh){
		return (bruh & currentBitmask) == 0;
	});

	while(newBitmasks.size() > 0){
		//I know this modifies 'oldBitmasks' too. It's intentional.
		//This makes it so that the word is never involved in any of the child serches or any of the later searches in this while loop.
		const unsigned int word = newBitmasks.back(); newBitmasks.pop_back();

		std::vector<unsigned int> newHistory = history;
		newHistory.push_back(word);

		recurse(newBitmasks, newHistory, currentBitmask | word);
	}
}

int main(){
	const std::set<unsigned int>* bitmasksSet = getBitmasks();
	std::vector<unsigned int> bitmasks(bitmasksSet->begin(), bitmasksSet->end());
	delete bitmasksSet;

	recurse(bitmasks, std::vector<unsigned int>(), 0);

	return 0;
}