#include <6170.h>
#include <antichess_board.h>

typeinfo_t antichess_board::typeinfo = new_typeinfo();

antichess_board::antichess_board(istream &initial_format) :
chess_display_board(initial_format) {
}

antichess_board::antichess_board() : chess_display_board() {
}

antichess_board::~antichess_board() {
}

int antichess_board::winner() {
    if (!are_valid_move_available(0, false))
	return 0;
    if (!are_valid_move_available(1, false))
	return 1;
    return -1;
}

board * antichess_board::clone() const {
    antichess_board *ab = new antichess_board();
    board::clone_part(*ab);
    chess_display_board::clone_part(*ab);
    clone_part(*ab);
    return ab;
}

void antichess_board::clone_part(antichess_board &ab) const {
    ab.evaluation = evaluation;
}
	

bool antichess_board::is_legal_move(move &m, int player_num) const {
    chess_capture_move *mv = (chess_capture_move *)
	m.force(chess_capture_move::typeinfo);
    if (!mv)
	return false;
    path route = mv->get_path();
    chess_piece piece = mv->get_piece_taken();
    if (piece == none){
	move_generator *mg = valid_moves(player_num);
	move *cm;
	if (mg->get(cm)) {
	    chess_capture_move *force = (chess_capture_move *)
		cm->force(chess_capture_move::typeinfo);
	    if (!force)
		return false;
	    if (force->get_piece_taken() != none)
		return false;
	}
    }
        
    bool t = move_validity(player_num, route, piece);
    if (!t){
	cout << route.x1 << route.y1 << route.x2 << route.y2 << "\n";
	cout << "given invalid move\n";
	save(cout);
    }
    return t;
}

game::move_result antichess_board::apply(move &m, int player_num){
    chess_capture_move *mv = (chess_capture_move *)
	m.force(chess_capture_move::typeinfo);
    if (!mv)
	return game::move_invalid;
    
    if (!is_legal_move(*mv, player_num))
	return game::move_invalid;
    
    path temp = mv->get_path();
    if ((temp.x1<0) || (temp.x1>7) ||
	(temp.y1<0) || (temp.y1>7) ||
	(temp.x2<0) || (temp.x2>7) ||
	(temp.y2<0) || (temp.y2>7))
	return game::move_invalid;
    square sq1 = fetch(temp.y1,temp.x1);
    if (sq1.piece_type == none)
	return game::move_invalid;
    move_piece(temp.x1,temp.y1,temp.x2,temp.y2);
    return game::ok;
}

game::move_result antichess_board::apply_internal(chess_capture_move *m, 
						  int player_num){
    path temp = m->get_path();
    move_piece(temp.x1,temp.y1,temp.x2,temp.y2);
    return game::ok;
}

bool antichess_board::unapply(move &m, int ){
    chess_capture_move *mv =  (chess_capture_move *)
	m.force(chess_capture_move::typeinfo);
    if (!mv)
	return false;
        
    path temp = mv->get_path();
    if ((temp.x1<0) || (temp.x1>7) ||
	(temp.y1<0) || (temp.y1>7) ||
	(temp.x2<0) || (temp.x2>7) ||
	(temp.y2<0) || (temp.y2>7))
	return false;
    square sq1 = fetch(temp.y2,temp.x2);
    if (sq1.piece_type == none)
	return false;
    chess_piece old_piece = mv->get_piece_taken();
    color old_color = mv->get_color_taken();
    move_piece(temp.x2,temp.y2,temp.x1,temp.y1);
    place_piece(temp.x2,temp.y2,old_piece, old_color);
    return true;
}

board::value antichess_board::eval_move_delta(int p_pov, move &m, 
					      int p_mover) const{
    board::value total =0;
    antichess_board *b = (antichess_board *) this;
    chess_capture_move *mv = 
        (chess_capture_move *)m.force(chess_capture_move::typeinfo);
    if (!mv)
        return 0;

    if (!is_legal_move(m, p_mover))
	return 0;
    
    b->apply_internal(mv, p_mover);
    
    if (!are_valid_move_available(p_pov, false))
	return board::infinity;
    
    b->unapply(m, p_mover);

    switch(mv->get_piece_taken()){
    case invalid:  break;  //this should never happen
    case none: total =0;
	break;
    case pawn: total= 1;
	break;
    case rook: total= 5;
	break;
    case knight: total= 3;
	break;
    case bishop: total= 5;
	break;
    case queen: total= 7;
	break;
    case king: total= 2;
	break;
    }
    if (p_mover == p_pov)
	return -total;
    return total;
}

board::value antichess_board::evaluate(int player_num) const{
    int x1, y1;
    register antichess_board *b = (antichess_board *) this;
    board::value total =0;
    color this_color;
    
    if (!state_changed())
	return evaluation;
    b->update();
    
    if (player_num==0)
	this_color=white;
    else if (player_num==1)
	this_color=black;

    for(y1=0;y1<8;y1++)
	for(x1=0;x1<8;x1++){
	    if (b->fetch(y1,x1).piece_color != this_color)
		break;
	
	    switch(b->fetch(y1,x1).piece_type){
	    case invalid:  break;  //this should never happen
	    case none:     break;
	    case pawn: total-= 7;
		break;
	    case rook: total-= 2;
		break;
	    case knight: total-= 4;
		break;
	    case bishop: total-= 2;
		break;
	    case queen: total-= 2;
		break;
	    case king: total-= 6;
		break;
	    }
	}
    b->evaluation = total;
    return total;
}

long antichess_board::suggest_time(long time_left) const {
  if ((starting_pieces()-pieces_remaining(0)-pieces_remaining(1)) < 1)
    return (time_left / 30);  // Start game, don't think too hard
  else if ((pieces_remaining(0)+pieces_remaining(1)) < 10)
    return (time_left / 10);
  else return (time_left / (pieces_remaining(0) + pieces_remaining(1)));
//    return (time_left * (starting_pieces()+1-pieces_remaining(0)
//		  -pieces_remaining(1))) /starting_pieces();
}

void * antichess_board::force (typeinfo_t &t){
    if (t == typeinfo) return this;
    else return 0;
}


bool antichess_board::valid_move_available(int player_num) const {
    return are_valid_move_available(player_num, true);
}

