(svn r2165) - Codechange: [NPF] Properly enummed NPF hash size, it is easily changable now.
authormatthijs
Thu, 07 Apr 2005 19:19:16 +0000
changeset 1661 6af0c4416154
parent 1660 92ffb9ef5240
child 1662 9f8c03dbc1bd
(svn r2165) - Codechange: [NPF] Properly enummed NPF hash size, it is easily changable now.
- Codechange: [NPF] Improved the NPF hash calculation slightly.
- Codechange: [NPF] Increased hash size, should speed up somewhat.
npf.c
npf.h
queue.c
queue.h
--- a/npf.c	Thu Apr 07 10:50:55 2005 +0000
+++ b/npf.c	Thu Apr 07 19:19:16 2005 +0000
@@ -102,9 +102,19 @@
 
 uint NTPHash(uint key1, uint key2)
 {
+	/* This function uses the old hash, which is fixed on 10 bits (1024 buckets) */
 	return PATHFIND_HASH_TILE(key1);
 }
 
+uint NPFHash(uint key1, uint key2)
+{
+	/* TODO: think of a better hash? */
+	uint part1 = TileX(key1) & NPF_HASH_HALFMASK;
+	uint part2 = TileY(key1) & NPF_HASH_HALFMASK;
+	/* The value of 14 below is based on the maximum value of key2 (13) */
+	return ((((part1 << NPF_HASH_HALFBITS) | part2)) + (NPF_HASH_SIZE * key2 / 14)) % NPF_HASH_SIZE;
+}
+
 int32 NPFCalcZero(AyStar* as, AyStarNode* current, OpenListNode* parent) {
 	return 0;
 }
@@ -809,7 +819,7 @@
 
 void InitializeNPF(void)
 {
-	init_AyStar(&_npf_aystar, NTPHash, 1024);
+	init_AyStar(&_npf_aystar, NPFHash, NPF_HASH_SIZE);
 	_npf_aystar.loops_per_tick = 0;
 	_npf_aystar.max_path_cost = 0;
 	_npf_aystar.max_search_nodes = 0;
--- a/npf.h	Thu Apr 07 10:50:55 2005 +0000
+++ b/npf.h	Thu Apr 07 19:19:16 2005 +0000
@@ -8,6 +8,13 @@
 //#define NPF_DEBUG
 //#define NPF_MARKROUTE //Mark the routes considered by the pathfinder by
 //mowing grass
+enum {
+	NPF_HASH_BITS = 12, /* The size of the hash used in pathfinding. Just changing this value should be sufficient to change the hash size. Should be an even value. */
+	/* Do no change below values */
+	NPF_HASH_SIZE = 1 << NPF_HASH_BITS,
+	NPF_HASH_HALFBITS = NPF_HASH_BITS / 2,
+	NPF_HASH_HALFMASK = (1 << NPF_HASH_HALFBITS) - 1
+};
 
 typedef struct NPFFindStationOrTileData { /* Meant to be stored in AyStar.targetdata */
 	TileIndex dest_coords; /* An indication of where the station is, for heuristic purposes, or the target tile */
--- a/queue.c	Thu Apr 07 10:50:55 2005 +0000
+++ b/queue.c	Thu Apr 07 19:19:16 2005 +0000
@@ -443,9 +443,10 @@
  * Hash
  */
 
-void init_Hash(Hash* h, Hash_HashProc* hash, int num_buckets) {
+void init_Hash(Hash* h, Hash_HashProc* hash, uint num_buckets) {
 	/* Allocate space for the Hash, the buckets and the bucket flags */
-	int i;
+	uint i;
+	uint max_hash;
 	assert(h);
 	#ifdef HASH_DEBUG
 	debug("Allocated hash: %p", h);
@@ -502,10 +503,54 @@
 		free(h);
 }
 
+void stat_Hash(Hash* h)
+{
+	uint used_buckets = 0;
+	uint max_collision = 0;
+	uint max_usage = 0;
+	uint usage[200];
+	uint i,j;
+	uint collision;
+	HashNode* node;
+
+	for (i=0;i<200;i++) usage[i] = 0;
+	for (i=0;i<h->num_buckets;i++) {
+		collision = 0;
+		if (h->buckets_in_use[i]) {
+			used_buckets++;
+			node = &h->buckets[i];
+			while (node != NULL) {
+				collision++;
+				node = node->next;
+			}
+			if (collision > max_collision) max_collision = collision;
+		}
+		if (collision > 199) collision = 199;
+		usage[collision]++;
+		if (collision >0 && usage[collision] >= max_usage) max_usage = usage[collision];
+	}
+	printf("---\nHash size: %d\nNodes used: %d\nNon empty buckets: %d\nMax collision: %d\n", h->num_buckets, h->size, used_buckets, max_collision);
+	printf("{ ");
+	for (i=0;i<=max_collision;i++)
+		if (usage[i]) {
+			printf("%d:%d ", i, usage[i]);
+			/*if (i>0)
+				for (j=0;j<(usage[i] * 160 / 800);j++)
+					printf("#");
+			printf("\n");
+			*/
+		}
+	printf ("}\n");
+}
+
 void clear_Hash(Hash* h, bool free_values)
 {
 	uint i;
 	HashNode* node;
+#ifdef HASH_STATS
+	if (h->size > 2000)
+		stat_Hash(h);
+#endif
 	/* Iterate all buckets */
 	for (i=0;i<h->num_buckets;i++)
 	{
--- a/queue.h	Thu Apr 07 10:50:55 2005 +0000
+++ b/queue.h	Thu Apr 07 19:19:16 2005 +0000
@@ -4,6 +4,7 @@
 //#define NOFREE
 //#define QUEUE_DEBUG
 //#define HASH_DEBUG
+//#define HASH_STATS
 
 
 typedef struct Queue Queue;
@@ -142,7 +143,8 @@
 	void* value;
 	HashNode* next;
 };
-/* Generates a hash code from the given key pair. You should make sure that
+/**
+ * Generates a hash code from the given key pair. You should make sure that
  * the resulting range is clearly defined.
  */
 typedef uint Hash_HashProc(uint key1, uint key2);
@@ -184,7 +186,7 @@
 Hash* new_Hash(Hash_HashProc* hash, int num_buckets);
 /* Builds a new hash in an existing struct. Make sure that hash() always
  * returns a hash less than num_buckets! Call delete_hash after use */
-void init_Hash(Hash* h, Hash_HashProc* hash, int num_buckets);
+void init_Hash(Hash* h, Hash_HashProc* hash, uint num_buckets);
 /*
  * Deletes the hash and cleans up. Only cleans up memory allocated by new_Hash
  * & friends. If free is true, it will call free() on all the values that