// Author: Chan Tsz Ming
// U. No.: 3035692462
// COMP2113 Course Project
// Description: Bulls and Cows

// this is the main file for running the game

#include <iostream>
#include <cstdlib>
#include <string>
#include <cctype>
#include <ctime>

using namespace std;

// A "Guess" contains parameters A and B, representing...
// ...the no. of bulls and cows respectively of a guess number
// It stores the guess number ("gnum") in a dynamic char array as well
struct Guess {
  int A;
  int B;
  char * gnum;
};

// this function gets a number from user input
// if the input is valid, it returns True and stores the input number in a dynamic char array num[]
// int leng is the required no. of digits in the number
// it returns False if the input is invalid
// NOTE: num is a char array, not int or int array
bool getnum_in(char * &num, int leng)
{
  string num_in;
  cin >> num_in;
  if (num_in.length() != leng) {
    return 0;
  }
  else {
    int i;
    for (i = 0; i < num_in.length(); i++) {
      if (!isdigit(num_in[i])) {
        return 0;
        break;
      }
      else num[i] = num_in[i];
    }
    num[i] = '\0';
    return 1;
  }
  
}


// this function returns the number of bulls
// sec: secret number    guess: guess number by player   leng: no. of digits of the number
int n_bulls(char * &sec , char * &guess, int leng)
{
  int b = 0;
  for (int i = 0 ; i < leng ; i++) {
    if (sec[i] == guess[i]) {b++ ;}
  }
  return b;
}

// this function returns the number of COWS AND BULLS TOGETHER
// by comparing all possible combinations (pairs) between...
// ... the digits of secret number and guess number
int n_cowsNbulls(char * &sec , char * &guess, int leng)
{
  // these two bool arrays are to record whether the digit...
  // ... has already been matched, to avoid double counting...
  // ... when there are repeated digits in sec or in guess
  bool * sec_matched = new bool[leng];
  bool * guess_matched = new bool[leng];
  
  for (int a = 0 ; a < leng ; a++) { // initialize all entries to be false
    sec_matched[a] = 0;
    guess_matched[a] = 0;
  }
  
  int c = 0;
  for (int i = 0 ; i < leng ; i++) {
    for (int j = 0; j < leng ; j++) {
      if (guess_matched[i] || sec_matched[j]) {
        continue;
      }
      else if (sec[j] == guess[i]) {
        c++;
        sec_matched[j] = 1;
        guess_matched[i] = 1;
      }
    }
  }
  
  delete [] sec_matched;
  delete [] guess_matched;
  return c;
}

// this function increases the size of the dynamic array guesses[]
// guesses: the dynamic array guesses[]
// size: the current size of guesses
// increase: how much do you want the size of guesses[] to increase by
void grow_guesses(Guess * &guesses, int &size, int increase)
{
  if (guesses == NULL) return;
  
  int new_size = size + increase;
  Guess * tmp = new Guess [new_size];
  
  for (int i = 0 ; i < size ; i++) {
    tmp[i] = guesses[i];
  }
  delete [] guesses;
  guesses = tmp;
  size = new_size;
  
}


// main function
int main() {
  srand(time(NULL));
  // welcome message and introduction
  cout << "--------------------Welcome to Bulls and Cows!!--------------------" << endl;
  
  // choosing game mode
  cout << "Please indicate your preferred game mode:\n        1 Play with computer     2 Play with another person\n"
    << "Type \'1\' \'or \'2\': ";
  string mode;
  getline(cin, mode);
  while (mode!="1" && mode!="2") {
    cout << "Invalid mode. Please indicate the game mode by typing the number \'1\' or \'2\': ";
    getline(cin, mode);
  }
  
  if (mode == "1") cout << "\nYou may choose the no. of digits (1 to 20) of the secret number according to your desired difficulty.\n";
  else if (mode == "2") cout << "\nPlayer 1 please get ready! Now, please think of a secret number and its no. of digits.\n";
      
  
  // get the no. of digits of the secret number from user
  int leng;
  bool valid = 0;
  cout << "How many digits does the secret number contain? (1-20): ";
  while (!valid) {
    cin.clear();
    cin >> leng;
    if (cin.fail()) {
      cout << "Invalid input. The no. of digits should lie between 1 and 20. Please enter again: ";
    }
    else if (leng < 1 || leng > 20) {
      cout << "Invalid input. The no. of digits should lie between 1 and 20. Please enter again: ";
    }
    else valid = 1;
      
  }
    
  char * secnum = new char[leng+1];
   if (mode == "1") {
      for (int s = 0 ; s < leng ; s++) {
        secnum[s] = rand() % 10 + 48;
      }
      secnum[leng] = '\0';
      cout << "DEBUGGING S random gen: " << secnum << "DBE" << endl;
      cout << "Secret number generated!" << endl;
   }
   else if (mode == "2") {
     // For Player 1, who sets the secret number
     // get the secret number from user
     cout << "Please enter your secret number for Player 2 to guess: ";
     while (!getnum_in(secnum, leng)) {
       cout << "\nInvalid input. Your secret number should consists of exactly " << leng << " digits.\n"
         << "Please enter your secret number again: ";
     }
  
     // For Player 2, who guesses the secret number
     cout << ".\n.\n.\n.\n.\n.\n.\n.\n.\n.\n.\n.\n.\n.\n.\nPlayer 2, are you ready to guess? Let\'s start!\n"
       << "-----A kind reminder: don't scroll to the above to peep the secret number!!!-----\n";
   }
  
  // "guesses" stores the series of guess numbers by the player
  // the entry [0] is not used and the first trial is stored at index [1]
  
  int guesses_size = 21; // original size of guesses: stores at most 20 trials
  Guess * guesses = new Guess[guesses_size]; 
  bool won = 0;
  int trial = 0;
  
  // while the secret number is not guessed, ask the player to enter guess numbers repeatedly
  // IMPORTANT: guesses[0] is NOT used!! The information of the first trial is stored in guesses[1]
  while (!won) {
    // if the no. of trials of player exceeds the size where guesses[] can hold
    if (trial == guesses_size - 1) {
      cout << "\nYou have tried " << trial << " times already. Do you want to continue? [Y/N]: ";
      string choice;
      getline(cin, choice);
      while (choice!="Y" && choice!="N") {
        cout << "Invalid choice. Please state whether you want to continue. (Y for yes and N for No): ";
        getline(cin, choice);
      }

      if (choice == "N") {
        cout << "-----Sorry. You didn\'t get it. The secret number is " << secnum << ".-----"
        << "\n-----Add oil next time!-----" << endl;
        break;
      }
      
      else if (choice == "Y") {
        grow_guesses(guesses, guesses_size, 10);
        cout << "OK. You are granted 10 more trials. Keep it up!!" << endl;
      }
      
    }
    
    
    trial++;
    guesses[trial].gnum = new char[leng+1];
    cout << "\nPlease enter your guess: ";
    while (!getnum_in(guesses[trial].gnum, leng)) {
      cout << "Invalid guess. Your guess number should consists of exactly " << leng << " digits.\n"
       << "Please enter your guess number again: ";
    }
    guesses[trial].A = n_bulls(secnum, guesses[trial].gnum, leng);
    guesses[trial].B = n_cowsNbulls(secnum, guesses[trial].gnum, leng) - guesses[trial].A;
    
    // for determing to use "st" in 1st, 21st, etc.; "rd" in 3rd, 33rd, etc. or "th" in 5th, 6th, 11th, 12th, etc.
    string nth;
    switch (trial % 10) {
     case 1:
        if (trial % 100 == 11) nth = "th";
        else nth = "st";
        break;
     case 2:
        if (trial % 100 == 12) nth = "th";
        else nth = "nd";
        break;
     case 3:
        if (trial % 100 == 13) nth = "th";
        else nth = "rd";
        break;
     default: nth = "th";
    }
    
    cout << "Your " << trial << nth << " trial is" << ": " << guesses[trial].gnum
      << "     Result: " << guesses[trial].A << 'A' << guesses[trial].B << 'B' << endl;
    
    if (guesses[trial].A == 4) {
      cout << "-----Congratulations! You\'ve guessed it! The secret number is " << secnum << ".-----"
        << "\n-----You took " << trial << " trials to guess the correct number.-----" << endl;
      won = 1;
    }
    
  }
  cout << "See you again. Byebye!" << endl;
  
  
  for (int t = 1 ; t <= trial ; t++) {
    delete [] guesses[t].gnum;
  }
  delete [] secnum;
  return 0;
} 

C++ Online Compiler

Write, Run & Share C++ code online using OneCompiler's C++ online compiler for free. It's one of the robust, feature-rich online compilers for C++ language, running on the latest version 17. Getting started with the OneCompiler's C++ compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as C++ and start coding!

Read inputs from stdin

OneCompiler's C++ online compiler supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample program which takes name as input and print your name with hello.

#include <iostream>
#include <string>
using namespace std;

int main() 
{
    string name;
    cout << "Enter name:";
    getline (cin, name);
    cout << "Hello " << name;
    return 0;
}

About C++

C++ is a widely used middle-level programming language.

  • Supports different platforms like Windows, various Linux flavours, MacOS etc
  • C++ supports OOPS concepts like Inheritance, Polymorphism, Encapsulation and Abstraction.
  • Case-sensitive
  • C++ is a compiler based language
  • C++ supports structured programming language
  • C++ provides alot of inbuilt functions and also supports dynamic memory allocation.
  • Like C, C++ also allows you to play with memory using Pointers.

Syntax help

Loops

1. If-Else:

When ever you want to perform a set of operations based on a condition If-Else is used.

if(conditional-expression) {
   //code
}
else {
   //code
}

You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.

2. Switch:

Switch is an alternative to If-Else-If ladder.

switch(conditional-expression){    
case value1:    
 // code    
 break;  // optional  
case value2:    
 // code    
 break;  // optional  
......    
    
default:     
 code to be executed when all the above cases are not matched;    
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for(Initialization; Condition; Increment/decrement){  
  //code  
} 

4. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while (condition) {  
// code 
}  

5. Do-While:

Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.

do {  
 // code 
} while (condition); 

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity. Function gets run only when it is called.

How to declare a Function:

return_type function_name(parameters);

How to call a Function:

function_name (parameters)

How to define a Function:

return_type function_name(parameters) {  
 // code
}