#pragma once

#include "types.h"

enum important_limits {
    maxMoves	=	256,		// maximum number of moves per position (218, according to wikipedia)
    maxUndo		=	8,			// maximum number of undo moves
    mate		=	500000		// checkmate value (used in evaluation)
};

class Board;

// type: 0 = full, 1 = short, 2 = tiny
// describe value -> buffer (32-byte buffer should do)
void describeValue( i32 val, char *buf, i32 type = 0 );

// is mate value?
inline bool isMate( i32 val )
{
    return val <= -mate + 1000 || val >= +mate - 1000;
}

// capture scores for move ordering, the higher the better (Move.val)
enum move_order_capture_scores
{
    winCap			=	80,			// winning capture
    queenPromo		=	64,			// queen promotions
    goodCap			=	48,			// good capture (exchange)
    castVal			=	32,			// castling
    underPromo		=	28,			// underpromotions
    checkingMove	=	24,			// checking move
    normalMove		=	22,			// normal move
    normalCap		=	22,			// normal capture
};

class Move
{
public:
    union {
        struct {
u32 from:
            6;			// from
u32 to:
            6;			// to
u32 promo:
            3;		// promotion to PieceType (none => no promotion)
u32 dangerous:
            1;	// dangerous => requires quiescence search
u32 capture:
            1;		// capture
u32 castling:
            2;		// castling: 0 = none, 1 = O-O, 2 = O-O-O
u32 enpassant:
            1;	// enpassant capture

u32 cappiece:
            3;		// movegen helper: captured piece type
u32 lastcap:
            1;		// movegen/search helper: capture of last moved piece?

u32 val:
            8;			// search helper: (sorting; tmp value)
        };
        u32 packed;
    };

    // move sorting...
    inline bool operator <( const Move &o ) const
    {
        if ( val != o.val )
            return val > o.val;							// cmp by value
        if ( dangerous != o.dangerous )
            return dangerous;
        if ( dangerous )
        {
            if ( capture != o.capture )
                return capture;
            if ( capture )
            {
                if ( lastcap != o.lastcap )
                    return lastcap;
                if ( cappiece != o.cappiece )
                    return cappiece > o.cappiece;
            }
        }
        return promo > o.promo;					// better promotions first
    }

    // describe move -> buffer (32-byte buffer should do)
    void describe( const Board &b, char *buf ) const;

    // describe move using SAN (short algebraic notation)
    // checks: use '+' and '#' suffices for check/checkmate
    void describeSAN( i32 turn, const Board &b, char *buf, bool checks = true ) const;

    // describe in uci-compatible format
    void describeUCI( char *buf ) const;

    // describe in ics-compatible format
    void describeICS( char *buf ) const;

    void parse( const char *&lan );

    // returns true if two moves are equal (wrt start/end position)
    bool equal( const Move &m ) const;

    // returns true if two moves are equal (wrt PV)
    bool equalPV( const Move &m ) const;

    // returns true if two moves are equal (wrt UCI)
    bool equalUCI( const Move &m ) const;

    inline void clear()
    {
        packed = 0;
    }

    // move eval bonus (because of castling!)
    i32 eval( i32 turn, const Board *b = 0 ) const;

    // returns true if valid move
    bool valid() const;

    // returns true if 'null move', i.e. king to same_position, like Ke1
    bool isNull() const;
};

typedef struct Undo {
    u8 pos;
    u8 packed;			// packed value
} Undo;
