- /* 
-     Protector -- a UCI chess engine 
-   
-     Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com) 
-   
-     This program is free software: you can redistribute it and/or modify 
-     it under the terms of the GNU General Public License as published by 
-     the Free Software Foundation, either version 3 of the License, or 
-     (at your option) any later version. 
-   
-     This program is distributed in the hope that it will be useful, 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-     GNU General Public License for more details. 
-   
-     You should have received a copy of the GNU General Public License 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>. 
-   
- */ 
-   
- #include <stdio.h> 
- #include <stdlib.h> 
- #include <assert.h> 
- #include <math.h> 
- #include "hash.h" 
- #include "protector.h" 
- #include "io.h" 
- #include "keytable.h" 
-   
- #define NODE_TABLE_SIZE (MAX_THREADS * MAX_DEPTH * 32) 
-   
- const unsigned int NUM_DATES = 16; 
- const unsigned int CLUSTER_SIZE = 4; 
- const UINT8 DEPTH_NONE = 0; 
- Nodeentry nodeUsageTable[NODE_TABLE_SIZE]; 
- long numNodeTableEntries; 
-   
- INT16 getHashentryValue(const Hashentry * entry) 
- { 
-    return (INT16) (entry->data & 0xFFFF); 
- } 
-   
- INT16 getHashentryStaticValue(const Hashentry * entry) 
- { 
-    return (INT16) ((entry->data >> 16) & 0xFFFF); 
- } 
-   
- UINT8 getHashentryImportance(const Hashentry * entry) 
- { 
-    return (UINT8) ((entry->data >> 32) & 0xFF); 
- } 
-   
- UINT16 getHashentryMove(const Hashentry * entry) 
- { 
-    return (UINT16) ((entry->data >> 40) & 0xFFFF); 
- } 
-   
- UINT8 getHashentryDate(const Hashentry * entry) 
- { 
-    return (UINT8) ((entry->data >> 56) & 0x0F); 
- } 
-   
- UINT8 getHashentryFlag(const Hashentry * entry) 
- { 
-    return (UINT8) ((entry->data >> 60) & 0x03); 
- } 
-   
- UINT64 getHashentryKey(const Hashentry * entry) 
- { 
-    return entry->key ^ entry->data; 
- } 
-   
- static int getAge(const Hashtable * hashtable, const UINT8 date) 
- { 
-    assert(- hashtable ->- date  <-  NUM_DATES );
 
-   
-    return (hashtable->date + NUM_DATES - date) & (NUM_DATES - 1); 
- } 
-   
- void incrementDate(Hashtable * hashtable) 
- { 
-    assert(- hashtable ->- date  <-  NUM_DATES );
 
-   
-    hashtable->date = (UINT8) ((hashtable->date + 1) % NUM_DATES); 
-   
-    assert(- hashtable ->- date  <-  NUM_DATES );
 
- } 
-   
- static void deleteTables(Hashtable * hashtable) 
- { 
-    if (hashtable->table != 0) 
-    { 
-       hashtable->table = 0; 
-    } 
- } 
-   
- static UINT64 _getHashData(INT16 value, INT16 staticValue, UINT8 importance, 
-                            UINT16 bestMove, UINT8 date, UINT8 flag) 
- { 
-    return ((UINT64) (value & 0xFFFF)) | 
-       ((UINT64) (staticValue & 0xFFFF)) << 16 | 
-       ((UINT64) importance) << 32 | 
-       ((UINT64) bestMove) << 40 | 
-       ((UINT64) date) << 56 | ((UINT64) flag) << 60; 
- } 
-   
- Hashentry constructHashEntry(UINT64 key, INT16 value, INT16 staticValue, 
-                              UINT8 importance, UINT16 bestMove, UINT8 date, 
-                              UINT8 flag) 
- { 
-    Hashentry entry; 
-   
-    entry.key = key; 
-    entry.data = _getHashData(value, staticValue, importance, 
-                              bestMove, date, flag); 
-   
-    return entry; 
- } 
-   
- void resetHashtable(Hashtable * hashtable) 
- { 
-    UINT64 l; 
-    Hashentry emptyEntry; 
-   
-    emptyEntry.key = ULONG_ZERO; 
-    emptyEntry.data = _getHashData(-VALUE_MATED, 0, DEPTH_NONE, 
-                                   (UINT16) NO_MOVE, 0, HASHVALUE_UPPER_LIMIT); 
-   
-    for (l = 0; l < hashtable->tableSize + CLUSTER_SIZE; l++) 
-    { 
-       hashtable->table[l] = emptyEntry; 
-    } 
-   
-    hashtable->date = 0; 
-    hashtable->entriesUsed = 0; 
-   
-    /* logDebug("hashtable reset done.\n"); */ 
- } 
-   
- void resetNodetable() 
- { 
-    int i; 
-   
-    for (i = 0; i < NODE_TABLE_SIZE; i++) 
-    { 
-       nodeUsageTable[i].key = ULONG_ZERO; 
-    } 
- } 
-   
- void initializeHashtable(Hashtable * hashtable) 
- { 
-    hashtable->table = 0; 
-    hashtable->tableSize = 0; 
-    hashtable->entriesUsed = 0; 
- } 
-   
- bool isPrimeNumber(UINT64 n) 
- { 
-    UINT64 limit, d; 
-   
-    if (n == 2) 
-    { 
-       return TRUE; 
-    } 
-   
-    if (n < 2 || n % 2 == 0) 
-    { 
-       return FALSE; 
-    } 
-   
-    limit  = (- UINT64 ) (sqrt((double)-  n ) + 1.0);
-   
-    for (d = 3; d <= limit; d += 2) 
-    { 
-       if (n % d == 0) 
-       { 
-          return FALSE; 
-       } 
-    } 
-   
-    return TRUE; 
- } 
-   
- UINT64 getNextPrime(UINT64 n) 
- { 
-    while (isPrimeNumber(n) == FALSE) 
-    { 
-       n++; 
-    } 
-   
-    return n; 
- } 
-   
- UINT64 getPreviousPrime(UINT64 n) 
- { 
-    n--; 
-   
-    while (isPrimeNumber(n) == FALSE) 
-    { 
-       n--; 
-    } 
-   
-    return n; 
- } 
-   
- void setHashtableSize(Hashtable * hashtable, UINT64 size) 
- { 
-    const UINT64 ENTRY_SIZE = sizeof(Hashentry); 
-   
-    deleteTables(hashtable); 
-    hashtable->tableSize = getNextPrime(size / ENTRY_SIZE); 
-    hashtable->table = 
-       malloc((size_t)((- hashtable ->- tableSize  +-  CLUSTER_SIZE ) *-  ENTRY_SIZE )); // Pierre-Marie Baty -- added type cast
 
-   
-    /* logDebug("Hashtable size: %ld entries\n", 
-       hashtable->tableSize); */ 
- } 
-   
- UINT64 getHashIndex(Hashtable * hashtable, UINT64 key) 
- { 
-    return key % ((hashtable)->tableSize); 
- } 
-   
- void setHashentry(Hashtable * hashtable, UINT64 key, INT16 value, 
-                   UINT8 importance, UINT16 bestMove, UINT8 flag, 
-                   INT16 staticValue) 
- { 
-    const UINT64 index = getHashIndex(hashtable, key); 
-    UINT64 data, i, bestEntry = 0; 
-    int bestEntryScore = -1024; 
-    Hashentry *entryToBeReplaced; 
-   
-    for (i = 0; i < CLUSTER_SIZE; i++) 
-    { 
-       Hashentry copy = hashtable->table[index + i]; 
-       const UINT8 copyDate = getHashentryDate(©); 
-       const int copyFlag = getHashentryFlag(©); 
-   
-       if (getHashentryKey(©) == key || copy.key == ULONG_ZERO) 
-       { 
-          if (copyDate != hashtable->date || copy.key == ULONG_ZERO) 
-          { 
-             hashtable->entriesUsed++; 
-          } 
-   
-          if (bestMove == (UINT16) NO_MOVE) 
-          { 
-             bestMove = getHashentryMove(©); 
-          } 
-   
-          data = _getHashData(value, staticValue, importance, bestMove, 
-                              hashtable->date, flag); 
-          hashtable->table[index + i].key = key ^ data; 
-          hashtable->table[index + i].data = data; 
-   
-          return; 
-       } 
-       else 
-       { 
-          const int score = 
-             getAge(hashtable, copyDate) * 8 - 
-             getHashentryImportance(©) - 
-             (copyFlag == HASHVALUE_EXACT ? 24 : 0); 
-   
-          if (score > bestEntryScore) 
-          { 
-             bestEntry = i; 
-             bestEntryScore = score; 
-          } 
-       } 
-    } 
-   
-    if (getHashentryDate(&hashtable->table[index + bestEntry]) != 
-        hashtable->date) 
-    { 
-       hashtable->entriesUsed++; 
-    } 
-   
-    entryToBeReplaced = &hashtable->table[index + bestEntry]; 
-    data = _getHashData(value, staticValue, importance, bestMove, 
-                        hashtable->date, flag); 
-    entryToBeReplaced->key = key ^ data; 
-    entryToBeReplaced->data = data; 
- } 
-   
- Hashentry *getHashentry(Hashtable * hashtable, UINT64 key) 
- { 
-    const UINT64 index = getHashIndex(hashtable, key); 
-    UINT64 i; 
-   
-    for (i = 0; i < CLUSTER_SIZE; i++) 
-    { 
-       Hashentry *tableEntry = &hashtable->table[index + i]; 
-   
-       if (getHashentryKey(tableEntry) == key) 
-       { 
-          if (getHashentryDate(tableEntry) != hashtable->date) 
-          { 
- #ifndef NDEBUG 
-             const Hashentry originalEntry = *tableEntry; 
- #endif 
-             const UINT64 mask = (((UINT64) 0x0F) << 56); 
-             const UINT64 newData = (tableEntry->data & ~mask) | 
-                (((UINT64) hashtable->date) << 56); 
-   
-             tableEntry->key = key ^ newData; 
-             tableEntry->data = newData; 
-             hashtable->entriesUsed++; 
-   
-             assert(- getHashentryValue (&- originalEntry ) ==
 
-                    getHashentryValue(tableEntry)); 
-             assert(- getHashentryStaticValue (&- originalEntry ) ==
 
-                    getHashentryStaticValue(tableEntry)); 
-             assert(- getHashentryImportance (&- originalEntry ) ==
 
-                    getHashentryImportance(tableEntry)); 
-             assert(- getHashentryMove (&- originalEntry ) ==
 
-                    getHashentryMove(tableEntry)); 
-             assert(- getHashentryFlag (&- originalEntry ) ==
 
-                    getHashentryFlag(tableEntry)); 
-             assert(- hashtable ->- date  ==-  getHashentryDate (- tableEntry ));
 
-          } 
-   
-          return tableEntry; 
-       } 
-    } 
-   
-    return 0; 
- } 
-   
- UINT64 getNodeIndex(UINT64 key) 
- { 
-    return key % numNodeTableEntries; 
- } 
-   
- bool nodeIsInUse(UINT64 key, UINT8 depth) 
- { 
-    UINT64 nodeIndex = getNodeIndex(key); 
-   
-    return nodeUsageTable[nodeIndex].key == key && 
-       nodeUsageTable[nodeIndex].depth >= depth && key != ULONG_ZERO; 
- } 
-   
- bool setNodeUsage(UINT64 key, UINT8 depth) 
- { 
-    UINT64 nodeIndex = getNodeIndex(key); 
-   
-    if (nodeUsageTable[nodeIndex].key == ULONG_ZERO) 
-    { 
-       nodeUsageTable[nodeIndex].key = key; 
-       nodeUsageTable[nodeIndex].depth = depth; 
-   
-       return TRUE; 
-    } 
-    else 
-    { 
-       return FALSE; 
-    } 
- } 
-   
- void resetNodeUsage(UINT64 key, UINT8 depth) 
- { 
-    UINT64 nodeIndex = getNodeIndex(key); 
-   
-    nodeUsageTable[nodeIndex].key = ULONG_ZERO; 
- } 
-   
- int initializeModuleHash() 
- { 
-    resetNodetable(); 
-    numNodeTableEntries = (long)getPreviousPrime(NODE_TABLE_SIZE); // Pierre-Marie Baty -- added type cast 
-   
-    return 0; 
- } 
-   
- static int testAgeCalculation() 
- { 
-    Hashtable hashtable; 
-   
-    hashtable.date = 0; 
-    assert(- getAge (&- hashtable , (- UINT8 ) (- NUM_DATES  - 1)) == 1);
 
-    assert(- getAge (&- hashtable , 0) == 0);
 
-    assert(- getAge (&- hashtable , 1) == (int) (- NUM_DATES  - 1));
 
-   
-    hashtable.date = 2; 
-    assert(- getAge (&- hashtable , 1) == 1);
 
-    assert(- getAge (&- hashtable , 2) == 0);
 
-    assert(- getAge (&- hashtable , 3) == (int) (- NUM_DATES  - 1));
 
-   
-    hashtable.date = (UINT8) (NUM_DATES - 1); 
-    assert(- getAge (&- hashtable , (- UINT8 ) (- NUM_DATES  - 2)) == 1);
 
-    assert(- getAge (&- hashtable , (- UINT8 ) (- NUM_DATES  - 1)) == 0);
 
-    assert(- getAge (&- hashtable , 0) == (int) (- NUM_DATES  - 1));
 
-   
-    return (hashtable.date == (UINT8) (NUM_DATES - 1) ? 0 : 1); 
- } 
-   
- int testModuleHash() 
- { 
-    int result = 0; 
-   
-    if ((result = testAgeCalculation()) != 0) 
-    { 
-       return result; 
-    } 
-   
-    return 0; 
- } 
-