// Copyright 1993, 1995 by Jon Dart.  All Rights Reserved.

#include "stdafx.h"
#include "movearr.h"
#include "types.h"
#include "debug.h"

Pool Move_Record::allocator;

const Move_Array_Incr = 50;  // grow by this amount

struct BIGINT
{
  DWORD low;
  DWORD high;
};

union INT64UNION
{
  BIGINT b;
  hash_t u;
} ;

static inline int32 quickmod(hash_t hashcode, int32 buckets)
{
   // We do a modulus only on the low order DWORD of the hashcode,
   // to save time.
   INT64UNION un;
   un.u = hashcode;
   return (int32)(un.b.low % buckets);
}

Move_Record::Move_Record(const Board &board, const ExtendedMove &move)
: my_move(move),my_hashcode(board.HashCode())
{
}

Move_Record::Move_Record()
: my_move(ExtendedMove()),my_hashcode(0)
{
}

int Move_Record::operator == ( const Move_Record &l ) const
{
  return my_hashcode == l.my_hashcode;
}

int Move_Record::operator != ( const Move_Record &l ) const
{
  return my_hashcode != l.my_hashcode;
}

Move_Array::Move_Array() 
{ 
    arr.SetSize(0, Move_Array_Incr);
    for (int i=0; i<Rep_Table_Size;i++)
      rep_table[i] = 0;
}
	     
Move_Array::~Move_Array()
{
    // free the contents
    for (unsigned i=0; i < num_moves(); i++)
    {
        delete (Move_Record*)arr[i];
    }
}

void Move_Array::add_move( const Board &board, const ExtendedMove &emove )
{
    Move_Record *entry = new Move_Record( board, emove );
    arr.Add(entry);
    int probe = quickmod(board.HashCode(),Rep_Table_Size);
    rep_table[probe]++;
}

void Move_Array::remove_move()
{
    int n = num_moves();
    if (n == 0)
        return;
    Move_Record *entry = (Move_Record*)arr[n-1];
    rep_table[quickmod(entry->hashcode(),Rep_Table_Size)]--;
    arr.RemoveAt(n-1);
    delete entry;
}

const ExtendedMove &Move_Array::move( const unsigned n )
{
    return ((Move_Record*)arr[n])->move();
}
	
int Move_Array::rep_count( const Board &board, int start) const
{
    // we do a quick check first to see if any entry has the same
    // lower 7 bits in the hash code.
    if (num_moves() == 0 ||
        rep_table[quickmod(board.HashCode(),Rep_Table_Size)] == 0)
       return 0;
    int n = num_moves()-1;
    int count = 0;
    Move_Record e(board,ExtendedMove());
    for (int i = n ; i >= start; --i )
    {
       Move_Record *cur_entry = (Move_Record*)arr[i];
       if (*cur_entry == e)
          count++;
       const ExtendedMove &cur_move = cur_entry->move();
       if (!cur_move.Capture().IsEmpty() ||
            cur_move.PieceMoved().Type() == Piece::Pawn ||
	    cur_move.Special() != ExtendedMove::Normal)
          break;
    }
    return count;
}	

int Move_Array::rep_count( const Board &board) const
{
    return rep_count(board,0);
}

void Move_Array::clear()
{
    /*
    for (int i = 0; i < arr.GetSize(); i++)
    {
        Move_Record *rec = (Move_Record*)arr[i];
        delete rec;
    }
    */
    arr.RemoveAll();
}

unsigned Move_Array::num_moves(const ColorType side)
{
    if (side == White)
        return num_moves() ? num_moves()/2 + 1 : 0;
    else
        return num_moves() ? (num_moves()-1)/2 : 0;
}

