main.cpp /* * COMP.CS.110 Ohjelmointi 2 * Osio 4, projekti: Mastermind * * Ohjelman kuvaus: * Ohjelma toteuttaa Mastermind-pelin. Pelissä annetaan tai arvotaan * ensin salainen neljän värin sarja. Sama väri voi esiintyä sarjassa * useita kertoja, mutta mikään neljästä positiosta ei voi olla tyhjä. * Käyttäjä yrittää arvata, mitkä värit esiintyvät sarjassa ja missä * järjestyksessä. Tätä varten käyttäjä antaa oman neljän värin sarjansa, * ja ohjelma ilmoittaa, kuinka monta väriarvausta meni täysin oikein * (oikea väri oikeassa positiossa) sekä kuinka monta arvausta meni * pelkästään värin osalta oikein (oikea väri väärässä positiossa). * Tämän jälkeen käyttäjä voi tehdä uuden arvauksen jne. * Aluksi käyttäjältä kysytään, täytetäänkö peliruudukko satunnaisesti * arvottavilla väreillä vai käyttäjän luettelemilla väreillä. * (Jälkimmäinen tapa ei ole kovin järkevä, mutta se on hyödyllinen * testauksen kannalta.) Ensimmäisessä vaihtoehdossa käyttäjältä kysytään * satunnaislukugeneraattorin siemenlukua ja jälkimmäisessä häntä * pyydetään syöttämään neljä väriä (värien alkukirjaimet eli neljän * merkin mittainen merkkijono). * Joka kierroksella käyttäjältä kysytään uutta arvausta. Peli päättyy * pelaajan voittoon, jos arvaus menee jokaisen värin kohdalta täysin * oikein. Peli päättyy pelaajan häviöön, jos hän ei ole arvannut oikein * maksimimäärällä (10) arvauskertoja. * Ohjelma tarkistaa, että annetut värit kuuluvat sallittujen värien * joukkoon. Pelin päättyessä kerrotaan, voittiko vai hävisikö pelaaja. * */ #include "mastermind.hh" int main() { Board mastermind; mastermind.play_game(); return EXIT_SUCCESS; } MASTERMIND.CPP /* * COMP.CS.110 Ohjelmointi 2 * Osio 4, projekti: Mastermind */ #include "mastermind.hh" #include #include #include #include using namespace std; // converts string to lowercase string to_lower(string str) { transform(str.begin(), str.end(), str.begin(), ::tolower); return str; } // converts string to uppercase string to_upper(string str) { transform(str.begin(), str.end(), str.begin(), ::toupper); return str; } Board::Board() { } Board::~Board() { } void Board::play_game() { ask_game_type(); generate_colors(); // MAIN GAME LOOP while (turn < MAX_TURNS) { ask_for_colors(); // QUIT GAME if(user_guess == QUIT_CMD) { return; } grade_a_guess(); print_board(); if (is_game_won) { cout << MSG_GAME_WON << endl; break; } turn++; } // if main loop ends, it means turns are used up and the player lost if (not is_game_won) { cout << MSG_GAME_LOST << endl; } } void Board::ask_game_type() { string user_input; string seed_value; // print colors used in the game for user cout << COLOR_INFO << endl; cout << std::string(COLOR_INFO.size(), '*') << endl; // user must choose a random or predef game type while (true) { cout << INPUT_WAY_QUESTION; cin >> user_input; // RANDOM game if (to_lower(user_input) == "r") { cout << SEED_QUESTION << endl; get_valid_seed(); is_random_game = true; break; } // PREDEFINED game else if (to_lower(user_input) == "l") { is_random_game = false; break; } // WRONG INPUT else { cout << BAD_INPUT << endl; } } } void Board::generate_colors() { // fill solution vector with 4 random letters if (is_random_game) { srand(seed); for(int i = 0; i < MAX_COLORS; i++) { char color = COLORS[rand() % DIFFERENT_COLORS]; solution.push_back(color); } } else { ask_for_colors(COLOR_QUESTION); solution = user_guess; } } int Board::ask_for_colors(string question) { string user_input; bool valid = false; // demand correct input from user while(true) { if (question != "") { cout << question; } else { cout << ROW; } cin >> user_input; // q = QUIT GAME if (to_lower(user_input) == QUIT_CMD and question == "") { user_guess = QUIT_CMD; return 0; } // check user input for size and allowed colors else if(user_input.size() == MAX_COLORS) { user_guess = user_input; valid = is_input_valid(); if (valid) { return 0; } else { cout << UNKNOWN_COLOR << endl; } } else { cout << MSG_WRONG_SIZE << endl; } } } void Board::grade_a_guess() { int fully_correct = 0; int partially_correct = 0; string potentially_partially_correct_colors = ""; string leftover_colors_from_solution = ""; // count fully correct colors for (unsigned long int i = 0; i < user_guess.size(); i++) { if (user_guess.at(i) == solution.at(i)) { fully_correct++; } else { potentially_partially_correct_colors += user_guess.at(i); leftover_colors_from_solution += solution.at(i); } } // count partially correct colors for (char pot : potentially_partially_correct_colors) { unsigned long int index; index = leftover_colors_from_solution.find(pot); if (index < MAX_COLORS) { partially_correct += 1; leftover_colors_from_solution.erase(index, 1); } } // save results and check if the game is won all_grades.push_back({user_guess, fully_correct, partially_correct}); if (fully_correct == MAX_COLORS) { is_game_won = true; } } void Board::print_board() { cout << std::string(GAME_BOARD_WIDTH, '=') << endl; for (auto &guess : all_grades) { cout << "| "; for(char &color : guess.guess) { cout << (char) toupper(color) << " "; } cout << "| " << guess.fully_correct << " | " << guess.partially_correct << " |" << endl; } cout << std::string(GAME_BOARD_WIDTH, '=') << endl; } bool Board::is_input_valid() { bool valid = true; // convert char array to string since char doesn't seem to have find() string tmp = ""; tmp += COLORS; // search for invalid colors in user input for(unsigned long int i = 0; i < user_guess.size(); i++) { string letter = ""; letter += user_guess.at(i); // find returns a big number if it doesn't find the letter if (tmp.find(letter) > DIFFERENT_COLORS) { valid = false; break; } } return valid; } void Board::get_valid_seed() { string user_input; string temp_seed = ""; while (true) { cin >> user_input; // check for anything else than digits in seed for (char ch : user_input) { if(isdigit(ch)) { temp_seed += ch; } else { cout << BAD_INPUT << endl; break; } } // accept a seed consisting only of digits if(temp_seed != "" and temp_seed.size() == user_input.size()) { seed = stoi(temp_seed); break; } } } /* * COMP.CS.110 Ohjelmointi 2 * Osio 4, projekti: Mastermind */ #ifndef MASTERMIND_HH #define MASTERMIND_HH #include #include using namespace std; const char COLORS[] = "brygov"; const int MAX_COLORS = 4; const int DIFFERENT_COLORS = 6; const int MAX_TURNS = 10; const int GAME_BOARD_WIDTH = 19; class Board { const string QUIT_CMD = "q"; const string COLOR_INFO = "Colors in use: B = Blue, R = Red, " "Y = Yellow, G = Green, O = Orange, V = Violet"; const string INPUT_WAY_QUESTION = "Enter an input way (R = random, L = list): "; const string COLOR_QUESTION = "Enter four colors (four letters without spaces): "; const string SEED_QUESTION = "Enter a seed value: "; const string ROW = "ROW> "; const string BAD_INPUT = "Bad input"; const string UNKNOWN_COLOR = "Unknown color"; const string MSG_WRONG_SIZE = "Wrong size"; const string MSG_GAME_WON = "You won: Congratulations!"; const string MSG_GAME_LOST = "You lost: Maximum number of guesses done"; public: // constructor and destructor (no idea how to use these, sorry!) Board(); ~Board(); // starts the game and runs the main gameplay loop // until user quits, wins or loses the game void play_game(); private: struct Correct { string guess; int fully_correct; int partially_correct; }; vector all_grades; string solution; string user_guess; bool is_random_game; bool is_game_won = false; int seed; int turn = 0; // user mandates if gametype is random or predefined void ask_game_type(); // generates random colors or asks user for colors, depending // on gametype chosen earlier void generate_colors(); /* asks user for correct letters (colors) listed in const COLORS * return: 0 (basically just returns to main program when * user inputs correct letters) */ int ask_for_colors(string question = ""); // grades user's guess and saves it to vector all_grades void grade_a_guess(); // prints the game board using data from vector all_grades /* Example: * =================== * | B B R R | 1 | 0 | * | B B O O | 1 | 1 | * =================== */ void print_board(); // checks that the colors user provided are listed in COLORS bool is_input_valid(); // gets a seed consisting of only digits from user void get_valid_seed(); }; #endif // MASTERMIND_HH