#ifndef STATE_H_INCLUDED
#define STATE_H_INCLUDED

#include <stdint.h>
#include "ramjet.h"
#include "quadboard.h"

// the state data type
typedef uint32_t STATE;

// bit 0: side to move
#define ST_GET_PL(st) ((st) & 1)
#define ST_SET_PL(st, pl) (((st) & ~1) | (pl))
#define ST_TOGGLE_PL(st) ((st) ^ 1)

// bit 1-7: en-passant target square
#define ST_GET_EP(st) (((st) & 0xFE) >> 1)
#define ST_SET_EP(st, sq) (((st) & ~0xFE) | ((sq) << 1))
#define ST_CLEAR_EP(st) (ST_SET_EP(st, SQ_NULL))

// bit 8-23: castling rights (white 8-15, black 16-23)
extern STATE st_castle_pl[2];
extern STATE st_castle_sq[64];
#define ST_GET_CASTLE_PL(st, pl) ((st) & st_castle_pl[pl])
#define ST_SET_CASTLE_SQ(st, sq) ((st) | st_castle_sq[sq])
#define ST_CLEAR_CASTLE_PL(st, pl) ((st) & ~st_castle_pl[pl])
#define ST_CLEAR_CASTLE_SQ(st, sq) ((st) & ~st_castle_sq[sq])
#define IS_ST_CASTLE_SQ(st, sq) ((st) & st_castle_sq[sq])

// bit 24-31: counter for the fifty-move rule
#define ST_GET_50(st) ((st) >> 24)
#define ST_SET_50(st, n) (((st) & ~0xFF000000) | (n << 24))
#define ST_CLEAR_50(st) (ST_SET_50(st, 0))
#define ST_INC_50(st) ((st) + (1 << 24))

// other macros and constants
#define ST_NULL (ST_CLEAR_EP(0)) // null state for an empty board
#define ST_REP(st) ((st) & 0xFFFFFF) // subset for repetition detection

// initialise the constants
void st_init();

// set the ep square if it is pseudolegal
STATE st_set_true_ep(STATE st, const QUADBOARD* qb, SQUARE sq);

// return the first castle target square while erasing it
SQUARE st_castle_sq_next(STATE* st);

// input-output in FEN format
STATE st_scan_fen(char* fen, const QUADBOARD* qb);
void st_print_fen(char* fen, const QUADBOARD* qb, STATE st);

// compute a hash digest of the state
HASHKEY st_hash(STATE st);

// sanity check on the state
int is_st_bad(const QUADBOARD* qb, STATE st);

// test the functions above
int st_test();

#endif // STATE_H_INCLUDED
