/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2003 Pierre Delore
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "plugin.h"

#ifdef HAVE_LCD_CHARCELLS

/* NIM game for the player 

Rules of nim game
-----------------
There are 21 matches.
Two players (you and the cpu) alternately pick a certain number of matches and the one,
who takes the last match, loses.


History:
-------
V1.0 : 2003-07-22
    First release of the game
V1.1 : 2003-07-22
    I Change the patterns definition in order to have a clean code
V1.2 : 2003-07-30
    Patch from JB that change:
    . the win and lose message
    . the BUTTON_STOP code
    . Add a test
    I suppress the exit variable
    I suppress or translates the comments which were in French
    I put min=1 at the of the main loop ( When there are 21 matches you can decide not to
     take a match. Later you are obliged to take at least one.)
*/


/*Pattern for the game*/
static unsigned char smile[]={0x00, 0x11, 0x04, 0x04, 0x00, 0x11, 0x0E};    /* :-) */
static unsigned char cry[]  ={0x00, 0x11, 0x04, 0x04, 0x00, 0x0E, 0x11};    /* :-( */
static unsigned char pattern3[]={0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15}; /*3 parts*/
static unsigned char pattern2[]={0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}; /*2 parts*/
static unsigned char pattern1[]={0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}; /*1 part*/

static unsigned char str[12];   /*String use to display the first line*/
static unsigned char hsmile,hcry,h1,h2; /*Handle for the new pattern*/

static bool end;    /*If true game is finished*/
static struct plugin_api* rb;


/*Display that the action it's impossible*/
static void impossible(void)
{
    rb->lcd_puts(0,1,"Impossible!");
    rb->sleep(HZ);
    return;
}

/*Display that the CPU lose :) */
static void lose(void)
{
    rb->lcd_define_pattern(hsmile,smile);
    rb->snprintf(str,sizeof(str),"You Win!!%c",hsmile);
    rb->lcd_puts(0,1,str);
    end=true;
    rb->sleep(HZ*2);
    return;
}


/* Display that the CPU win :( */
static void win(void)
{
    rb->lcd_define_pattern(hcry,cry);
    rb->snprintf(str,sizeof(str),"You Lose!!%c",hcry);
    rb->lcd_puts(0,1,str);
    end=true;
    rb->sleep(HZ*2);
    return;
}


/*Display the first line*/
static void display_first_line(int x)
{
    int i;

    rb->snprintf(str,sizeof(str),"       =%d",x);

    rb->lcd_define_pattern(h1,pattern3);
    for(i=0;i<x/3;i++)
        str[i]=h1;

    if (x%3==2)
    {
        rb->lcd_define_pattern(h2,pattern2);
        str[i]=h2;
    }
    if (x%3==1)
    {
        rb->lcd_define_pattern(h2,pattern1);
        str[i]=h2;
    }
    rb->lcd_puts(0,0,str);
}

/* Call when the program end */
static void nim_exit(void)
{
    /*Restore the old pattern*/
    rb->lcd_unlock_pattern(h1);
    rb->lcd_unlock_pattern(h2);
    rb->lcd_unlock_pattern(hsmile);
    rb->lcd_unlock_pattern(hcry);

    /*Clear the screen*/
    rb->lcd_clear_display();
}

/* this is the plugin entry point */
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
    int y,z,button;
    int x,v,min;
    bool ok;
    bool go;

    /* this macro should be called as the first thing you do in the plugin.
       it test that the api version and model the plugin was compiled for
       matches the machine it is running on */
    TEST_PLUGIN_API(api);

    /* if you don't use the parameter, you can do like
       this to avoid the compiler warning about it */
    (void)parameter;

    /* if you are using a global api pointer, don't forget to copy it!
       otherwise you will get lovely "I04: IllInstr" errors... :-) */
    rb = api;

    /*Get the pattern handle*/
    h1=rb->lcd_get_locked_pattern();
    h2=rb->lcd_get_locked_pattern();
    hcry=rb->lcd_get_locked_pattern();
    hsmile=rb->lcd_get_locked_pattern();


    rb->splash(HZ, true, "NIM V1.2");
    rb->lcd_clear_display();

    /* Main loop */
    while (1)
    {
        /* Init */
        x=21;
        v=1;
        y=1;
        end=false;
        min=0;

        /*Empty the event queue*/
        while (rb->button_get(false)!=BUTTON_NONE);

        /* Game loop */
        while(end!=true)
        {
            do
            {
                ok=1;
                y=1;
                display_first_line(x);

                rb->snprintf(str,sizeof(str),"[%d..%d]?=%d",min,v,y);
                rb->lcd_puts(0,1,str);

                go=false;
                while (!go)
                {
                    button = rb->button_get(true);
                    switch ( button )
                    {
                        case BUTTON_STOP|BUTTON_REL:
                            go = true;
                            nim_exit();
                            return PLUGIN_OK;
                            break;

                        case BUTTON_PLAY|BUTTON_REL:
                            go=true;
                            break;

                        case BUTTON_LEFT|BUTTON_REL:
                            go=false;
                            if (y>min)
                                y--;
                            break;

                        case BUTTON_RIGHT|BUTTON_REL:
                            go=false;
                            if (y<v)
                                y++;
                            break;

                        case SYS_USB_CONNECTED:
                            rb->usb_screen();
                            nim_exit();
                            return PLUGIN_USB_CONNECTED;
                    }
                    display_first_line(x);
                    rb->snprintf(str,sizeof(str),"[%d..%d]?=%d",min,v,y);
                    rb->lcd_puts(0,1,str);
                }

                if ( (y==0) && (x<21))
                {
                    impossible();
                    ok=false;
                }
                else
                {
                    if (y!=0) /*If y=0 and x=21 jump to CPU code */
                    {
                        if ((y>v) || (y>x))
                        {
                            impossible();
                            ok=false;
                        }
                        if (y-x==0)
                            win();
                        else
                        {
                            v=y*2;
                            x-=y;
                        }
                    }
                }
            }
            while (ok==false);

            display_first_line(x);

            /*CPU*/
            if (x==1)
                lose();
            else
                if (x==2)
                    win();
            y=0;
            if (end==false)
            {
                for (z=v;z>=1;z--)
                {
                    if (x-z==1)
                        y=z;
                }
                if (y<=0)
                {
                    for(z=v;z>=1;z--)
                    {
                        if(x-(z*3)==2)
                            y=z;
                    }
                    if ((y==0) && (x>14))
                        y=v;
                    if (y==0)
                        y=1;
                }
                v=y*2;
                x-=y;
                rb->snprintf(str,sizeof(str),"I take=%d",y);
                rb->lcd_puts(0,1,str);
                rb->sleep(HZ);
            }
            if ((x==1)&&(!end))
                win();
            min=1;
        }
    }
    nim_exit();
    return PLUGIN_OK;
}
#endif
