CHECK.CPP
/* function prototyping for internal functions */ 
long CheckMiniMaxAlphaBeta(BOARD b, int t, int j, int d, long c, long p); 
 
#define JUMP_CONT_DEEPER 1 
 
/* -------------------------------------------------------------------------- 
true if previous level should prune 
else false 
 
note: it would be possible to not prune equal qualities becuase they 
      may be used to increase the number of available suggestions 
 
statistics: 02:42:00  3-13-1994 
            if this function is return 0, six levels takes 33 seconds 
            if this function is implemented, six levels takes 9 seconds 
-------------------------------------------------------------------------- */ 
inline int AlphaBeta(int t,long q, long c) 
{ 
    pdebug(stddbg,"alpha-beta pruning t=%d q=%ld c=%ld %s(%d)\n",t,q,c,__FILE__,__LINE__); 
 
    if (c > 0) 
        { 
        if (computer_color & t) 
            { 
            if (q > c) 
                { 
                pdebug(stddbg,"alpha-beta COMP pruning t=%d q=%ld c=%ld %s(%d)\n",t,q,c,__FILE__,__LINE__); 
                return 1; 
                } 
            } 
        else 
            { 
            if (q < c) 
                { 
                pdebug(stddbg,"alpha-beta USER pruning t=%d q=%ld c=%ld %s(%d)\n",t,q,c,__FILE__,__LINE__); 
                return 1; 
                } 
            } 
        } 
    return 0; 
} 
 
 
/* -------------------------------------------------------------------------- 
The algorithm is basically a min-max tree 
This function takes care of whether or no we remember the Min or the Max 
In checkers terms this means the following: 
    if it is my (the computers) move, pick the move that results in the highest quality 
    if it is your move, remember the move that does the most damage (min quality) 
 
Parameters: 
    t    - whos turn it is (RED or BLACK) 
    type - the move type.  this parameter should be a constant from check.h 
           it says if it the move is a black or red move, and if the move is 
           a sliding or jumping move.  This also indicates if the move is a 
           move towards the left or towards the right. 
    number - this is the index into the move table derived from 'type' 
    d      - current recursion depth (debugging purposes only) 
    besttype    - type corresponding with bestquality 
    bestnumber  - number corresponding with bestquality 
    bestquality - either a min or a max of qualities depending on current turn 
-------------------------------------------------------------------------- */ 
inline void RememberMove(int t,int type, int number, long q,int d, 
                         int* besttype, int* bestnumber, long* bestquality, 
                         long c, long p, int* fBreak) 
{ 
    *fBreak = AlphaBeta(t,q,c); 
    if (q == *bestquality) 
        { 
        pdebug(stddbg,"evaluation (equal move) t=%d type=%d num=%d q=%ld d=%d %s(%d)\n",t,type,number,q,d,__FILE__,__LINE__); 
        if (1 & rand()) return; 
        } 
    else if (computer_color & t) 
        { 
        pdebug(stddbg,"evaluation (computer) t=%d type=%d num=%d q=%ld d=%d %s(%d)\n",t,type,number,q,d,__FILE__,__LINE__); 
        if (q < *bestquality) return; 
        } 
    else 
        { 
        pdebug(stddbg,"evaluation (opponent) t=%d type=%d num=%d q=%ld d=%d %s(%d)\n",t,type,number,q,d,__FILE__,__LINE__); 
        if (*bestquality > 0 && q > *bestquality) return; 
        } 
 
    pdebug(stddbg,"RememberMove! evaluated t=%d type=%d num=%d q=%ld d=%d %s(%d)\n",t,type,number,q,d,__FILE__,__LINE__); 
    *besttype = type; 
    *bestnumber = number; 
    *bestquality = q; 
    return; 
} 
 
/* -------------------------------------------------------------------------- 
This function calls recurse for each possible jumping move for t's turn 
starting from the start position 
 
Note: there is special logic to crown men since landing in a crown position 
      can not continue the jump, but having a man that is already a king land 
      in a crown position can continue a jump. 
If the piece I am moving is a king, I look at both BLACK and RED moves. 
 
Parameters: 
    b     - board (value is not changed) 
    start - starting position 
    t     - whos turn it is (RED or BLACK) 
    besttype    - type corresponding with bestquality 
    bestnumber  - number corresponding with bestquality 
    bestquality - either a min or a max of qualities depending on current turn 
-------------------------------------------------------------------------- */ 
int IterateJumps(BOARD b, int start, int t, int d, 
                 int* besttype, int* bestnumber, long* bestquality, 
                 long c, long p, int *fBreak) 
{ 
    int moves_made=0; 
    long q; 
    SQUARE play_board[SQRS_MAX]; 
 
    if ((RED == t) || (KING & b[start])) 
        { 
        AssertSz(b[start] & t, "chicken"); 
        if (0 == b[red_jump_lut[start][1]] && red_jump_lut[start][1] && (next(t) & b[red_jump_lut[start][0]])) 
            { 
            pdebug(stddbg,"trying RED_JUMP0 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMoveNoKing_RED_JUMP0(play_board,start); 
            if (0 == red_jump_lut[start][4] || (KING & play_board[red_jump_lut[start][1]])) 
                { 
                q = CheckMiniMaxAlphaBeta(play_board,t,red_jump_lut[start][1],JUMP_CONT_DEEPER+d,c,p); 
                } 
            else 
                { 
                AssertSz(play_board[red_jump_lut[start][1]], "what the?"); 
                play_board[red_jump_lut[start][1]] |= red_jump_lut[start][4]; 
                q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
                } 
            RememberMove(t,TYPE_RED_JUMP0,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        if (0 == b[red_jump_lut[start][3]] && red_jump_lut[start][3] && (next(t) & b[red_jump_lut[start][2]])) 
            { 
            pdebug(stddbg,"trying RED_JUMP2 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMoveNoKing_RED_JUMP2(play_board,start); 
            if (0 == red_jump_lut[start][4] || (KING & play_board[red_jump_lut[start][3]])) 
                { 
                q = CheckMiniMaxAlphaBeta(play_board,t,red_jump_lut[start][3],JUMP_CONT_DEEPER+d,c,p); 
                } 
            else 
                { 
                AssertSz(play_board[red_jump_lut[start][3]], "this stupid piece"); 
                play_board[red_jump_lut[start][3]] |= red_jump_lut[start][4]; 
                q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
                } 
            RememberMove(t,TYPE_RED_JUMP2,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        } 
    if ((BLACK == t) || (KING & b[start])) 
        { 
        AssertSz(b[start] & t, "but... I thought it was my turn"); 
        if (0 == b[black_jump_lut[start][1]] && black_jump_lut[start][1] && (next(t) & b[black_jump_lut[start][0]])) 
            { 
            pdebug(stddbg,"trying BLACK_JUMP0 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMoveNoKing_BLACK_JUMP0(play_board,start); 
            if (0 == black_jump_lut[start][4] || (KING & play_board[black_jump_lut[start][1]])) 
                { 
                q = CheckMiniMaxAlphaBeta(play_board,t,black_jump_lut[start][1],JUMP_CONT_DEEPER+d,c,p); 
                } 
            else 
                { 
                AssertSz(play_board[black_jump_lut[start][1]], "you thought it was who's turn?"); 
                play_board[black_jump_lut[start][1]] |= black_jump_lut[start][4]; 
                q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
                } 
            RememberMove(t,TYPE_BLACK_JUMP0,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        if (0 == b[black_jump_lut[start][3]] && black_jump_lut[start][3] && (next(t) & b[black_jump_lut[start][2]])) 
            { 
            pdebug(stddbg,"trying BLACK_JUMP2 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMoveNoKing_BLACK_JUMP2(play_board,start); 
            if (0 == black_jump_lut[start][4] || (KING & play_board[black_jump_lut[start][3]])) 
                { 
                q = CheckMiniMaxAlphaBeta(play_board,t,black_jump_lut[start][3],JUMP_CONT_DEEPER+d,c,p); 
                } 
            else 
                { 
                AssertSz(play_board[black_jump_lut[start][3]], "maggots"); 
                play_board[black_jump_lut[start][3]] |= black_jump_lut[start][4]; 
                q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
                } 
            RememberMove(t,TYPE_BLACK_JUMP2,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        } 
    return moves_made; 
} 
 
/* -------------------------------------------------------------------------- 
This function calls recurse after making each possible sliding move for t's turn 
starting from the start position 
 
If the piece I am moving is a king, I look at both BLACK and RED moves. 
 
Parameters: 
    b     - board (value is not changed) 
    start - starting position 
    t     - whos turn it is (RED or BLACK) 
    besttype    - type corresponding with bestquality 
    bestnumber  - number corresponding with bestquality 
    bestquality - either a min or a max of qualities depending on current turn 
-------------------------------------------------------------------------- */ 
int IterateMoves(BOARD b, int start, int t, int d, 
                 int* besttype, int* bestnumber, long* bestquality, 
                 long c, long p, int *fBreak) 
{ 
    int moves_made=0; 
    long q; 
    SQUARE play_board[SQRS_MAX]; 
 
    if ((RED == t) || (KING & b[start])) 
        { 
        AssertSz(b[start] & t, "I wish I could fly"); 
        if (0 == b[red_lut[start][0]] && red_lut[start][0]) 
            { 
            pdebug(stddbg,"trying RED0 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMove_RED0(play_board,start); 
            q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
            RememberMove(t,TYPE_RED0,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        if (0 == b[red_lut[start][2]] && red_lut[start][2]) 
            { 
            pdebug(stddbg,"trying RED2 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMove_RED2(play_board,start); 
            q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
            RememberMove(t,TYPE_RED2,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        } 
 
 
    if ((BLACK == t) || (KING & b[start])) 
        { 
        AssertSz(b[start] & t, "what are you... "); 
        if (0 == b[black_lut[start][0]] && black_lut[start][0]) 
            { 
            pdebug(stddbg,"trying BLACK0 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMove_BLACK0(play_board,start); 
            q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
            RememberMove(t,TYPE_BLACK0,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        if (0 == b[black_lut[start][2]] && black_lut[start][2]) 
            { 
            pdebug(stddbg,"trying BLACK2 std move %d %s(%d)\n",start,__FILE__,__LINE__); 
            CopyBoard(b,play_board); 
            MakeMove_BLACK2(play_board,start); 
            q = CheckMiniMaxAlphaBeta(play_board,next(t),0,1+d,p,*bestquality); 
            RememberMove(t,TYPE_BLACK2,start,q,d,besttype,bestnumber,bestquality,c,p,fBreak); 
            ++moves_made; 
            } 
        } 
    return moves_made; 
} 
 
 
/* -------------------------------------------------------------------------- 
 
RECURSIVE MIN MAX ALGORITHM 
 
Parameters: 
    b - pointer to the board 
    t - whos turn it is (RED or BLACK) 
    j - space on board in which jump landed or zero if this 
        is not a jump continuation 
    d - depth of recursion 
 
    alpha-beta pruning parameters: 
 
    c - cutoff value for min max algorithm 
    p - threshold to be passed on to next level 
 
always returns the value of the best outcome of the board 
 
note: this function is to be called from within the checkers engine only 
note: this function evaluates moves based on the piece order structure defined 
      in lut.cpp.  The reason for this is that we gain two things by looking 
      at the best moves first: 
        1) pruning is more effective 
        2) if we must give up due to time constraint, we have already 
           evaluated some of the best moves. 
 
-------------------------------------------------------------------------- */ 
long CheckMiniMaxAlphaBeta(BOARD b, int t, int j, int d, long c, long p) 
{ 
    /* ----- stack variables ----- */ 
    int  moves_made        = 0; 
    int  best_move_type    = -1; 
    int  best_move_number  = -1; 
    long best_move_quality = -1; 
    int  fBreak            = 0; 
 
    /* ----- debug ----- */ 
    #ifdef DEBUG 
    debug=1; 
    if (debug && d < 7) PrintBoard(b,d); 
    #endif 
 
    AssertSz(b[0] == 0, "no b for my b my for my be my"); 
    AssertSz(d >= 0, "i am so tired of this"); 
 
    /* ----- if we have reached maximum depth, return now ----- */ 
    if (d >= depth_maximum) return QualityOfBoard(b,next(t)); 
 
    /* ----- iterate through all possible moves ----- */ 
    if (0 == j) 
        { 
        int i; 
        pdebug(stddbg,"standard iteration d=%d %s(%d)\n",d,__FILE__,__LINE__); 
        for (i=0;i<SQRS_MAX; i++) 
            { 
            int piece; 
            piece = (int) piece_order[i].m; 
            if (0 == (b[piece] & t)) continue; /* not our piece */ 
            moves_made += IterateJumps(b,piece,t,d,&best_move_type,&best_move_number,&best_move_quality,c,p,&fBreak); 
            if (fBreak) 
                { 
                AssertSz(moves_made,"I'm pruning something I have not looked at..."); 
                break; 
                } 
            } 
        if (0 == moves_made /* enforce the must jump rule */ 
            #ifndef HIGH_PERFORMANCE 
                || 0==rConfig.iMustJump 
            #endif 
            ) 
            { 
            pdebug(stddbg,"could not find a jumping move to make %s(%d)\n",__FILE__,__LINE__); 
            for (i=0;i<SQRS_MAX; i++) 
                { 
                int piece; 
                piece = (int) piece_order[i].m; 
                if (0 == (b[piece] & t)) continue; /* not our piece */ 
                moves_made += IterateMoves(b,piece,t,d,&best_move_type,&best_move_number,&best_move_quality,c,p,&fBreak); 
                if (fBreak) 
                    { 
                    AssertSz(moves_made,"to Scottland, I have not been"); 
                    break; 
                    } 
                } 
            } 
        if (0 == moves_made) 
            { 
            pdebug(stddbg,"could not find a move to make (error not handled) %s(%d)\n",__FILE__,__LINE__); 
            return QualityOfBoard(b,next(t)); 
            } 
 
        return best_move_quality; 
        } 
 
    /* ----- handle jump continuation ----- */ 
    pdebug(stddbg,"jump continuation d=%d %s(%d)\n",d,__FILE__,__LINE__); 
    moves_made = IterateJumps(b,j,t,d,&best_move_type,&best_move_number,&best_move_quality,c,p,&fBreak); 
    // AssertSz(0==fBreak,"is this a valid assert?"); 
    if (0==moves_made) 
        { 
        return CheckMiniMaxAlphaBeta(b,next(t),0,d,p,best_move_quality); 
        } 
    return best_move_quality; 
 
} /* end CheckMiniMaxAlphaBeta */