/*
 * Author: Jan So
 * Originally created for Loraine Lacap of Mapua Institute of Technolgy
 * for Demo Purposes
 * */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>
#include <dos.h>

/******************************************************************************
 *  various definitions
 *****************************************************************************/
#define SMALL_A 97
#define DWORD unsigned long 
#define TRUE 1
#define FALSE 0
#define MAX_LEVEL 10
#define MAX_ERROR 4

// modify this if you're gonna add some items to be guessed
#define ASKED_ITEMS 6

#define WIN 1
#define LOSE 0
#define STARTED 2

/******************************************************************************
 *  letter equivalent when represented,using 26 bits. call this the alpha code
 *****************************************************************************/
#define A 1
#define B 2
#define C 4
#define D 8
#define E 16
#define F 32
#define G 64
#define H 128
#define I 256
#define J 512
#define K 1024
#define L 2048
#define M 4096
#define N 8192
#define O 16384
#define P 32768
#define Q 65536
#define R 131072
#define S 262144
#define T 524288
#define U 1048576
#define V 2097152
#define W 4194304
#define X 8388608
#define Y 16777216
#define Z 33554432
#define COMPLETE_ALPHABET 0x3FFFFFF


/******************************************************************************
 *  this is the hangaroo class
 *****************************************************************************/
class Hangaroo
{
    private:
        int exist;    
        int errors;
        int game_status;
        int level;
        DWORD alpha_code;
        DWORD guess_code;
        char guess_words_str[50];
        char clue[50];
        char unknown[50];
        int gw_length;
        char display_answered[50];
        DWORD key_in;
        int xv;

        int lower_case(int letter);
        int get_letters_index(int letter);
        DWORD letter_exist(DWORD sentinel);
        DWORD letter_exist_in_words(DWORD sentinel);
        void decide_outcome();
        void display_errors();
        DWORD display_letters();
        void display_clue();
        void get_guess_code();
        void display_guessed_letter();
        void intro();
    void messages(int mode);
    public:    
        void play_hangaroo();
        Hangaroo();
};

/******************************************************************************
 *  this is the constructor. automatic initialization
 *****************************************************************************/
Hangaroo::Hangaroo()
{
    char *game_data[ASKED_ITEMS][2] = {{"phrase"   , "nobody is perfect!"},
                                       {"movie"    , "lord of the rings"},
                                       {"country"  , "philippines" },
                                       {"movie"    , "final destination"},
                                       {"inventor" , "hidetsugu yagi and shintaro uda"},
                                       {"scientist", "einstein"}
    };
    int item_index;
    time_t t;

    errors = 0;
    alpha_code = COMPLETE_ALPHABET;
    guess_code = 0;
    level = 0;
    game_status = STARTED;
    memset(guess_words_str, 0, sizeof(guess_words_str));
    memset(clue, 0, sizeof(clue));
    memset(unknown, 0, sizeof(unknown));
    memset(display_answered, 0, sizeof(display_answered));

    xv = 12;
    srand((unsigned)time(&t));
    //    item_index = rand() % (sizeof(game_data)/8);
    item_index = rand() % ASKED_ITEMS;
    strcpy(clue,    game_data[item_index][0]);
    strcpy(unknown, game_data[item_index][1]);

    strcpy(guess_words_str, unknown);
    strcpy(display_answered, unknown);
    strset(display_answered, ' ');
    gw_length = strlen(unknown);
};

/******************************************************************************
 *  display_clue
 *      obviously it displays the clue
 *****************************************************************************/
void Hangaroo::display_clue()
{
    int length;

    length = strlen(clue) + 9;
    gotoxy((80 - length)/2, 7);
    textcolor(WHITE);
    cprintf("= clue: %s =", clue);
}
/******************************************************************************
 *  lower_case
 *      converts a letter to lowercase
 *****************************************************************************/
int Hangaroo::lower_case(int letter)
{
    if(letter >= 65 && 90 >= letter)
    {
        letter += 32;
    }
    else if(letter >= 97 && 122 >= letter)
    {
        return letter;
    }
    else
    {
        letter = 0;
    }
    return letter;
}

/******************************************************************************
 *  get_letters_index
 *      gets the letters equivalent if represented by numbers (a=1,b=2,..)
 *****************************************************************************/
int Hangaroo::get_letters_index(int letter)
{
    int index;

    if(letter >= 65 && 90 >= letter)
    {
        index = (letter - 65) + 1;
    }
    else if(letter >= 97 && 122 >= letter)
    {
        index = (letter - 97) + 1;
    }
    else
    {
        letter = 0;
    }
    return index;
}

void Hangaroo::display_guessed_letter()
{
    int index;
    int length;
    char c;

    for(index = 0; index < gw_length; index++)
    {
        c = unknown[index];
        if(c == key_in)
        {
            //            printf("%c", unknown[index]);
            display_answered[index] = c;
        }
        else if(!isalpha(c) && !isspace(c))
        {
            //            printf("%c", c);
            display_answered[index] = c;
            //          
        }
        else if(c != key_in && isalpha(c))
        {
            if(display_answered[index] == ' ')
            {
                display_answered[index] = '°';
            }
        }

    }
    length = strlen(unknown) + 4;
    gotoxy((80 - length) / 2, 10);
    printf("[ %s ]", display_answered);
}

/******************************************************************************
 *  letter_exist     
 *      checks the alpha code if the specified letter is available, which is 
 *      represented by the sentinel, is available.
 *****************************************************************************/
DWORD Hangaroo::letter_exist(DWORD sentinel)
{
    DWORD bit;
    DWORD result;

    result = alpha_code & ((DWORD)1 << (sentinel - 1));
    bit = (DWORD)result >> (sentinel - 1);
    if(bit == 1)
    {
        return 1;
    }
    return 0;
}

DWORD Hangaroo::letter_exist_in_words(DWORD sentinel)
{
    DWORD bit;
    DWORD result;

    result = guess_code & ((DWORD)1 << (sentinel - 1));
    bit = (DWORD)result >> (sentinel - 1);
    if(bit == 1)
    {
        return 1;
    }
    return 0;
}

DWORD Hangaroo::display_letters()
{
    DWORD index;
    DWORD result;
    DWORD bit;

    for(index = 0; index < 26; index++)
    {
        bit = letter_exist(index + 1);
        if(bit == 1)
        {
            gotoxy(xv+=2, 8);
            textcolor(GREEN);
            cprintf("%c ", SMALL_A + index);
        }
        else
        {
            gotoxy(xv+=2, 8);
            textcolor(DARKGRAY);
            cprintf("%c ", SMALL_A + index);
        }
    }
    textcolor(WHITE);
    gotoxy(10, 14);
    cprintf("You     : ");
    textcolor(YELLOW);
    key_in = getch();
    xv = 12;
    key_in = lower_case(key_in);
    if(key_in != 0)
    {
        if(letter_exist(get_letters_index(key_in)) == 1)
        {
            bit = get_letters_index(key_in) - 1;
            alpha_code ^= ((DWORD)1 << bit);
            if(letter_exist_in_words(get_letters_index(key_in)) == 1)
            {
                bit = get_letters_index(key_in) - 1;
                guess_code ^= ((DWORD)1 << bit);
                if(guess_code == 0)
                {
                    game_status = WIN;
        }
        messages(1);
        }
        else
        {
        errors++;
        messages(0);
                display_errors();
                if(errors >= 4)
                {
                    game_status = LOSE;
                }
            }
        }
    }
    return alpha_code;
}

void Hangaroo::play_hangaroo()
{
    intro();
    get_guess_code();
    while(game_status == STARTED)
    {
        display_clue();
        display_guessed_letter();
        display_letters();
    }
    display_guessed_letter();
    decide_outcome();
}

void Hangaroo::intro()
{
    int length;
    int index;
    char *intr_text[2] = {{"NO KANGAROOS WERE HARMED IN THE MAKING OF THIS GAME"},
                          {"H A N G A R O O"}};
        clrscr();
        length = strlen(intr_text[0]);

        gotoxy((80 - length)/2, 13);
        textcolor(DARKGRAY);
        cprintf("%s", intr_text[0]);
        sleep(1);

        gotoxy((80 - length)/2, 13);
        textcolor(LIGHTGRAY);
        cprintf("%s", intr_text[0]);
        sleep(1);

        gotoxy((80 - length)/2, 13);
        textcolor(WHITE);
        cprintf("%s", intr_text[0]);
        sleep(1);

        length = strlen(intr_text[1]);
        clrscr();
        gotoxy((80 - length)/2, 13);
        textcolor(WHITE);
        cprintf("%s", intr_text[1]);
        sleep(1);

        clrscr();
}

void Hangaroo::decide_outcome()
{
    char *end_msgs[2] = {{"You Won! I owe you man!"},
             {"<gasp> AKKKKKkkkkkk!!!"}};
    int length;

    textcolor(CYAN|BLINK);
    if(game_status == WIN)
    {
    length = strlen(end_msgs[0]);
    gotoxy((80 - length)/2, 17);
    cprintf(end_msgs[0]);
    level++;
    }
    else if(game_status == LOSE)
    {
    length = strlen(end_msgs[0]);
    gotoxy((80 - length)/2, 17);
    cprintf(end_msgs[1]);
    }
}

void Hangaroo::get_guess_code()
{
    int length;
    int index;
    char *status;
    char tmp_str[3];
    DWORD bits;

    for(index = 0; index < 26; index++)
    {
        memset(tmp_str, 0, sizeof(tmp_str));
        sprintf(tmp_str, "%c",  index+97);
        if(strstr(guess_words_str, tmp_str))
        {
            bits = ((DWORD)1 << index);
            guess_code |= bits;
        }
    }
}

void Hangaroo::messages(int mode)
{
    char *kangaroo_msgs[4][2] = {{"Oh Boy!        ", "Yeah!          "},
                                 {"I am SO dead!  ", "OH Yeah!       "},
                                 {"Use your brain!", "Perfect!       "},
                                 {"Damn ^$%^@!    ", "You're the man!"}
    };
    int msg_index;
    time_t t;
    
    srand((unsigned)time(&t));
    msg_index = rand() % 4;
    gotoxy(10, 15);
    textcolor(WHITE);
    cprintf("Kangaroo: ");
    gotoxy(20, 15);
    textcolor(YELLOW);
    cprintf("%s", kangaroo_msgs[msg_index][mode]);
}

void Hangaroo::display_errors()
{
    int index;

    for(index = 0; index < MAX_ERROR; index++)
    {
        gotoxy(55 + index * 2, 3);
        if(index < errors)
        {
            textcolor(RED);
        }
        else
        {
            textcolor(DARKGRAY);
        }
        cprintf("X ");
    }
    if(errors >= 1)
    {
        sound(880); // A octave in hertz
        delay(500);
        nosound();
    }
}


int main()
{
    Hangaroo hangaroo;

    hangaroo.play_hangaroo();

    //    clrscr();
    getch();
    return 0;
}

