- Home /
[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[i].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[i].ingredients.Count; k++)
{
for(int c = 0; c < ingredients.Count; c++)
{
if(ItemBluePrintDatabase.bluePrints[i].ingredients[k] == ingredients[c])
{
correct++;
break;
}
}
if(correct == ItemBluePrintDatabase.bluePrints[i].ingredients.Count)
{
resultID = ItemBluePrintDatabase.bluePrints[i].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.
To find all things the player can craft, my first attempt on this would be the following:
for each crafting recipe in the database: does the player have all components
So: - For each craftabe item in the database - Get the list of things the player needs to craft this item - look in the players list of items if he has all those items - if the player has all ingredients to craft this item, put the item in a list of craftable items.
If i understood your problem and the above does not help, i can try to put some code in here.
Yeah, the above code that I posted does what you said. It gets all the crafting recipes, then it checks to see if the player has all the ingredients needed for the recipe. If the player does, then resultID equals that, else it is null. The seems to be that the for loop does not check all the recipes, but I am not 100% sure that this is the case.
Answer by Hrungdak · May 10, 2015 at 08:12 AM
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[i].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.
Thanks for the help! all of the ways I have tried have led to the same problem, So I am going to look through all my code to see if I have messed something else up.
I got it to work!
Thank you guys for the help! I got it working after deleting the whole script and starting all over. But I used the way above to search for the blueprints
Thank you :D
Answer by Bunny83 · May 10, 2015 at 04:10 AM
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)).
These changes do not seem to work still. For example, when I just put item 0 in the crafting system the result it supposed to be one, but ins$$anonymous$$d I get 2. This happens whenever I have item 0 in the crafting system with other items too
@Infinite_Gamer: Not really. According to your logic it should return 1 since it's the first that matches your ingredients. You don't seem to be interested in a certain order or item count in your crafting system. The way you do your check is as soon as you have a certain item type in your ingredients list it will accept that item for every item that is required in your blueprint.
There are hundreds of possibilities how crafting recipes can be implemented. From your description it's not clear what you exactly want. As it seems you don't have stacks of items as far as i can tell? Since you always have 9 items in your blueprints, is it possible that you want a similar system to $$anonymous$$inecraft? So shape bound recipes / blueprints? In that case your ingredients list should also represent a 3x3 grid and you only have to compare cell to cell.
resultID = -1;
for(int i = 0; i < ItemBluePrintDatabase.bluePrints.Count; i++)
{
var blueprint = ItemBluePrintDatabase.bluePrints[i];
int correct = 0;
for(int k = 0; k < blueprint.ingredients.Count; k++)
{
if(blueprint.ingredients[k] == ingredients[k])
{
correct++;
}
}
if(correct == blueprint.ingredients.Count)
{
resultID = blueprint.result;
return;
}
}
If you don't want a shape bound system you have to at least mark which items you have already matched with a requested item. Otherwise the same item will be matched again and again. You should start writing down some kind of design document so you understand yourself what logic you actually want.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Illuminating a 3D object's edges OnMouseOver (script in c#)? 1 Answer
Spawning random prefabs at random spawn points (C#) 0 Answers
Inventory List Crafting HELP 0 Answers