/* $Id: chc_rule.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include "config.h"
#include "pttstruct.h"
#include "common.h"
#include "proto.h"

extern rc_t chc_from, chc_to;
extern int chc_my;

#define CENTER(a, b)      (((a) + (b)) >> 1)

void chc_init_board(board_t board) {
    memset(board, 0, sizeof(board_t));
    board[0][4] = CHE(1, chc_my ^ 1);                    /* �N */
    board[0][3] = board[0][5] = CHE(2, chc_my ^ 1);      /* �h */
    board[0][2] = board[0][6] = CHE(3, chc_my ^ 1);      /* �H */
    board[0][0] = board[0][8] = CHE(4, chc_my ^ 1);      /* �� */
    board[0][1] = board[0][7] = CHE(5, chc_my ^ 1);      /* �� */
    board[2][1] = board[2][7] = CHE(6, chc_my ^ 1);      /* �] */
    board[3][0] = board[3][2] = board[3][4] =
	board[3][6] = board[3][8] = CHE(7, chc_my ^ 1);  /* �� */

    board[9][4] = CHE(1, chc_my);                    /* �� */
    board[9][3] = board[9][5] = CHE(2, chc_my);      /* �K */
    board[9][2] = board[9][6] = CHE(3, chc_my);      /* �� */
    board[9][0] = board[9][8] = CHE(4, chc_my);      /* �� */
    board[9][1] = board[9][7] = CHE(5, chc_my);      /* �X */
    board[7][1] = board[7][7] = CHE(6, chc_my);      /* �� */
    board[6][0] = board[6][2] = board[6][4] =
	board[6][6] = board[6][8] = CHE(7, chc_my);  /* �L */
}

void chc_movechess(board_t board) {
    board[chc_to.r][chc_to.c] = board[chc_from.r][chc_from.c];
    board[chc_from.r][chc_from.c] = 0;
}

static int dist(rc_t from, rc_t to, int rowcol) {
    int d;
    
    d = rowcol ? from.c - to.c : from.r - to.r;
    return d > 0 ? d : -d;
}

static int between(board_t board, rc_t from, rc_t to, int rowcol) {
    int i, rtv = 0;

    if(rowcol) {
	if(from.c > to.c)
	    i = from.c, from.c = to.c, to.c = i;
	for(i = from.c + 1; i < to.c; i++)
	    if(board[to.r][i]) rtv++;
    } else {
	if(from.r > to.r)
	    i = from.r, from.r = to.r, to.r = i;
	for(i = from.r + 1; i < to.r; i++)
	    if(board[i][to.c]) rtv++;
    }
    return rtv;
}

int chc_canmove(board_t board, rc_t from, rc_t to) {
    int i;
    int rd, cd, turn;

    rd = dist(from, to, 0);
    cd = dist(from, to, 1);
    turn = CHE_O(board[from.r][from.c]);
    
    /* general check */
    if(board[to.r][to.c] && CHE_O(board[to.r][to.c]) == turn)
	return 0;

    /* individual check */
    switch(CHE_P(board[from.r][from.c])) {
    case 1: /* �N �� */
	if(!(rd == 1 && cd == 0) &&
	   !(rd == 0 && cd == 1))
	    return 0;
	if((turn == (chc_my ^ 1) && to.r > 2) ||
	   (turn == chc_my && to.r < 7) ||
	    to.c < 3 || to.c > 5)
		return 0;
	break;
    case 2: /* �h �K */
	if(!(rd == 1 && cd == 1))
	    return 0;
	if((turn == (chc_my ^ 1) && to.r > 2) ||
	   (turn == chc_my && to.r < 7) ||
	    to.c < 3 || to.c > 5)
		return 0;
       	break;
    case 3: /* �H �� */
	if(!(rd == 2 && cd == 2))
	    return 0;
	if((turn == (chc_my ^ 1) && to.r > 4) ||
	   (turn == chc_my && to.r < 5))
	    return 0;
	/* ��H�L */
	if(board[CENTER(from.r, to.r)][CENTER(from.c, to.c)])
	    return 0;
	break;
    case 4: /* �� */
	if(!(rd > 0 && cd == 0) &&
	   !(rd == 0 && cd > 0))
	    return 0;
	if(between(board, from, to, rd == 0))
	    return 0;
	break;
    case 5: /* �� �X */
	if(!(rd == 2 && cd == 1) &&
	   !(rd == 1 && cd == 2))
	    return 0;
	/* �䰨�} */
	if(rd == 2) {
	    if(board[CENTER(from.r, to.r)][from.c])
		return 0;
	} else {
	    if(board[from.r][CENTER(from.c, to.c)])
		return 0;
	} 
	break;
    case 6: /* �] �� */
	if(!(rd > 0 && cd == 0) &&
	   !(rd == 0 && cd > 0))
	    return 0;
	i = between(board, from, to, rd == 0);
	if((i > 1) ||
	   (i == 1 && !board[to.r][to.c]) ||
	   (i == 0 && board[to.r][to.c]))
	   return 0;
	break;
    case 7: /* �� �L */
	if(!(rd == 1 && cd == 0) &&
	   !(rd == 0 && cd == 1))
	    return 0;
	if(((turn == (chc_my ^ 1) && to.r < 5) ||
	    (turn == chc_my && to.r > 4)) &&
	    cd != 0)
	    return 0;
	if((turn == (chc_my ^ 1) && to.r < from.r) ||
	   (turn == chc_my && to.r > from.r))
	    return 0;
	break;
    }
    return 1;
}

static void findking(board_t board, int turn, rc_t *buf) {
    int i, r, c;

    r = (turn == (chc_my ^ 1)) ? 0 : 7;
    for(i = 0; i < 3; r++, i++)
	for(c = 3; c < 6; c++)
	    if(CHE_P(board[r][c]) == 1 &&
	       CHE_O(board[r][c]) == turn) {
		buf->r = r, buf->c = c;
		return ;
	    }
}

int chc_iskfk(board_t board) {
    rc_t from, to;
    
    findking(board, 0, &to);
    findking(board, 1, &from);
    if(from.c == to.c && between(board, from, to, 0) == 0)
	return 1;
    return 0;
}

int chc_ischeck(board_t board, int turn) {
    rc_t from, to;
    
    findking(board, turn, &to);
    for(from.r = 0;from.r < BRD_ROW; from.r++)
	for(from.c = 0; from.c < BRD_COL; from.c++)
	    if(board[from.r][from.c] &&
	       CHE_O(board[from.r][from.c]) != turn)
		if(chc_canmove(board, from, to))
		    return 1;
    return 0;
}