[Answered](C#)Comparing two Lists for a Crafting System

Hello Community,

I am am making a crafting system. What I am doing is getting the item IDs that are in the crafting slots and putting them into the ingredients List. Then I am checking to see if the ingredients in the database are equal to the ingredients I have in the crafting system.

I have been at this for a while now. I have been searching around, I found a lot of examples that compare two Lists. I have tried many of these examples but none of them end up with the right result.

For some reason it seems that the for loop skips the the first elements that are in the database List and only checks the last element. I am not sure if this is the only problem.

Here is a Snippet from my crafting system

//Crafting System C#
	public void SearchIngredients()
	{
		int e = 0;
		for(int i = 0; i < essentials.items.Count; i++)
		{
			ingredients[e] = essentials.items*.item.id;*
  •  	e++;*
    
  •  }*
    
  •  FindResultItem();*
    
  • }*

  • void FindResultItem()*

  • {*

  •  int correct = 0;*
    
  •  for(int i = 0; i < ItemBluePrintDatabase.bluePrints.Count; i++)*
    
  •  {*
    

_ for(int k = 0; k < ItemBluePrintDatabase.bluePrints*.ingredients.Count; k++)_
_
{_
_
for(int c = 0; c < ingredients.Count; c++)_
_
{_
_ if(ItemBluePrintDatabase.bluePrints.ingredients[k] == ingredients*
```c_

*)
{
correct++;
break;
}
}

				if(correct == ItemBluePrintDatabase.bluePrints*.ingredients.Count)
				{
					resultID = ItemBluePrintDatabase.bluePrints*.result;
					break;
				}
				else
					resultID = -1;
			}
		}
	}

And here is my whole database script

//ItemBluePrintDatabase
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class ItemBluePrint
{
	public List<int> ingredients = new List<int>();
	public int result = -1;

	public ItemBluePrint(List<int> ingredientItems, int resultItem)
	{
		ingredients = ingredientItems;
		result = resultItem;
	}
}

public class ItemBluePrintDatabase : MonoBehaviour
{
	public static List<ItemBluePrint> bluePrints = new List<ItemBluePrint>();

	void Start()
	{
		bluePrints.Add(new ItemBluePrint(new List<int>(new int[]{-1, 0, -1, -1, 0, -1, -1, 0, -1}), 2));
		bluePrints.Add(new ItemBluePrint(new List<int>(new int[]{0, -1, -1, -1, -1, -1, -1, -1, -1}), 1));
		bluePrints.Add(new ItemBluePrint(new List<int>(new int[]{0, 1, -1, -1, -1, -1, -1, -1, -1}), 2));
		
	}
}

Thanks for the help in advance.
_```*_

In line 33 you should replace the “break” with a “return”. You just break out of the second loop but not out of the first. So even when you’ve found the correct blueprint you continue checking all others. Since you set the resultID to -1 if it doesn’t match the only blueprint it can detect is the last one.

Next problem is your “correct” counter should be resetted for each blueprint (set it to 0 before you start the second loop (line 19)).

For the first, it’s a bad idea to nest three for-loops. The problems you have can be easily solved if you avoid this. First: write a method that compares one blueprint to the ingredients.

        private bool IsCraftable(ItemBluePrint bluePrint, int[] playerIngredients)
        {
            // ensure that all ingredients in blueprint.ingredients are in playerIngredients
            foreach (int ingredient in bluePrint.ingredients)
            {
                if (!playerIngredients.Contains<int>(ingredient))
                    return false;
            }

            return true;
        }

Next: cycle through each blueprint in the database and return the first that is craftable with the ingredients of the player:

        public void FindResultItem()
        {
            resultId = -1;

            foreach (ItemBluePrint bluePrint in ItemBluePrintDatabase.bluePrints)
            {
                if (IsCraftable(bluePrint, ingredients))
                {
                    resultId = bluePrint.result;
                    break;
                }
            }

            return result;
        }

FindResultItem sets the resultId to the first bluePrint that can be crafted with the ingredients of the player. There are some other coding issues in this solution. First, FindResultItem has a non obvious side effect by setting resultId. FindResultItem should return the id and SearchIngredients should handle the result:

        public void SearchIngredients()
        {
            int e = 0;
            for (int i = 0; i < essentials.items.Count; i++)
            {
                ingredients[e] = essentials.items*.item.id;*

e++;
}

resultId = FindResultItem();
}

public int FindResultItem()
{
int localResultId = -1;

foreach (ItemBluePrint bluePrint in ItemBluePrintDatabase.bluePrints)
{
if (IsCraftable(bluePrint, ingredients))
{
localResultId = bluePrint.result;
break;
}
}

return localResultId;
}
Hope that helps.
Another issue is the name of the method SearchIngredients. A better name would be SearchCraftableBlueprint or something like that. Method names should reflect the purpose of the method. That may not lok like a big thing, but if you get used to this, your code will get much better readable. And if we just speak of this, FindResultItem should rename to FindCraftableBlueprintItemId.