/*
    STB Generator
    Copyright (C) 2006 Gian-Carlo Pascutto
   
    File: make.c
    Purpose: Making and unmaking moves
*/

#include <assert.h>
#include "global.h"
#include "squares.h"

void make (state_s *s, matsig_s *ms, move_s *move) {
    int ep, from, target, captured, promoted;    
    int ep_target;
    int mvpiece;        
    int oldsq;    
    
    /* 
        processing aides 
    */
    ep = move->ep;
    from = move->from;
    target = move->target;
    captured = move->captured;
    promoted = move->promoted;
    
    /* 
        DEBUG 
    */
    assert(s->board[from] != npiece);
    assert((captured == npiece) || s->board[target] == captured || ep);
    assert(captured != 0);
    
    /* 
        clear the en passant rights: 
    */
    move->epsq = s->ep_square;    
    if (s->ep_square) {      
        s->ep_square = 0;
    }     
       
    /* 
        update piece square arrays
    */
    move->cap_num = s->squares[target];
            
    /* store old index-into-piece of target square */
    oldsq = s->squares[target];    
    
    s->pieces[oldsq] = 0;

    s->pieces[s->squares[from]] = target;
    s->squares[target] = s->squares[from];
    s->squares[from] = 0;
              
    /* 
        Remove captured piece from
        count, hash, bitboards        
    */
    if (!ep) {
        /* normal capture? */
        if (captured != npiece) {                                        
            ms->npieces[captured]--;                      
            s->piece_count--;
        }
    } else {
        /* ep capture
           need to clean ep-target square too,
           since unlike normal capture its empty now
        */
        if (s->board[from] == bpawn) {            
            ep_target = target + 12;                                              
            ms->npieces[wpawn]--;                                                         
        } else {           
            ep_target = target - 12;                        
            ms->npieces[bpawn]--;                         
        }
        
        move->cap_num = s->squares[ep_target];
        s->pieces[s->squares[ep_target]] = 0;
        s->squares[ep_target] = 0;

        s->board[ep_target] = npiece;                    
        
        s->piece_count--;                      
    }
    
    /*
        leave from square
    */
    mvpiece = s->board[from];      
    
    s->board[from] = npiece;
    s->board[target] = mvpiece;                  
    
    /*
        side to move and ply adjust
    */
    s->white_to_move ^= 1;    
    
    /* 
        check for special pawn moves
        or castling
    */
    if (mvpiece == wpawn) {                        
        if (promoted) {
            s->board[target] = promoted;                                                                        
            
            ms->npieces[wpawn]--;
            ms->npieces[promoted]++;          
        } else {
            /* moved a pawn up 2 squares: */
            if (target == from+24) {
                s->ep_square = from+12;                   
            }                                                   
        }                                                                      
    } else if (mvpiece == bpawn) {
        if (promoted) {
            s->board[target] = promoted;                                                
            
            ms->npieces[promoted]++;
            ms->npieces[bpawn]--;                        
        } else {
            if (target == from-24) {
                s->ep_square = from-12;                                            
            }                       
        }
    } else if (mvpiece == wking) {                                 
        s->wking_loc = target;                                
    } else  if (mvpiece == bking) {                           
        s->bking_loc = target;                                               
    }    

    return;
}

void unmake (state_s *s, matsig_s *ms, move_s *move) {  
    int ep, from, target, captured, promoted;
    int ep_target;    
    int tpiece, oldsq;              

    ep = move->ep;
    from = move->from;
    target = move->target;
    captured = move->captured;
    promoted = move->promoted;
    
    assert(from >= A1 && from <= H8);
    assert(target >= A1 && target <= H8);
               
    s->white_to_move ^= 1;    
    
    s->ep_square = move->epsq;       
        
    oldsq = s->squares[from];
    s->squares[from] = s->squares[target];
    s->squares[target] = move->cap_num;
    s->pieces[s->squares[target]] = target;
    s->pieces[s->squares[from]] = from;    
        
    tpiece = s->board[target];
    s->board[from] = tpiece;

    if (!ep) {  
        if (from != target) {
            s->board[target] = captured;  
        }
        if (captured != npiece) {                       
            ms->npieces[captured]++;            
            s->piece_count++; 
        }
    } else {
        s->board[target] = npiece;

        if (tpiece == wpawn) {            
            ep_target = target - 12;
           
            ms->npieces[bpawn]++;  
            s->board[ep_target] = bpawn; 
        } else {           
            ep_target = target + 12;
         
            ms->npieces[wpawn]++;
            s->board[ep_target] = wpawn;   
        }

        s->piece_count++;        
        
        s->squares[ep_target] = move->cap_num;
        s->pieces[move->cap_num] = ep_target;
        s->squares[target] = 0;                   
    }   
    
    if (promoted) {
        /* white promotions: */
        if (PIECECOLOR(tpiece) == WHITE) {     
            s->board[from] = wpawn;            
            
            ms->npieces[promoted]--;
            ms->npieces[wpawn]++;                       
        } else {            
            s->board[from] = bpawn;
                        
            ms->npieces[promoted]--;
            ms->npieces[bpawn]++;                             
        }
    } else if (tpiece == wking) {  
        s->wking_loc = from;                      
    } else  if (tpiece == bking) {        
        s->bking_loc = from;                              
    }
 
    return;
}
