#ifndef MAGIC_H
#define MAGIC_H

// includes

#include "GCint.h"
#include "board.h"

// defines
#ifdef __i386__
// Idea of Harm Geert Muller to economize one 32 bit multiplication.
#define MagicMul(b,magic)                    \
    ((                                       \
((uint32_t)((b)& 0xFFFFFFFF))                \
*                                            \
((uint32_t)((magic)& 0xFFFFFFFF))            \
)^(                                          \
   ((uint32_t)   ((b)>>32))                  \
*                                            \
   ((uint32_t)   ((magic)>>32))              \
))
#define BMagic(sq) BMagic32[sq]
#define RMagic(sq) RMagic32[sq]
#define MagicShift(bits) (32-(bits))
#else
#define MagicMul(b,magic) ((b)*(magic))
#define BMagic(sq) BMagic64[sq]
#define RMagic(sq) RMagic64[sq]
#define MagicShift(bits) (64-(bits))
#endif

#define MagicHash(b,magic,bits) ( (int)   (MagicMul(b,magic)>>MagicShift(bits)))

#define MagicBishopAttackEx(sq,blocker)                                 \
(									\
 MagicBishopTable[sq][							\
		      MagicHash((BMask[sq] & ~(blocker)),		\
		      BMagic(sq),				\
		      BBits[sq])					\
		  ]							\
)

#define MagicRookAttackEx(sq,blocker)                                   \
(									\
 MagicRookTable[sq][							\
		      MagicHash((RMask[sq] & ~(blocker)),		\
		      RMagic(sq),				\
		      RBits[sq])					\
		]							\
)

#define MagicBishopAttack(board,sq) MagicBishopAttackEx(sq,board->blocker)

#define MagicRookAttack(board,sq) MagicRookAttackEx(sq,board->blocker)


#define MagicQueenAttack(board,sq) ( MagicBishopAttack(board,sq) | MagicRookAttack(board,sq))

// variables

extern const uint64_t RMagic64[64];
extern const uint64_t BMagic64[64];
extern const uint64_t RMagic32[64];
extern const uint64_t BMagic32[64];
extern const int RBits[64];
extern const int BBits[64];
extern const BitBoard BMask[64];
extern const BitBoard RMask[64];
extern BitBoard MagicBishopTable[64][512];
extern BitBoard MagicRookTable[64][4096];

// functions

void MagicInit();

// functions for testing

BitBoard MagicAttack(int sq, int piece, BitBoard blocker);
BitBoard MagicBishopAttack_(board_t *board, int sq);
BitBoard MagicRookAttack_  (board_t *board, int sq);
BitBoard MagicQueenAttack_  (board_t *board, int sq);


#endif
