/*
 * Copyright 1996 by Michel D. Grimminck
 *
 * All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * 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.
 */
#include <stdio.h>
#include "var.h"
#include "functions.h"
#include <string.h>
#include <time.h>
#include <math.h>
#include <signal.h>

static int deepning[32]={20, 33, 53, 67, 77, 86, 94, 100, 106, 111, 115, 119, 123, 127, 130, 133, 136, 139, 142, 144, 146, 149, 151, 153, 155, 157, 158, 160, 162, 164, 165, 167}; /* near-logarithmic function */
int stopflag=false;
int max_ext_depth;
int current_move[MAXPLY];

#define USEHASH 100

void stopsearch(int sig)
{
        sig++;
        set_col(31,31);
        printf("Search terminated\n");
        res_col();
        stopflag=true;
}



int play(int color,float maxtime,int verbose)
        /* front end for alpha-beta
           search for player 'color' until maxtime is reached.
           if maxtime=0 search forever.
           */
{
        int n,time,d,score,t,myscore,myd,i;
        int my_score,my_d,my_time,my_neval,totalman;
        char mymove[32];
        char comment[MAXCOMMENT];
        int plyscore[MAXPLY];
        int accept=true;
        int offer=true;
        int resign=true;
        int ntest=0;
        
        set_eval();
        stopflag=false;
        n=move_list(0,color);
        if (n==1) {
                if (verbose>0) {printf("forced move:"); print_move(movelist[0][0]); printf("\n");}
                xstore_history(movelist[0][0],"forced");
                do_move(movelist[0][0]);
                return(false);
        }
        score=try_book(0,color);
        if (score!=UNKNOWN) {
                if (verbose>0) {printf("book move:"); print_move(PV[0][0]); printf("\n");}
                return(score);
        }
        score=theoretic(color);
        if (score!=UNKNOWN) {
                printf("exact move, score:%i\n",score);
                plyscore[0]=score=theo_alfabeta(-INF,INF,color,0,d,theoretic(color));
                if (score==UNKNOWN) goto notexact;
                movecopy(mymove,PV[0][0]);
                xstore_history(mymove,"exact");
                do_move(mymove);
                set_col(32,32);
                printf("my move: ");
                print_move(mymove);
                printf("\n");
                res_col();
                return(score);
        }
 notexact:
        d=100;
        signal(SIGINT,stopsearch);
        time=clock();
        init_hash();
        while(((clock()-time)<0.5*CLOCKS_PER_SEC*maxtime || maxtime==0) && d<100*(MAXPLY-10) || d<300) {
                init_stats();
                t=-clock();
                max_ext_depth=(d/100)+4;
                plyscore[d/100]=score=alfabeta(-INF,INF,color,0,d,0);
                if (stopflag==false) {
                        movecopy(mymove,PV[0][0]);
                        my_score=score;
                        my_d=d;
                        my_time=clock()+t;
                        my_neval=neval;
                }
                else {
                        if (verbose>0) {
                                set_col(32,32);
                                printf("my move: ");
                                print_move(mymove);
                                printf("\n");
                                res_col();
                        }
                        break;
                }
                t+=clock();
                if (verbose>3) {
                        set_col(33,33);
                        if ((verbose>5 && ((double) t/CLOCKS_PER_SEC)>3.0) || verbose>9) printf("\n");
                        printf("depth:%2i   ",d/100);
                        printf("s:%.3f t:%.1f   ",score/1000.0F,(float) t/CLOCKS_PER_SEC);
                        print_pv();
                        res_col();
                        if ((verbose>5 && ((double) t/CLOCKS_PER_SEC)>3.0) || verbose>9) {
                                print_stats();
                                if ( ((double) t/CLOCKS_PER_SEC)>60.0) beep();
                        }
                        fflush(stdout);
                }
                if (score==WIN) break;
                d+=100;
        }
        signal(SIGINT,SIG_DFL);
        stopflag=false;
        sprintf(comment,"score: %.3f, time:%.2f, depth:%i, nodes:%i",(float)(my_score/1000.0F),(float) my_time/CLOCKS_PER_SEC,my_d/100,my_neval);
        xstore_history(mymove,comment);
        do_move(mymove);
        for(i=4;i<d/100;i++) {
                if (plyscore[i]>-3500) resign=false;
                if (plyscore[i]>-10) accept=false;
                if (plyscore[i]!=0) offer=false;
                ntest++;
        }
        beep();
        totalman=pieces[white|man]+pieces[black|man]+pieces[white|crown]+pieces[black|crown];
        if (ntest>=3) {
                if (resign==true) printf("I resign\n");
                else if (accept==true && totalman<=14) printf("accepting draws (if offered)\n");
                else if (offer==true && totalman<=14) printf("offering draw\n");
        }
        return(score);
}

void resume(void)
{
        ;
        
}

void print_pv(void)
{
        int i;
        
        printf("pv: ");
        for(i=0;i<MPV;i++) if (PV[0][i][0]!=0) {
                print_move(PV[0][i]); printf(" ");
        }
        printf("\n");
        resume();
}

int move_nr(char *move)
{
    if (move[0]!=4) return(invmap[move[1]]);
    else if (move[1]==(move[3]+6) || move[1]==(move[3]-6)) return(invmap[move[1]]+50);
    else return(invmap[move[1]]+100);
}

void badmove(int level,char *move,int nmoves)
{
    if (kill_method==PROBKILL) history[level] [move_nr(move)] [nmoves]=(00+970*history[level] [move_nr(move)] [nmoves])/1024;
}

void goodmove(int level,char *move,int nmoves)
{
    if (kill_method==HISTORY) history[level] [move_nr(move)] [0]++;
    else if (kill_method==PROBKILL) history[level] [move_nr(move)] [nmoves]=1024-(970*(1024-history[level] [move_nr(move)] [nmoves]))/1024;
    movecopy(killer[level],move);
}

void goodmove2(int level,char *move,int nmoves)
{
    if (kill_method==HISTORY) history[level] [move_nr(move)] [0]++;
    else if (kill_method==PROBKILL) history[level] [move_nr(move)] [nmoves]+=124;
    movecopy(killer[level],move);
}


void storemove(int level,char *move)
{
    int i;

    if (level>=maxpv) return;

    movecopy(PV[level][level],move);
    for(i=level+1;i<maxpv;i++) {
        movecopy(PV[level][i],PV[level+1][i]);
        }
}

void init_hash(void)
{
    int i;

    for(i=0;i<tablesize;i++) {
        transpos[i].hashkey=-1;
        transpos[i].board[0]=invalid;
        transpos[i].depth=0;
        }
    for(i=0;i<MAXEVAL;i++) {
        evalcache[i].hashkey=-1;
	evalcache[i].board[0]=invalid;
        }
}

unsigned int hash_key(int color)
{
    unsigned int key=0;
    int i;

    for(i=0;i<50;i++) key+=hash_rnd[i][board[map[i]]];
    key=key&0xFFFFFFFE;
    return(key+2*color);
}

int retreive_eval(int color)
/* retreive the current position from the hash table */
{
    int i,entry;
    unsigned int key;
    unsigned char temp[18];

    key=hash_key(color);
    entry=key%MAXEVAL;

    if (key!=evalcache[entry].hashkey) {
      return(UNKNOWN);
    }
    strong_compress_board(temp,board); temp[17]=color;
    for(i=0;i<18;i++) if (evalcache[entry].board[i]!=temp[i]) return(UNKNOWN);
    outeval++;
    return(evalcache[entry].score);
}

void store_eval(int color,int score)
/* store the current position in the hash table */
{
    int entry;
    unsigned int key;

    key=hash_key(color);
    entry=key%MAXEVAL;

    evalcache[entry].hashkey=key;
    evalcache[entry].score=score;
    strong_compress_board(evalcache[entry].board,board);
    evalcache[entry].board[17]=color;
    ineval++;
}

int retreive_hash(int color,int *min, int *max,int *hd,char *move)
/* retreive the current position from the hash table */
{
    int i,entry;
    unsigned int key;
    unsigned char temp[18];

    key=hash_key(color);
    entry=key%tablesize;

    if (key!=transpos[entry].hashkey) {
        entry++;
        if (key!=transpos[entry].hashkey) return(UNKNOWN);
    }
    strong_compress_board(temp,board); temp[17]=color;
    for(i=0;i<18;i++) if (transpos[entry].board[i]!=temp[i]) return(UNKNOWN);
    outhash++;
    *min=transpos[entry].min_score;
    *max=transpos[entry].max_score;
    *hd=transpos[entry].depth;
    move[0]=transpos[entry].move[0];
    move[1]=transpos[entry].move[1];
    return(!UNKNOWN);
}

void store_hash(int color,int depth,int min,int max,char *move)
/* store the current position in the hash table */
{
    int entry;
    unsigned int key;

    key=hash_key(color);
    entry=key%tablesize;

    if (transpos[entry].depth>depth) {
        transpos[entry+1]=transpos[entry];
    }
    transpos[entry].hashkey=key;
    transpos[entry].min_score=min;
    transpos[entry].max_score=max;
    strong_compress_board(transpos[entry].board,board);
    transpos[entry].board[17]=color;
    transpos[entry].depth=depth;
    transpos[entry].move[0]=move[1];
    transpos[entry].move[1]=move[move[0]-1];
    inhash++;
}

void sort_viahash(int level,int nmoves,char *hashmove,int depth,int color)
{
    int i;
    char temp[32];

    /*if (depth>=600) {
        do_presearch(level,nmoves,color);
    }*/
    for(i=0;i<nmoves;i++) if (movelist[level][i][1]==hashmove[0] && movelist[level][i][(int)movelist[level][i][0]-1]==hashmove[1]) {
        movecopy(temp,movelist[level][0]);
        movecopy(movelist[level][0],movelist[level][i]);
        movecopy(movelist[level][i],temp);
        return;
        }

    set_col(31,31);
    printf("error: movelist corrupted\n"); res_col();
    display_board();
    print_movelist(level,nmoves);
    print_move(hashmove);
}

void findkiller(int level,int nmoves)
{
    int i;
    char temp[32];

    for(i=0;i<nmoves;i++) if (movecmp(movelist[level][i],killer[level])==0) {
        movecopy(temp,movelist[level][0]);
        movecopy(movelist[level][0],movelist[level][i]);
        movecopy(movelist[level][i],temp);

        break;
        }

}
int quiet_crown(int p,int color)
{
    int d,pp,eneman,enecrown;

    eneman=man|!color;enecrown=crown|!color;

    for(d=0;d<4;d++) {
                pp=p;
                do pp=next[color][pp][d]; while(board[pp]==empty);
                if (board[pp]==eneman || board[pp]==enecrown) if (board[next[color][pp][d]]==empty) return(false);
                }
    return(true);
}

int wnc_quiet()
{
  int ip,p;

  for(ip=5;ip<50;ip++) {
    p=map[ip];
    if (board[p] == (white|man)) {
      if (board[p-7]==(black|man)) if (board[p-14]==empty) return(false);
      if (board[p-6]==(black|man)) if (board[p-12]==empty) return(false);
      if (board[p+7]==(black|man)) if (board[p+14]==empty) return(false);
      if (board[p+6]==(black|man)) if (board[p+12]==empty) return(false);
    }
  }
  nquietfail++;
  return(true);
}

int w_quiet()
{
  int ip,p,d,pp;

  if (pieces[white|crown]==0 && pieces[black|crown]==0) return(wnc_quiet());
  for(ip=0;ip!=50;ip++) {
    p=map[ip];
    if (board[p] == (white|man)) {
      if (board[p-7]==(black|man) || board[p-7]==(black|crown)) if (board[p-14]==empty) return(false);
      if (board[p-6]==(black|man) || board[p-6]==(black|crown)) if (board[p-12]==empty) return(false);
      if (board[p+7]==(black|man) || board[p+7]==(black|crown)) if (board[p+14]==empty) return(false);
      if (board[p+6]==(black|man) || board[p+6]==(black|crown)) if (board[p+12]==empty) return(false);
    }
    else if (board[p] ==(white|crown)) {
      for(d=0;d<4;d++) {
	pp=p;
	do pp=next[white][pp][d]; while(board[pp]==empty);
	if (board[pp]==(black|man) || board[pp]==(black|crown)) if (board[next[white][pp][d]]==empty) return(false);
      }
    }
  }
  nquietfail++;
  return(true);
}

int bnc_quiet()
{
  int ip,p;

  for(ip=44;ip>=0;ip--) {
    p=map[ip];
    if (board[p] == (black|man)) {
      if (board[p+7]==(white|man)) if (board[p+14]==empty) return(false);
      if (board[p+6]==(white|man)) if (board[p+12]==empty) return(false);
      if (board[p-7]==(white|man)) if (board[p-14]==empty) return(false);
      if (board[p-6]==(white|man)) if (board[p-12]==empty) return(false);
    }
  }
  nquietfail++;
  return(true);
}


int b_quiet()
{
  int ip,p,d,pp;

  if (pieces[white|crown]==0 && pieces[black|crown]==0) return(bnc_quiet());
  for(ip=49;ip>=0;ip--) {
    p=map[ip];
    if (board[p] == (black|man)) {
      if (board[p+7]==(white|man) || board[p+7]==(white|crown)) if (board[p+14]==empty) return(false);
      if (board[p+6]==(white|man) || board[p+6]==(white|crown)) if (board[p+12]==empty) return(false);
      if (board[p-7]==(white|man) || board[p-7]==(white|crown)) if (board[p-14]==empty) return(false);
      if (board[p-6]==(white|man) || board[p-6]==(white|crown)) if (board[p-12]==empty) return(false);
    }
    else if (board[p] ==(black|crown)) {
      for(d=0;d<4;d++) {
	pp=p;
	do pp=next[black][pp][d]; while(board[pp]==empty);
	if (board[pp]==(white|man) || board[pp]==(white|crown)) if (board[next[black][pp][d]]==empty) return(false);
      }
    }
  }
  nquietfail++;
  return(true);
}

int quiet(int color)
/* returns false if color can capture, true otherwise */
{
  nquiet++;
  if (color==white) return(w_quiet());
  else return(b_quiet());
  printf("fatal: q\n");
  return(false);
}

int active(int target,int color,int cdepth,int depth)
/* if non-active move available/(non-forced): return true if target is met
   else try achieve target with active moves only
   */
{
    int i,nr,score,activemoves=0,nmoves;
    int at_nr,def_nr,has_defence,try_active,defmoves;

    score=theoretic(color);
    if (score!=UNKNOWN) {
        if (score>=target) return(true);
        else return(false);
    }

    /* create general movelist */
    nmoves=move_list(cdepth,color);
    if (nmoves==0) return(false);

    try_active=true;
    if (movelist[cdepth][0][0]!=4) try_active=false; /* forced move */
    if (nmoves==1) try_active=false;

    if (movelist[cdepth][0][0]==4 && nmoves!=1) { /* no forced move:
       try doing nothing and achieving target */
        score=material(color);
        deval[cdepth]++;
        if (score>=target) return(true);
    }

    if (depth<=0) { /* no move moves are allowed, target not achieved */
       return(false);
    }
    /* make list of active moves */
    if (try_active==true) {
        for(i=0;i<nmoves;i++) {
            do_move(movelist[cdepth][i]);
            if (quiet(color^1)==false) {
                movecopy(movelist[cdepth][activemoves],movelist[cdepth][i]);
                activemoves++;
                }
            undo_move(movelist[cdepth][i]);
        }
    nmoves=activemoves;
    }
    if (cdepth==0) printf("%i active moves\n",nmoves);
	/* we now have nmoves active or forced moves to do,
	   do them all to achieve a true value, or return false
	   otherwise
	 */
    for(at_nr=0;at_nr<nmoves;at_nr++) {
        do_move(movelist[cdepth][at_nr]); /* do your active move */
        defmoves=move_list(cdepth+1,color^1);
        has_defence=false; /* defender loses */
        /* try all defences (they are forced) */
        for(def_nr=0;def_nr<defmoves;def_nr++) {
            do_move(movelist[cdepth+1][def_nr]);
            if (active(target,color,cdepth+2,depth-200)==false) {   /* attacker has no win */
                has_defence=true;
                /* break: undo move */
                undo_move(movelist[cdepth+1][def_nr]);
                break;
            }
            undo_move(movelist[cdepth+1][def_nr]);
        }
        if (cdepth==0) {
            movecopy(movescore[at_nr].move,movelist[cdepth][at_nr]);
            movescore[nr].value=has_defence;
        }
        if (has_defence==false) { /* target achieved!, undo move and return */
            goodmove(cdepth,movelist[cdepth][at_nr],nmoves);
            storemove(cdepth,movelist[cdepth][at_nr]);
            undo_move(movelist[cdepth][at_nr]);
            return(true);
        }
        undo_move(movelist[cdepth][at_nr]);
    }
    /* otherwise, for all active moves, target is not achieved */
    return(false);
}

int quiet_search(int alfa,int beta,int color,int cdepth)
/* quiescence search looks for material only.
*/
{
    int nmoves,nr,score;

    nmoves=move_list(cdepth,color);

    for(nr=0;nr<nmoves;nr++) {
            do_move(movelist[cdepth][nr]);
            if (quiet(color^1)==true) score=-material(color^1);
            else score=-quiet_search(-beta,-alfa,color^1,cdepth+1);

            if (score>=beta) {
                undo_move(movelist[cdepth][nr]);
                return(score);
                }
            if (score>alfa) alfa=score;
            undo_move(movelist[cdepth][nr]);
            }
    return(alfa);
}

void sort_moves_slow(int cdepth,int nmoves,int *iterscore)
{
    /* optimise iterscore[move] */
    int i,j,t;
    char tempmove[32];
    
    for(i=0;i<nmoves-1;i++) for(j=i+1;j<nmoves;j++)
        if (iterscore[i]<iterscore[j]) {
               movecopy(tempmove,movelist[cdepth][i]);
               movecopy(movelist[cdepth][i],movelist[cdepth][j]);
               movecopy(movelist[cdepth][j],tempmove);
               t=iterscore[i]; iterscore[i]=iterscore[j]; iterscore[j]=t;
               }
}

void sort_moves(int cdepth,int nmoves,int *iterscore)
{
  /* optimise iterscore[move] */
  int i,j,a;
  char tempmove[32];
  
  for(j=1;j<nmoves;j++) {
    a=iterscore[j];
    movecopy(tempmove,movelist[cdepth][j]);
    i=j-1;
    while(i>=0 && iterscore[i]<a) {
      iterscore[i+1]=iterscore[i];
      movecopy(movelist[cdepth][i+1],movelist[cdepth][i]);
      i--;
    }
    iterscore[i+1]=a;
    movecopy(movelist[cdepth][i+1],tempmove);
  }
}

int do_presearch(int cdepth,int nmoves,int color,int depth)
{
    int nr,sortlow=-INF;
    int iterscore[MAXNM];
    int ud;

    ud=100;
    if (depth>=600) ud=200;
    if (depth>=800) ud=300;
    precount-=neval;
    for(nr=0; nr<nmoves; nr++) {
        do_move(movelist[cdepth][nr]);
        if (quiet(color^1)==false) {
            iterscore[nr]=300-alfabeta(-INF,INF,color ^1,cdepth+1,ud,50)/*+500-120*move_list(cdepth+1,color^1);*/;
        } else iterscore[nr]=-evalboard(color^1,-INF,INF)-10*move_list(cdepth+1,color^1);
   
        undo_move(movelist[cdepth][nr]);
    }

    /* sort moves highest score first */
    sort_moves(cdepth,nmoves,iterscore);
    precount+=neval;
    return(0);
}

int giterscore[MAXNM];
char dummymove[32];

int solve(int alfa,int beta,int color,int cdepth,int depth)
{
    int treesize[MAXNM],iterscore[MAXNM],predepth[MAXNM];
    int i,nr,myscore=!UNKNOWN,score,result,nmoves,ts;


    if (depth<=0) { neval++; deval[cdepth]++; return(theoretic(color)); }

    score=theoretic(color);
    if (score!=UNKNOWN) return(score);

    nmoves=move_list(cdepth,color);
    if (nmoves==0) return(LOSE);

    for(i=0;i<nmoves;i++) {
        predepth[i]=-100; treesize[i]=0; iterscore[i]=UNKNOWN;
    }

    do {
        for(nr=0;nr<nmoves;nr++) if (iterscore[nr]==UNKNOWN) {
            do_move(movelist[cdepth][nr]);
            treesize[nr]=-neval; predepth[nr]+=100;

            result=solve(-beta,-alfa,color ^1,cdepth+1,predepth[nr]);
            treesize[nr]+=neval;
            undo_move(movelist[cdepth][nr]);
            /*if (cdepth==0) {
                print_move(movelist[cdepth][nr]);
                if (result==UNKNOWN) printf("    unknown\n");
                else if ((-result)==WIN) printf("    win\n");
                else if ((-result)==LOSE) printf("    lose\n");
                else if ((-result)==0) printf("    draw\n");
            }*/
            if (result!=UNKNOWN) {
                score=iterscore[nr]=-result;
                if (score>=beta || score==WIN && cdepth!=0) return(score);
                if (score>alfa) alfa=score;
            } else myscore=iterscore[nr]=UNKNOWN;

        }
        if (cdepth==0) for(nr=0;nr<nmoves;nr++) {
                print_move(movelist[cdepth][nr]);
                printf("  %i %i %i ",treesize[nr],iterscore[nr],predepth[nr]);
                if (iterscore[nr]==UNKNOWN) printf("    unknown\n");
                else if (iterscore[nr]==WIN) printf("    win\n");
                else if (iterscore[nr]==LOSE) printf("    lose\n");
                else if (iterscore[nr]==0) printf("    draw\n");
            }
        for(nr=0;nr<nmoves;nr++) if (predepth[nr]>=(depth-100)) goto esc;

        for(nr=0;nr<nmoves;nr++) if (iterscore[nr]==UNKNOWN) continue;

    } while(1==1);
    esc:
    if (myscore==UNKNOWN) return(UNKNOWN);
    return(alfa);
}

int theo_alfabeta(int alfa,int beta,int color,int cdepth,int depth,int exact)
{
  int best=-INF,nmoves,nr,tscore;

  nmoves=move_list(cdepth,color);
  if (nmoves==0) return(LOSE);
  
  for(nr=0;nr<nmoves;nr++) {
    do_move(movelist[cdepth][nr]);
    tscore=theoretic(color^1);
    if (cdepth==0) {
      movescore[nr].value=-tscore;
      movecopy(movescore[nr].move,movelist[cdepth][nr]);
    }
    if (tscore!=UNKNOWN) {
      if ((-tscore)>best) {
	best=-tscore;
	storemove(cdepth,movelist[cdepth][nr]);
      }
    }
    undo_move(movelist[cdepth][nr]);
  }
  if (best==-INF) return(UNKNOWN);
  return(best);
}

int moveselect[MAXPLY];

int alfabeta(int alfa,int beta,int color,int cdepth,int depth,int flags)
{
    int score,best=-1,q,min,max,hd;
    int nmoves,nr;
    int nextdepth;
    int pat,mateval,newflags,alfa0=alfa;
    char hashmove[2];

    /* depth <0: return static evaluation */
    if (depth<=0) {
#ifndef QUICKSTART
      int z,i,ok;

      if (pieces[white|man]>=6) {
	pat_try++;
	/*printf("hello1\n");*/
	
	pat=tpat_reconize(color);/*printf("hello2\n");*/
	
	if (pat!=-1) {
	  pat_found++; /*display_board();*/
	  for(z=0;z<tpat[pat].nmoves;z++) {/*printf("hello3\n");*/
	    ok=false;
	    nmoves=move_list(cdepth+z,(color+z)%2);
	    if (z%2==1) if (nmoves!=1) goto patch;
	    if (color==white) {
	      for(i=0;i<nmoves;i++) if (movecmp(movelist[cdepth+z][i],tpat[pat].movelist[z])==0) {
		do_move(movelist[cdepth+z][i]);
		moveselect[cdepth+z]=i;
		ok=true;
		break;
	      }
	    }
	    else {
	      for(i=0;i<nmoves;i++) if (reverse_movecmp(movelist[cdepth+z][i],tpat[pat].movelist[z])==0) {
		do_move(movelist[cdepth+z][i]);
		moveselect[cdepth+z]=i;
		
		ok=true;
		break;
	      }
	    }
	  patch:
	    if (ok==false) {
	      tpat[pat].use_fail++;
	      /*printf("impossible to do moves\n");*/
	      for(i=z-1;i>=0;i--) undo_move(movelist[cdepth+i][moveselect[cdepth+i]]);
	      return(evalboard(color,alfa,beta));
	    }
	  } /* all moves done now eval */
	  deval[cdepth+z]++;
	  min=evalboard((color+z)%2,-INF,INF);
	  
	  if ((color+z)%2!=color) min=-min;
	  for(i=z-1;i>=0;i--) {
	    
	    undo_move(movelist[cdepth+i][moveselect[cdepth+i]]);
	  }
	  deval[cdepth]++;
	  score=evalboard(color,alfa,beta);
	  /*printf("pat:%i %i\n",score,min);*/
	  if (min>score+500) {
	    tpat[pat].use_succes++;
	    pat_succes++;
	  }
	  return(min>score?min:score);
	}
      }
#endif
      deval[cdepth]++;
      return(evalboard(color,alfa,beta));
    }
    hashmove[0]=0;

    if (use_hash && depth>USEHASH) {
            score=retreive_hash(color,&min,&max,&hd,hashmove);
	    if (score!=UNKNOWN && hd>=depth) {
	        if (min==max) return(min);
                if (min>=beta) return(min);
                if (max<=alfa) return(alfa);
                if (min>alfa) alfa=min;
                }
	    if (score!=UNKNOWN && min==WIN) return(WIN);
	    if (score!=UNKNOWN && max==LOSE) return(LOSE);
            }

    /* try to determen theoretic value */
    score=theoretic(color);
    if (score!=UNKNOWN) return(score);

    /* generate moves */
    nmoves=move_list(cdepth,color);
    if (nmoves==0) return(LOSE);

    /* check for beta cut from hash tables */

    if (nmoves==1) goto nosort;

    if (use_hash && depth>=300) {
        if (stopflag==true) return(alfa);
        for(nr=0; nr<nmoves; nr++) {
            do_move(movelist[cdepth][nr]);
            score=retreive_hash(color^1,&min,&max,&hd,dummymove);
            if (score!=UNKNOWN) if (hd>=(depth-100)) {
                score=-max;
                if (score>=beta) {
                    storemove(cdepth,movelist[cdepth][nr]);
                    undo_move(movelist[cdepth][nr]);
                    return(score);
                    }
                if (score>alfa) alfa=score;
            }
            undo_move(movelist[cdepth][nr]);
        }
    }

    /* move ordering */
    if (hashmove[0]!=0) sort_viahash(cdepth,nmoves,hashmove,depth,color);
    else if (depth>=500) {
        do_presearch(cdepth,nmoves,color,depth);
    }
    else {
        if (kill_method==KILLER) findkiller(cdepth,nmoves);
        else if (kill_method==PROBKILL) {
            for(nr=0;nr<nmoves;nr++) {
                giterscore[nr]=history[cdepth][ move_nr(movelist[cdepth][nr]) ] [nmoves]; 
	      }
            sort_moves(cdepth,nmoves,giterscore);
        }
        else if (kill_method==HISTORY) {
            for(nr=0;nr<nmoves;nr++) giterscore[nr]=history[cdepth]
                    [ move_nr(movelist[cdepth][nr]) ] [0];
            sort_moves(cdepth,nmoves,giterscore);
        }
    }

    if (depth>=500) goto nosort;
    /* tactical pattern cut */
#ifdef notdef
    if (color==white && quiet(color)==true) {
      pat=tpat_reconize();
      ndat++;
    }
    else pat=-1;
    if (pat>=0) {
      int i;char temp[32];
      tpat[pat].use_fail++; dbfail++;
      /*display_board();*/
      for(i=0;i<nmoves;i++) if (movecmp(movelist[cdepth][i],tpat[pat].movelist[0])==0) {
        movecopy(temp,movelist[cdepth][0]);
        movecopy(movelist[cdepth][0],movelist[cdepth][i]);
        movecopy(movelist[cdepth][i],temp);
	tpat[pat].use_succes++;
        break;
      }
    }
#endif
    nosort:
    /* start normal alfa-beta search */
    for(nr=0;nr<nmoves;nr++) {
        newflags=flags;
        do_move(movelist[cdepth][nr]);
	if (cdepth<8) current_move[cdepth]=nr;
        nextdepth=depth-100;

        if (depth>100) {
            mateval=-material(color^1);
            if (mateval<(alfa-800)) if (quiet(color^1)==true && quiet(color)==true) {
                nextdepth-=100;
            }
	    if (mateval<(alfa-3400)) if (quiet(color^1)==true && quiet(color)==true) {
	      nextdepth-=100;
            }
	}


#ifdef notdef
	if (cdepth<8 && cdepth>=2 && nextdepth==depth-100) {
	  /* extend if previous move was local */
	  char *lastmove;
	  lastmove=movelist[cdepth-2][current_move[cdepth-2]];
	  if (movelist[cdepth][nr][1]==lastmove[lastmove[0]-1]) {
	    nextdepth=depth;
	  }
	}
#endif
        if (nextdepth<=0) { /* last move ? : check quiescence */
            q=quiet(color^1);
            if (q==false) {
	      nextdepth+=99;
	      while(nextdepth<0) nextdepth+=100;
	    }
	  }
        else if ((flags&EXTEND_TAKE)<=MAXEXTEND && nmoves==1 && depth<=600) {
	  nextdepth=depth;
	  newflags++;
	}

        score=-alfabeta(-beta,-alfa,color ^1,cdepth+1,nextdepth,newflags);
        abdone:
        /* store score for each move (at root only) */
        if (cdepth==0) {
            movecopy(movescore[nr].move,movelist[cdepth][nr]);
            movescore[nr].value=score;
	    /*printf("%i/%i\r  ",nr,nmoves); fflush(stdout);*/
            }
         /* beta cut */
        if (score>=beta) {
            storemove(cdepth,movelist[cdepth][nr]);
            goodmove(cdepth,movelist[cdepth][nr],nmoves);
            undo_move(movelist[cdepth][nr]);
            if (use_hash && depth>USEHASH) store_hash(color,depth,score,INF,movelist[cdepth][nr]);
            return(score);
            } else badmove(cdepth,movelist[cdepth][nr],nmoves);
        undo_move(movelist[cdepth][nr]);
        if (score>alfa) {
            alfa=score;
            best=nr;
            storemove(cdepth,movelist[cdepth][nr]);
            }

        }
    if (best!=-1) {
        goodmove2(cdepth,movelist[cdepth][best],nmoves);
        }
    if (use_hash && depth>USEHASH && alfa>alfa0) store_hash(color,depth,alfa,alfa,movelist[cdepth][best]);
    return(alfa);
}


















