#include <stdlib.h>
#include  <string.h>
#include "util.h"
#include "ptable.h"
#include "board.h"


ptable_t PTable[1];

void PTableInit(ptable_t *ptable){
    ptable->PawnTab[0]=NULL;
    ptable->PawnTab[1]=NULL;
    ptable->Size=0;
    ptable->PHashMask=0;
    PTableResetStats(ptable);
}

void PTableClear(ptable_t *ptable){
    if(ptable->PawnTab[0]!=NULL){
	free(ptable->PawnTab[0]);
    }
    if(ptable->PawnTab[1]!=NULL){
	free(ptable->PawnTab[1]);
    }
    ptable->PawnTab[0]=NULL;
    ptable->PawnTab[1]=NULL;
}

void PTableZero (ptable_t *ptable){
    memset (ptable->PawnTab[white], 0, ptable->Size * sizeof (ptable_slot_t)/2);
    memset (ptable->PawnTab[black], 0, ptable->Size * sizeof (ptable_slot_t)/2);
}


void PTableResetStats(ptable_t *ptable){
    ptable->TotalPawnHashCnt = 0;
    ptable->GoodPawnHashCnt = 0;
}

void PTableSetSize(ptable_t *ptable, unsigned int size){
    unsigned int psize,i;
    PTableClear(ptable);
    i = (size < PAWNSLOTS ? PAWNSLOTS : size)/2;
    ptable->PHashMask = 0;
    while ((i>>=1) > 0)	{
	ptable->PHashMask <<= 1;
	ptable->PHashMask |= 1;
    }
    ptable->Size = 2*(ptable->PHashMask+1);
    ptable->PawnTab[0] = (ptable_slot_t *) malloc (ptable->Size * sizeof (ptable_slot_t)/2);
    ptable->PawnTab[1] = (ptable_slot_t *) malloc (ptable->Size * sizeof (ptable_slot_t)/2);
    if (ptable->PawnTab[0] == NULL || ptable->PawnTab[1] == NULL) {
	OutputConsole("Not enough memory for pawn table, goodbye.\n");
	exit(EXIT_FAILURE);
    } else {
	psize = (ptable->Size *sizeof (ptable_slot_t)) >> 10;
    }

    OutputConsole("Pawn hash table: Entries=%dK Size=%dK\n",
		 ptable->Size  >> 10, psize);
    

}

void PTableSetSizeMb(ptable_t *ptable, unsigned int size){
    int slotsize;
    slotsize=(1048576*size)/(sizeof(ptable_slot_t));
    PTableSetSize(ptable,slotsize);
}

int PTableGet(ptable_t *ptable, 
	      board_t *board, 
	      int side,
	      BitBoard *passed, 
	      BitBoard *weaked, 
	      int *score, 
	      int *phase){
    ptable_slot_t *p;
    ptable->TotalPawnHashCnt++;
    p=ptable->PawnTab[side] + (board->PawnHashKey & ptable->PHashMask);
    if (p->phase == board->phase && p->pkey == KEY(board->PawnHashKey)){
	ptable->GoodPawnHashCnt++;
	*passed=p->passed;
	*weaked=p->weaked;
	*score=p->score;
	*phase=p->phase;
	return true;
    }
    return false;
}


void PTablePut(ptable_t *ptable,
	       board_t *board,  	      
	       int side,
	       BitBoard passed, 
	       BitBoard weaked, 
	       int score, 
	       int phase){
    ptable_slot_t *p;
    p=ptable->PawnTab[side] + (board->PawnHashKey & ptable->PHashMask);
    p->pkey = KEY(board->PawnHashKey);
    p->passed = passed;
    p->weaked = weaked;
    p->score = score;
    p->phase = phase;
}

void PTableStatsShow(ptable_t *ptable){
    OutputConsole("PHash: Get=%uk Good=%2.0f%%\n",
		  ptable->TotalPawnHashCnt/1000,
		  100*((double) ptable->GoodPawnHashCnt)/((double) ptable->TotalPawnHashCnt));
}
