diff src/core/inventory.c @ 110:d3bc14c1e243

inventory: add sorting algorithms
author David Demelier <markand@malikania.fr>
date Thu, 02 Apr 2020 18:22:27 +0200
parents ebbf35d90088
children
line wrap: on
line diff
--- a/src/core/inventory.c	Thu Apr 02 12:10:00 2020 +0200
+++ b/src/core/inventory.c	Thu Apr 02 18:22:27 2020 +0200
@@ -18,11 +18,14 @@
 
 #include <assert.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "inventory.h"
 #include "item.h"
 
+#define INVENTORY_TOTAL (INVENTORY_ROWS_MAX * INVENTORY_COLS_MAX)
+
 static bool
 can_be_used(struct inventory_slot *slot, const struct item *item)
 {
@@ -98,6 +101,47 @@
 	return amount;
 }
 
+static bool
+merge(struct inventory_slot *slot, struct inventory_slot *other)
+{
+	assert(slot);
+	assert(slot->item);
+	assert(other);
+
+	/* Not compatible, return false to let the sorting continue. */
+	if (slot->item != other->item)
+		return false;
+
+	while (slot->amount < slot->item->stackable && other->amount) {
+		slot->amount++;
+		other->amount--;
+	}
+
+	/* No more amount in the other slot, empty it. */
+	if (other->amount == 0U)
+		memset(other, 0, sizeof (*other));
+
+	return slot->amount >= slot->item->stackable;
+}
+
+static void
+sort(struct inventory *iv, struct inventory_slot *slot, int r, int c)
+{
+	assert(slot);
+	assert(slot->item);
+
+	/* Merge until the end of thiw row. */
+	for (c = c + 1; c < INVENTORY_COLS_MAX; ++c)
+		if (merge(slot, &iv->items[r][c]))
+			return;
+
+	/* Merge the next rows. */
+	for (r = r + 1; r < INVENTORY_ROWS_MAX; ++r)
+		for (c = 0; c < INVENTORY_COLS_MAX; ++c)
+			if (merge(slot, &iv->items[r][c]))
+				return;
+}
+
 unsigned int
 inventory_push(struct inventory *iv, struct item *item, unsigned int amount)
 {
@@ -117,6 +161,46 @@
 	return amount;
 }
 
+static int
+compare_slot(const void *v1, const void *v2)
+{
+	const struct inventory_slot *slot1 = v1;
+	const struct inventory_slot *slot2 = v2;
+	int cmp;
+
+	/* Two null slots compare equal. */
+	if (!slot1->item && !slot2->item)
+		return 0;
+
+	/* Null left should be moved after. */
+	if (!slot1->item)
+		return 1;
+
+	/* Null right slots should be moved after. */
+	if (!slot2->item)
+		return -1;
+
+	/* If they are identical, use amount to sort. */
+	if ((cmp = strcmp(slot1->item->name, slot2->item->name)) == 0)
+		return (long long int)slot2->amount - (long long int)slot1->amount;
+
+	return cmp;
+}
+
+void
+inventory_sort(struct inventory *iv)
+{
+	assert(iv);
+
+	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r)
+		for (int c = 0; c < INVENTORY_COLS_MAX; ++c)
+			if (iv->items[r][c].item)
+				sort(iv, &iv->items[r][c], r, c);
+
+	/* Sort by names AND by amount. */
+	qsort(iv->items, INVENTORY_TOTAL, sizeof (struct inventory_slot), compare_slot);
+}
+
 void
 inventory_clear(struct inventory *iv)
 {