// Standard Libraries
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
// Functions used for both modes
bool valid( int num )
{
if ( num > 6666 || num < 1111 ) {return false;}
if ( num%10 > 6 || (num/10)%10 > 6 ) {return false;}
if ( (num/100)%10 > 6 || (num/1000)%10 > 6 ) {return false;}
if ( num%10 < 1 || (num/10)%10 < 1 ) {return false;}
if ( (num/100)%10 < 1 || (num/1000)%10 < 1 ) {return false;}
return true;
}
bool valid_response( int num )
{
if ( num > 2222 || num < 0000 ) {return false;}
if ( num%10 > 2 || (num/10)%10 > 2 ) {return false;}
if ( (num/100)%10 > 2 || (num/1000)%10 > 2 ) {return false;}
return true;
}
inline int digit( const int loc, const int num )
{
return floor( pow(10, 1-loc) * ( num % (int) pow(10, loc) ) );
}
inline int nums_to_int( int a, int b, int c, int d )
{
return a*1000 + b*100 + c*10 + d;
}
const int get_difficulty()
{
char response;
std::cout << "\nWould you like easy(e), medium(m), or hard(h)?: ";
while ( true ) {
std::cin >> response;
if ( response == 'e' ) {return 12;}
else if ( response == 'm' ) {return 10;}
else if ( response == 'h' ) {return 8;}
else {
std::cout << "\nEnter a valid response of e, m, or h: ";
}
}
}
int decending( int num )
{
int a_num[4];
for ( int i = 4; i > 0; i-- )
{
a_num[i-1] = digit( i, num );
}
std::sort(a_num, a_num + 4, std::greater<int>() );
return nums_to_int( a_num[0], a_num[1], a_num[2], a_num[3] );
}
int auto_respond( const int& guess, const int& code, const bool& show )
{
int response[4] = { 0, 0, 0, 0 };
// Special case
if ( guess == 0 ) {return 3333;}
// Split digits into arr
int g[4], c[4];
for ( int i = 4; i > 0; i-- )
{
g[i-1] = digit( i, guess );
c[i-1] = digit( i, code );
}
// Return BLACK
for ( int i = 0; i < 4; i++ )
{
if ( g[i] == c[i] )
{
response[i] = 2;
c[i] = 0; g[i] = 0;
}
}
// Return WHITE
for ( int i = 0; i < 4; i++ )
{
if ( g[i] == 0 ) { continue; }
if ( g[i] == c[(i+1)%4] ||
g[i] == c[(i+2)%4] ||
g[i] == c[(i+3)%4] )
{
response[i] = 1;
}
}
// Output response if codebreaking
if ( show )
{
// Shuffle for realistic gameplay
std::random_shuffle(response, response+4);
std::cout << "The CPU's response is: ";
for ( int i = 0; i < 4; i++ )
{
std::cout << response[i];
}
std::cout << "\n\n";
}
return decending( nums_to_int( response[3], response[2],
response[1], response[0] ) );
}
// Functions for codebreaker mode
int cpu_make_code()
{
int code = 0;
for ( int i = 0; i < 4; i++ )
{
code += (rand() % 6 + 1) * (int) pow(10, i);
}
//std::cout << "The code is: " << code << '\n';
return code;
}
int user_guess()
{
int guess;
do {
std::cout << "Input your next guess: ";
std::cin >> guess;
if ( !valid( guess ) )
{
std::cout << "\nThis guess is not valid, try again\n";
}
} while ( !valid( guess ) );
return guess;
}
void play_codebreaker()
{
int code, guess, response, num_guess;
code = cpu_make_code();
num_guess = get_difficulty();
do {
std::cout << "\nGuesses Left: " << num_guess << '\n';
guess = user_guess();
response = auto_respond( guess, code, true );
num_guess--;
} while ( guess != code && num_guess != 0 );
if ( num_guess != 0 )
{
std::cout << "The code has been broken! You win!\n";
}
else { std::cout << "Out of guesses, you lose\n"; }
return;
}
// Functions for codemaker mode
int user_make_code()
{
int code;
do {
std::cout << "Input a valid code ( 1111 - 6666 ): ";
std::cin >> code;
} while ( !valid( code ) );
return code;
}
void fill_codes( int code_list[1296] )
{
int cnt = 0;
for ( int a = 1; a < 7; a++ )
{
for ( int b = 1; b < 7; b ++ )
{
for ( int c = 1; c < 7; c++ )
{
for ( int d = 1; d < 7; d ++ )
{
code_list[cnt++] = nums_to_int( a, b, c, d );
}
}
}
}
std::sort( code_list, code_list + 1296 );
}
int user_respond( const int& guess, const int& code )
{
int response;
std::cout << "\nThe current guess is: " << guess << '\n';
do {
std::cout << "Your code is: " << code << '\n';
std::cout << "Enter a valid response: ";
std::cin >> response;
} while ( !valid_response( response ) );
return response;
}
void play_codemaker()
{
int code, guess, response, chk_rsp, num_guess;
int total_zero = 0, possible_codes[1296];
code = user_make_code();
fill_codes( possible_codes );
num_guess = 8;
std::cout << "Reponse format { 2 = BLACK, 1 = WHITE, 0 = NULL }\n";
do {
std::cout << "\nGuesses Left: " << num_guess << '\n';
guess = possible_codes[rand()%(1296 - total_zero)];
response = user_respond( guess, code );
for ( int i = 0; i < 1296; i++ )
{
chk_rsp = auto_respond( possible_codes[i], guess, false );
if ( chk_rsp != decending( response ) && chk_rsp != 3333 )
{
possible_codes[i] = 0;
total_zero++;
}
}
if ( total_zero >= 1296 )
{
std::cout << "CHEATER! YOU LOSE!\n";
exit( EXIT_SUCCESS );
}
num_guess--;
std::sort(possible_codes, possible_codes + 1296, std::greater<int>() );
} while ( response != 2222 && num_guess != 0 );
if ( num_guess > 0 )
{
std::cout << "The code has been broken! You lose.\n";
}
else { std::cout << "Computer out of guesses, you win!\n"; }
return;
}
//Main
int main ( int argc, const char* argv[] )
{
bool valid, play_again;
char response;
do {
play_again = false;
valid = false;
std::cout << "Welcome to Mastermind\n";
std::cout << "Type 'b' for code breaker, 'm' for code maker: ";
do {
std::cin >> response;
if ( response == 'b' || response == 'm' )
{valid = true;}
} while ( !valid );
if ( response == 'b' )
{
play_codebreaker();
}
if ( response == 'm' )
{
play_codemaker();
}
std::cout << "Would you like to play again? (y/n)\n";
std::cin >> response;
if ( response == 'y' )
{
play_again = true;
}
} while ( play_again );
std::cout << "Goodbye\n";
return 0;
}