My Implementation of Bulls & Cows


#1

So, I have quite a bit of prior coding experience, and kinda just listened to the introduction of each video to see what was going to be accomplished, wrote my own implementation, then went back to see what Ben did, so there’s quite a few major differences in the code, but the end result is the same.

#pragma once
#include <string>
class BullCow {
public:
    enum Setting { EASY=1, NORMAL, HARD };
    BullCow(std::string word_to_guess, Setting difficulty);
    BullCow(std::string word_to_guess, int lives, Setting difficulty);
    ~BullCow();
    bool PlayGame();
private:
    const std::string word_to_guess;
    const size_t word_length;
    int lives;
    Setting difficulty;
    std::string GetGuess();
    bool CheckAnswer(const std::string &answer);
    bool AnIsogram(std::string &guess);
    bool CorrectLength(std::string &guess);
};
#include "BullCow.h"
#include <iostream>
#include <set>

BullCow::BullCow(std::string word_to_guess, Setting difficulty)
    : BullCow(word_to_guess, 8, difficulty) {
}

BullCow::BullCow(std::string word_to_guess, int lives, Setting difficulty)
    : word_to_guess {word_to_guess}
    , word_length {word_to_guess.length()}
    , lives {lives}
    , difficulty {difficulty} {
}

bool BullCow::CorrectLength(std::string &guess) {
    if (guess.length() != word_length) {
        std::cout << "Invalid length, please guess a " << word_length << " letter word." << std::endl;
        return false;
    } else return true;
}

bool BullCow::AnIsogram(std::string &guess) {
    std::set<char> check {};
    for (auto &c : guess) {
        c = ::tolower(c);
        if (!check.insert(c).second) {
            std::cout << "Isograms cannot use the same letter twice." << std::endl;
            return false;
        }
    }
    return true;
}

std::string BullCow::GetGuess() {
    std::string guess;
    do {
        std::cout << "Enter your guess: ";
        std::getline(std::cin, guess);
    } while (!CorrectLength(guess) || !AnIsogram(guess));
    return guess;
}

bool BullCow::CheckAnswer(const std::string &guess) {
    std::string result(word_length, '_');
    int bulls {}, cows {};
    for (size_t i {}; i < word_length; ++i) {
        for (size_t j {}; j < word_length; ++j) {
            if (word_to_guess[i] == guess[j]) {
                if (i == j) {
                    ++bulls;
                    result[i] = word_to_guess[i];
                } else ++cows;
                break;
            }
        }
    }
    if (difficulty == Setting::EASY) {
        std::cout << '\n';
        for (size_t i {}; i < word_length; ++i)
            std::cout << ' ' << guess[i];
        std::cout << '\n';
        for (size_t i {}; i < word_length; ++i)
            std::cout << ' ' << result[i];
        std::cout << " -> ";
    } else std::cout << '\n';
    std::cout << "Bulls: " << bulls << " Cows: " << cows << std::endl;
    return bulls == word_length;
}

bool BullCow::PlayGame() {
    std::cout << "\nCan you guess the " << word_length << " letter isogram I'm thinking of?" << std::endl;

    while(true) {
        std::cout << "\nYou have " << lives << " lives remaining." << std::endl;
        std::string guess {GetGuess()};
        if (CheckAnswer(guess)) {
            std::cout << "\nCongratulations! You Win!" << std::endl;
            return true;
        } else {
            --lives;
            if (lives <= 0) {
                std::cout << "\nSorry! Game Over!" << std::endl;
                return false;
            }
        }
    }
}

BullCow::~BullCow() {
    std::cout << "Thanks for playing!\n" << std::endl;
}