/***************************************************************************
 *   Copyright (C) 2002-2003 Andi Peredri                                  *
 *   andi@ukr.net                                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
//
// KCheckers Engine

//
// Internal:                 External:
//
// Board = 54 Fields:        Board = 32 Fields:
//
// |  06  07  08  09|  MAN2  |  00  01  02  03|
// |11  12  13  14  |        |04  05  06  07  |
// |  17  18  19  20|        |  08  09  10  11|
// |22  23  24  25  |        |12  13  14  15  |
// |  28  29  30  31|        |  16  17  18  19|
// |33  34  35  36  |        |20  21  22  23  |
// |  39  40  41  42|        |  24  25  26  27|
// |44  45  46  47  |  MAN1  |28  29  30  31  |

#include <time.h>
#include <stdlib.h>

#include <QDebug>

#include "checkers.h"


int Checkers::internal(int external) const
{
    const int i[]={6,7,8,9,11,12,13,14,17,18,19,20,22,23,24,25,
                   28,29,30,31,33,34,35,36,39,40,41,42,44,45,46,47};
    return i[external];
}


/*
int Checkers::external(int internal) const
{
    const int i[]={
	-1,-1,-1,-1,-1,-1,0,1,2,3,		// 0-9 internal
	-1,4,5,6,7,-1,-1,8,9,10,		// 10-19
	11,-1,12,13,14,15,-1,-1,16,17,		// 20-29
	18,19,-1,20,21,22,23,-1,-1,24,		// 30-39
	25,26,27,-1,28,29,30,31,-1,-1,		// 40-49
	-1,-1,-1,-1};				// 50-53
    return i[internal];
}
*/


Checkers::Checkers()
{
    for(int i=0;i<54;i++) board[i] = NONE;

    for(int i=0;  i<12; i++) board[internal(i)] = MAN2;
    for(int i=12; i<20; i++) board[internal(i)] = FREE;
    for(int i=20; i<32; i++) board[internal(i)] = MAN1;

    levelmax = 2;

    srand(time(0)); // Seed the random number generator
}


bool Checkers::setup(int setupboard[])
{
    /*aw - caused problems
    int sum1=0;      // Sum of MAN1 & KING1
    int sum2=0;      // Sum of MAN2 & KING2

    for(int i=0; i<32; i++) {
	switch(setupboard[i]) {
	case MAN1:
	case KING1: sum1++; break;
        case MAN2:
	case KING2: sum2++; break;

	case FREE:  break;

	default:    return false;
	}
    }

    if(sum1>12 || sum1==0 || sum2>12 || sum2==0)
	return false;

    for(int i=0; i<4; i++)
        if(setupboard[i]==MAN1) return false;

    for(int i=28; i<32; i++)
	if(setupboard[i]==MAN2) return false;
    */

    for(int i=0; i<32; i++)
	board[internal(i)] = setupboard[i];

    return true;
}


///////////////////////////////////////////////////
//
//  Player Functions
//
///////////////////////////////////////////////////


bool Checkers::checkMove1() const
{
    for(int i=6;i<48;i++)
	if(checkMove1(i))
	    return true;
    return false;
}


bool Checkers::checkMove1(int i) const
{
    switch(board[i]) {
    case MAN1:
	if(board[i-6]==FREE) return true;
	if(board[i-5]==FREE) return true;
	break;
    case KING1:
	if(board[i-6]==FREE) return true;
	if(board[i-5]==FREE) return true;
	if(board[i+5]==FREE) return true;
	if(board[i+6]==FREE) return true;
    }
    return false;
}


////////////////////////////////////////////////////
//
// Computer Functions
//
////////////////////////////////////////////////////


void Checkers::go2()
{
    //
    level=0;
    for(int i=6;i<48;i++)
	bestboard[i] = board[i];
    turn();
    for(int i=6;i<48;i++)
	board[i] = bestboard[i];
    ;
}


void Checkers::turn(int& resMax, bool capture)
{
    if(level<levelmax) {
        bool f12, f13, f14, f17, f18, f19, f23, f24, f25;
	bool f28, f29, f30, f34, f35, f36, f39, f40, f41;
        f12 = f13 = f14 = f17 = f18 = f19 = f23 = f24 = f25 = false;//for gcc
	f28 = f29 = f30 = f34 = f35 = f36 = f39 = f40 = f41 = false;//for gcc
	    
        if(capture) {
            if(board[12]==NONE) {f12=true; board[12] = FREE;} else f12=false;
            if(board[13]==NONE) {f13=true; board[13] = FREE;} else f13=false;
            if(board[14]==NONE) {f14=true; board[14] = FREE;} else f14=false;
            if(board[17]==NONE) {f17=true; board[17] = FREE;} else f17=false;
            if(board[18]==NONE) {f18=true; board[18] = FREE;} else f18=false;
            if(board[19]==NONE) {f19=true; board[19] = FREE;} else f19=false;
            if(board[23]==NONE) {f23=true; board[23] = FREE;} else f23=false;
            if(board[24]==NONE) {f24=true; board[24] = FREE;} else f24=false;
            if(board[25]==NONE) {f25=true; board[25] = FREE;} else f25=false;
            if(board[28]==NONE) {f28=true; board[28] = FREE;} else f28=false;
            if(board[29]==NONE) {f29=true; board[29] = FREE;} else f29=false;
            if(board[30]==NONE) {f30=true; board[30] = FREE;} else f30=false;
            if(board[34]==NONE) {f34=true; board[34] = FREE;} else f34=false;
            if(board[35]==NONE) {f35=true; board[35] = FREE;} else f35=false;
            if(board[36]==NONE) {f36=true; board[36] = FREE;} else f36=false;
            if(board[39]==NONE) {f39=true; board[39] = FREE;} else f39=false;
            if(board[40]==NONE) {f40=true; board[40] = FREE;} else f40=false;
            if(board[41]==NONE) {f41=true; board[41] = FREE;} else f41=false;
        }

        int b6=board[6];
        int b7=board[7];
        int b8=board[8];
        int b9=board[9];
        int b11=board[11];
        int b12=board[12];
        int b13=board[13];
        int b14=board[14];
        int b17=board[17];
        int b18=board[18];
        int b19=board[19];
        int b20=board[20];
        int b22=board[22];
        int b23=board[23];
        int b24=board[24];
        int b25=board[25];
        int b28=board[28];
        int b29=board[29];
        int b30=board[30];
        int b31=board[31];
        int b33=board[33];
        int b34=board[34];
        int b35=board[35];
        int b36=board[36];
        int b39=board[39];
        int b40=board[40];
        int b41=board[41];
        int b42=board[42];
        int b44=board[44];
        int b45=board[45];
        int b46=board[46];
        int b47=board[47];

        board[6]=FULL-b47;
        board[7]=FULL-b46;
        board[8]=FULL-b45;
        board[9]=FULL-b44;
        board[11]=FULL-b42;
        board[12]=FULL-b41;
        board[13]=FULL-b40;
        board[14]=FULL-b39;
        board[17]=FULL-b36;
        board[18]=FULL-b35;
        board[19]=FULL-b34;
        board[20]=FULL-b33;
        board[22]=FULL-b31;
        board[23]=FULL-b30;
        board[24]=FULL-b29;
        board[25]=FULL-b28;
        board[28]=FULL-b25;
        board[29]=FULL-b24;
        board[30]=FULL-b23;
        board[31]=FULL-b22;
        board[33]=FULL-b20;
        board[34]=FULL-b19;
        board[35]=FULL-b18;
        board[36]=FULL-b17;
        board[39]=FULL-b14;
        board[40]=FULL-b13;
        board[41]=FULL-b12;
        board[42]=FULL-b11;
        board[44]=FULL-b9;
        board[45]=FULL-b8;
        board[46]=FULL-b7;
        board[47]=FULL-b6;

        int res=-turn();

        board[6]=b6;
        board[7]=b7;
        board[8]=b8;
        board[9]=b9;
        board[11]=b11;
        board[12]=b12;
        board[13]=b13;
        board[14]=b14;
        board[17]=b17;
        board[18]=b18;
        board[19]=b19;
        board[20]=b20;
        board[22]=b22;
        board[23]=b23;
        board[24]=b24;
        board[25]=b25;
        board[28]=b28;
        board[29]=b29;
        board[30]=b30;
        board[31]=b31;
        board[33]=b33;
        board[34]=b34;
        board[35]=b35;
        board[36]=b36;
        board[39]=b39;
        board[40]=b40;
        board[41]=b41;
        board[42]=b42;
        board[44]=b44;
        board[45]=b45;
        board[46]=b46;
        board[47]=b47;

        if(res>resMax) {
            resMax=res;
            if(level==1) {
                for(int i=6;i<48;i++) bestboard[i]=board[i];
                bestcounter=1;
            }
        } else if(res==resMax && level==1) {
            bestcounter++;
            if((rand()%bestcounter)==0) {
                for(int i=6;i<48;i++) bestboard[i]=board[i];
            }
        }

        if(capture) {
            if(f12) board[12]=NONE;
            if(f13) board[13]=NONE;
            if(f14) board[14]=NONE;
            if(f17) board[17]=NONE;
            if(f18) board[18]=NONE;
            if(f19) board[19]=NONE;
            if(f23) board[23]=NONE;
            if(f24) board[24]=NONE;
            if(f25) board[25]=NONE;
            if(f28) board[28]=NONE;
            if(f29) board[29]=NONE;
            if(f30) board[30]=NONE;
            if(f34) board[34]=NONE;
            if(f35) board[35]=NONE;
            if(f36) board[36]=NONE;
            if(f39) board[39]=NONE;
            if(f40) board[40]=NONE;
            if(f41) board[41]=NONE;
        }
    }
    else if(resMax<0) resMax=0;
}


bool Checkers::checkMove2() const
{
    for(int i=6;i<48;i++) {
        switch(board[i]) {
        case MAN2:
            if(board[i+5]==FREE) return true;
            if(board[i+6]==FREE) return true;
            break;
        case KING2:
            if(board[i-6]==FREE) return true;
            if(board[i-5]==FREE) return true;
            if(board[i+5]==FREE) return true;
            if(board[i+6]==FREE) return true;
        }
    }
    return false;
}


int Checkers::turn()
{
    int resMax=(level-levelmax)*10;
    level++;

    if(checkCapture2()) {
        for(int i=6; i<48; i++) {
            switch(board[i]) {
            case MAN2:
                manCapture2(i, resMax);
                break;
            case KING2:
                kingCapture2(i,UL,resMax);
                kingCapture2(i,UR,resMax);
                kingCapture2(i,DL,resMax);
                kingCapture2(i,DR,resMax);
            }
        }

    } else if(checkMove2()) {
        for(int i=6;i<48;i++) {
            switch(board[i]) {
            case MAN2:
                if(board[i+5]==FREE) {	// down left
                    board[i]=FREE;
                    if(i>38)
			board[i+5]=KING2;
                    else
			board[i+5]=MAN2;
                    turn(resMax);
                    board[i+5]=FREE;
                    board[i]=MAN2;
                }
                if(board[i+6]==FREE) {	// down right
                    board[i]=FREE;
                    if(i>38)
			board[i+6]=KING2;
                    else
			board[i+6]=MAN2;
                    turn(resMax);
                    board[i+6]=FREE;
                    board[i]=MAN2;
                }
                break;
            case KING2:
                kingMove2(i,resMax);
                break;
            }
        }

    } else ;

    level--;
    return resMax;
}


QString Checkers::toString(bool rotate) const
{
    int fields[32];
    int it;

    for(int i=0; i<32; i++) {
	it = item(i);
	if(rotate)
	    fields[31-i] = (~it&7)-1;
	else
	    fields[i] = it;
    }

    QString str;
    for(int i=0; i<32; i++)
  	str += QString("").sprintf("%.2u", fields[i]);

    return str;
}


bool Checkers::fromString(const QString& str)
{
    int fields[32];

    for(int i=0; i<32; i++)
	fields[i] = str.mid(i*2, 2).toInt();

    // apply
    if(!setup(fields)) {
	qDebug() << "Checkers::fromString:" << str;
	return false;
    }

    return true;
}