#include "scr_LocalServer.h"

extern scr_LocalServer *TheGame;

scr_CPlayer::scr_CPlayer(int numtiles, char* namein, scr_Board* Board, scr_Dictionary* Diction){
char a;
int x,y,z;
 TheBoard=Board;
 Dictionary=Diction;
 x=TheBoard->GetXBoardSize()+1;
 y=TheBoard->GetYBoardSize()+1;
 z=TheBoard->GetZBoardSize()+1;
 bounds.point[0]=(x-1);
 bounds.point[1]=(y-1);
 bounds.point[2]=(z-1);
 TILENUM=numtiles;
 tiles = new unsigned long int[TILENUM];
 score=0;
 for(a=0;namein[a];a++) name[a]=namein[a]; name[a]=0;
 for(a=0;a<TILENUM;a++) tiles[a]=0;
}

scr_CPlayer::~scr_CPlayer(){
int count;
 for(count=1; count<16; count++) delete [] Moves[count];
 delete [] tiles;
}

int scr_CPlayer::WakeUp(){
 return 1;
}

int scr_CPlayer::Update(scr_Move* move, char* result){
 return 1;
}

int scr_CPlayer::InformFinalScores(int* scores){
 return 1;
}

int scr_CPlayer::InformInitialStats(int numplayers){
 return 1;
}

int scr_CPlayer::Run(){
int x,y,z,numtiles;
char c,d=0;
unsigned long int combo=0;
scr_Move *TheMove;

 numtiles=NumTiles();
 curscore=0;
 for(x=0; x<16; x++) total[x]=0;

 for(x=0; x<TILENUM; x++)
  for(y=x+1; y<TILENUM; y++){
   if(tiles[x]>tiles[y]){
    combo=tiles[x];
    tiles[x]=tiles[y];
    tiles[y]=combo;
   }
  }
 combo=0;

 for(x=0; x<TILENUM; x++) combo|=tiles[x];
  
 for(x=0; x<TheBoard->GetXBoardSize(); x++){
  if(TheBoard->GetZBoardSize()>1){
  for(y=0; y<TheBoard->GetYBoardSize(); y++){
   for(z=TheBoard->GetZBoardSize()-1, c=0,d=0; z>-1; z--){
    if(combo&TheBoard->Flags(x,y,z,0)&TheBoard->Flags(x,y,z,1)){
     if(TheBoard->Adjacent(x,y,z)&4) c=d=0;
     else 
      if(TheBoard->Adjacent(x,y,z)&59){
       c=numtiles;
       d=0;
      }
     if(c){
      c--;
      Gather(x,y,z,2,numtiles-c+d);
     }
    }
    else{
     c=0;
     d++;
    }
   }
   for(z=0; z<TheBoard->GetZBoardSize(); z++){
    if(TheBoard->Letter(x,y,z)){
     for(c=z+1;(c<TheBoard->GetZBoardSize())&&(TheBoard->Letter(x,y,c));c++);
     if(c<TheBoard->GetZBoardSize())
      if(combo&TheBoard->Flags(x,y,c,0)&TheBoard->Flags(x,y,c,1)){
       Gather(x,y,z,2,c-z+1);
      }
     z=c;
    }
   }
  }
  }
  
  if(TheBoard->GetYBoardSize()>1){
  for(z=0; z<TheBoard->GetZBoardSize(); z++){
   for(y=TheBoard->GetYBoardSize()-1, c=0,d=0; y>-1; y--){
    if(combo&TheBoard->Flags(x,y,z,0)&TheBoard->Flags(x,y,z,2)){
     if(TheBoard->Adjacent(x,y,z)&2) c=d=0;
     else
      if(TheBoard->Adjacent(x,y,z)&61){
       c=numtiles;
       d=0;
      }
     if(c){
      c--;
      Gather(x,y,z,1,numtiles-c+d);
     }
    }
    else{
     c=0;
     d++;
    }
   }
   for(y=0; y<TheBoard->GetYBoardSize(); y++){
    if(TheBoard->Letter(x,y,z)){
     for(c=y+1;(c<TheBoard->GetYBoardSize())&&(TheBoard->Letter(x,c,z));c++);
     if(c<TheBoard->GetYBoardSize())
      if(combo&TheBoard->Flags(x,c,z,0)&TheBoard->Flags(x,c,z,2)){
       Gather(x,y,z,1,c-y+1);
      }
     y=c;
    }
   }
  }
  }
 }
 if(TheBoard->GetXBoardSize()>1){
 for(y=0; y<TheBoard->GetYBoardSize(); y++)
  for(z=0; z<TheBoard->GetZBoardSize(); z++){
   for(x=TheBoard->GetXBoardSize()-1, c=0,d=0; x>-1; x--){
    if(combo&TheBoard->Flags(x,y,z,2)&TheBoard->Flags(x,y,z,1)){
     if(TheBoard->Adjacent(x,y,z)&1) c=d=0;
     else 
      if(TheBoard->Adjacent(x,y,z)&62){
       c=numtiles;
       d=0;
      }
     if(c){
      c--;
      Gather(x,y,z,0,numtiles-c+d);
     }
    }
    else{
     c=0;
     d++;
    }
   }
   for(x=0; x<TheBoard->GetXBoardSize(); x++){
    if(TheBoard->Letter(x,y,z)){
     for(c=x+1;(c<TheBoard->GetXBoardSize())&&(TheBoard->Letter(c,y,z));c++);
     if(c<TheBoard->GetXBoardSize())
      if(combo&TheBoard->Flags(c,y,z,2)&TheBoard->Flags(c,y,z,1)){
       Gather(x,y,z,0,c-x+1);
      }
     x=c;
    }
   }
  }
 }
 
 if(curscore){
  FormatWord();
  //cout<<"FINAL:"<<(int)finalcoords.point[0]<<' '<<(int)finalcoords.point[1]<<' '<<(int)finalcoords.point[2]<<' '<<(int)finaldir<<' '<<finalword<<'\n';
  //cout.flush();
  TheMove = new scr_Move(finalcoords.point[0], finalcoords.point[1], finalcoords.point[2], finaldir, finalword);
 }
 else TheMove = new scr_Move();

 TheGame->SubmitMove(TheMove);
 delete TheMove;
 return 1;
}

void scr_CPlayer::FormatWord(){
int count;
 for(count=0; finalword[count]; count++)
  if(finalword[count]<65) finalword[count]|=96;
}

void scr_CPlayer::Gather(int x, int y, int z, int direction, int minlength){
char output[20],isword,spawn, nextspawn;
char accept=1, fit=1;
char offset,letter,tail;
unsigned char usedstack[16],used;
char store[20];
Coordinate coords,iterator;
unsigned long int temp,tempscore,combo;
 
 coords.point[0]=x;
 coords.point[1]=y;
 coords.point[2]=z;
 accept=fit=1;
 spawn=0;
 iterator=coords;
 usedstack[0]=0;
 Dictionary->SetStart();
 while(1==1){
  isword=Dictionary->Next(store,nextspawn,accept);
  if(store[0]==0) break;
  if(fit==0) spawn=accept;
  strcpy(output+spawn,store);
  used=usedstack[spawn];
  iterator=coords;
  iterator.point[direction]+=spawn;
  fit=1;
  accept=0;
  if((strlen(output)+coords.point[direction]>bounds.point[direction])){
   fit=accept=0;
   continue;
  }
  for(offset=spawn; output[offset]&&fit&&(iterator.point[direction]<bounds.point[direction]); offset++, iterator.whole+=(1<<(direction<<3))){
   if(iterator.point[direction]==bounds.point[direction]){
    fit=0;
    break;
   }
   letter=TheBoard->Letter(iterator.point[0], iterator.point[1], iterator.point[2]);
   if(letter==0){
    combo=(1<<(output[offset]-1));
    for(temp=0; temp<3; temp++)
     if(temp!=direction) combo&=TheBoard->Flags(iterator.point[0],iterator.point[1],iterator.point[2],temp);
    if(combo){
     for(temp=0; temp<TILENUM; temp++){
      if(tiles[temp]&combo){
       if(((used>>temp)&1)==0){
        used|=(1<<temp);
        if((tiles[temp]&3)==3) output[offset]+=64;
        break;
       }
      }
     }
     if(temp==TILENUM) fit=0;
    }
    else fit=0;
   }
   else{
    if(letter!=output[offset]) fit=0;
    else output[offset]+=(TheBoard->HasBlank(iterator.point[0],iterator.point[1], iterator.point[2])<<6);
   }
  }
  if(nextspawn>spawn) usedstack[nextspawn]=used;

  if(fit){
   if(used==((1<<TILENUM)-1)){
    fit=accept=0;
    tempscore=50;
   }
   else{
    tempscore=0;
    accept=1;
    spawn=nextspawn;
   }
   if((strlen(output)+coords.point[direction])==bounds.point[direction]){
    accept=fit=tail=0;
   }
   else tail=TheBoard->Letter(iterator.point[0], iterator.point[1], iterator.point[2]);
   // cout<<(int)coords.point[0]<<' '<<(int)coords.point[1]<<' '<<(int)coords.point[2]<<' '<<(int)direction<<' ';
   // for(isword=0;output[isword];isword++) cout<<(char)((output[isword]<64) ? (output[isword]+64) : output[isword]);
    //cout<<' '<<tempscore<<' '<<(int)TheBoard->Valid(coords,direction,output)<<'\n';
   // cout.flush();
   
   if(isword&&(strlen(output)>=minlength)){
    if(tail==0){
     tempscore+=TheBoard->RawScore(coords,direction,output);
     if(tempscore>curscore){
      strcpy(finalword,output);
      finaldir=direction;
      finalcoords=coords;
      curscore=tempscore;
     }
     /*

     */
    }
   }
  }
    
 }//end while 1==1
}
