#include <stdio.h>

#define SIZE_NUMBER 4
#define BOOLEAN     unsigned short
#define TRUE        1
#define FALSE       0
#define TEN         10
#define TWO         2
#define ONE         1
#define ZERO        0
#define MAX(x, y)   (x > y) ? x : y
#define MIN(x, y)   (x < y) ? x : y
#define ABS(x)      (x) * (((2 * (x)) + 1) % 2)


//---------------------------------------------------------------------------------------
//                                              Equality
//                                              --------
//
// General      : Checks whether two numbers are equal in value.
//
// Parameters   :  
//          number1 -  first number (int)
//          number2 -  second number (int)
//
// Return value : If there is an equality between the two numbers (BOOLEAN).
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
BOOLEAN Equality(int number1, int number2)
{
    BOOLEAN answer = (ONE / (ABS(number1 - number2) + ONE));
    return answer;
}

//---------------------------------------------------------------------------------------
//                                              NumBBiggerThenNumA
//                                              ------------------
//
// General      : Checks if the second number (B) is greater than the first number (A).
//
// Parameters   :  
//          number_a -  first number (int)
//          number_b -  second number (int)
//
// Return value : If the second number (B) is greater than the first number (A) (BOOLEAN).
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
BOOLEAN NumBBiggerThenNumA(int number_a, int number_b)
{
    int sub = number_a - number_b + ONE;
    BOOLEAN answer = (ONE / (ABS(sub) + (sub) + ONE));
    return answer;
}

//---------------------------------------------------------------------------------------
//                                CountADigitInNumber
//                                -------------------
//
// General      : Count the number of times her story appears in number.
//
// Parameters   :  
//          number - a number (int)
//          digit  - a digit (unsigned short)
//
// Return value : The number of times the number appears in the number (unsigned short)
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
unsigned short CountADigitInNumber(int number, unsigned short digit)
{
    int temp_num = number;
    unsigned count = FALSE;
    for (; temp_num; temp_num /= TEN)
    {
        count += Equality(temp_num % TEN, digit);
    }

    return (count);
    
}

//---------------------------------------------------------------------------------------
//                                              CountDigits
//                                              -----------
//
// General      : COunt digit in number.
//
// Parameters   :  
//          num - first number (int)
//
// Return value : Number of digits count in a number.
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 26.09.2019
//---------------------------------------------------------------------------------------
unsigned short CountDigits(int num)
{
    unsigned short count;
    for (count = ZERO; num; num /= TEN, count++);
    
    return (count);
}

//---------------------------------------------------------------------------------------
//                                ForeignDigits
//                                -------------
//
// General      : Checks whether all digits are foreign to each other by number.
//
// Parameters   :  
//          number - first number (int)
//
// Return value : If all the numbers are foreign to each other in number (BOOLEAN)
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
BOOLEAN ForeignDigits(int number)
{
    int temp_num = number;
    BOOLEAN answer = TRUE;
    for (; temp_num; temp_num /= TEN)
    {
        answer *= NumBBiggerThenNumA(CountADigitInNumber(temp_num, temp_num % TEN), TWO);
    }
    
    return (answer);
}

//---------------------------------------------------------------------------------------
//                                CountOfIdenticalDigitsInSomeIndex
//                                ---------------------------------
//
// General      : Count the number of times there are identical digits between 
//                two numbers and in the same location.
//
// Parameters   :  
//          number1 - first number (int)
//          number2 - second number (int)
//
// Return value : The number of times there are identical 
//                digits between two numbers and in the same location (unsigned short)
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
unsigned short CountOfIdenticalDigitsInSomeIndex(int number1, int number2)
{
    int temp_num1,
        temp_num2;
    unsigned short count = ZERO;
    for (temp_num1 = MIN(number1, number2), temp_num2 = MAX(number1, number2);
            temp_num1;
            temp_num1 /= TEN, temp_num2 /= TEN)
    {
        count += Equality(temp_num1 % TEN, temp_num2 % TEN);
    }

    return (count);
}

//---------------------------------------------------------------------------------------
//                                CountOfIdenticalDigits
//                                ----------------------
//
// General      : Count the number of times there are identical digits
//                between two numbers.
//
// Parameters   :  
//          number1 - first number (int)
//          number2 - second number (int)
//
// Return value : The number of times there are identical digits
//                between two numbers (unsigned short)
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
unsigned short CountOfIdenticalDigits(int number1, int number2)
{
    int temp_num1,
        temp_num2;
    unsigned short count = ZERO,
                    digit_num1;
    for (temp_num1 = number1; temp_num1; temp_num1 /= TEN)
    {   
        digit_num1 = temp_num1 % TEN;
        for (temp_num2 = number2; temp_num2; temp_num2 /= TEN)
        {
            count += Equality(digit_num1, temp_num2 % TEN);
        }
        temp_num2 = number2;
    }

    return (count);
}

//---------------------------------------------------------------------------------------
//                                              ChangeBool
//                                              ----------
//
// General      : Boolean variable inverse.
//
// Parameters   :  
//          bool1 -  Boolean variable (BOOLEAN)
//
// Return value : Boolean variable (BOOLEAN).
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 21.10.2019
//---------------------------------------------------------------------------------------
BOOLEAN ChangeBool(BOOLEAN bool1)
{
    BOOLEAN answer = ++bool1 % TWO;
    return answer;
}

//---------------------------------------------------------------------------------------
//                                              Game Bullseye
//                                              -------------
//
// General : There are two contestants. Each contestant chooses an integer
//           of 4 digits without declaring it
//           The number consists of foreign literature to each other.
//           Each participant is supposed to guess the number chosen by his or
//           her member in minimum steps.
//           For each guess, the contestant will receive a response according to
//           the following rules:
//           If you guess a book exists in a selected number and is not in its exact
//           location - this is an injury
//           If you guess a book exists in a number but not in its
//           exact location - it's a bullet.
//
// Input   : Two numbers with 4 digits and Foreign digits.
//
// Process : The program receives two numbers per number, it checks their correctness.
//           If the number is foreign and has 4 digits. 
//           The program then enters the loop where it stops only when one of the
//           players manages to reach four hits.
//           The program checks the accuracy of each player's guess.
//           The program then checks to see if the number has vulnerabilities and
//           projectiles with its opponent's number.
//           The program prints the player's results and moves to the next 
//           player's queue. If one of the players wins the program comes
//           out of the loop and announces the winner
//
// Output  : Who wins.
//
//---------------------------------------------------------------------------------------
// Programmer : Cohen Idan
// Student No : 211675038
// Date       : 23.10.2019
//---------------------------------------------------------------------------------------
void main(void) 
{
    unsigned short player1_number   = ZERO,
                    player2_number  = ZERO,
                    check_number,
                    damage,
                    projectiles,
                    guess_number,
                    guessing_amount = ZERO;
    BOOLEAN is_player1;
    
    // Checking the correctness of the input (4 digits, foreign digits) for player1
    while ((CountDigits(player1_number) - SIZE_NUMBER) + !ForeignDigits(player1_number))
    {
        printf("Player 1 : : Enter number with foreign digits and 4 digits: ");
        scanf("%hu", &player1_number);
    }

    // Checking the correctness of the input (4 digits, foreign digits) for player2
    while ((CountDigits(player2_number) - SIZE_NUMBER) + !ForeignDigits(player2_number))
    {
        printf("Player 2 : : Enter number with foreign digits and 4 digits: ");
        scanf("%hu", &player2_number);
    }

    // First player starts his turn
    is_player1 = TRUE;

    // As long as the vulnerability is not 4, the loop is running
    while (!Equality(damage, SIZE_NUMBER))
    {
        damage = ZERO;
        projectiles = ZERO;

        // Checks that the correctness of the guess input is 4 digits
        while (CountDigits(guess_number) - SIZE_NUMBER)
        {
            printf("Player ");
            if (is_player1)
            {
                printf("1");
                guessing_amount++;
            }
            else
                printf("2");
            printf(" : : Enter your guess: ");
            scanf("%hu", &guess_number);
        }

        // Checks the guess based on the player's turn
        check_number = (!is_player1) ? player1_number : player2_number;

        // Checks the amount of vulnerability
        damage = CountOfIdenticalDigitsInSomeIndex(check_number, guess_number);

        // Checking the amount of projectiles 
        projectiles = CountOfIdenticalDigits(check_number, guess_number) - damage;
        
        printf("Damage: %hu\nTarget Shooting: %hu\n\n", damage, projectiles);
        guess_number = ZERO;

        // Changing the turn of the player to the next player
        is_player1 = ChangeBool(is_player1);
    }
    printf("The winner is \"Player ");
    if (!is_player1)
        printf("1");
    else
        printf("2");
    printf("\" with %hd guesses!\n", guessing_amount);
}