Creating a tree of required items - c#

As I am developing my small game, I have made a lot of progress yet frustrated about a lot of things. The latest thing was creating a list of required items and for you to understand that I will provide you with both Explanation as well as Code which I created but obviously doesn't work...
I - Explanation
In order for the player to build a building he must have done some required researches with each research requires more researches for it to be researched... It is like a tree of researches that the player will go through them by exploring the game and doing some tasks...
So to imagine it more accurately you can look at my small code here
II - Code
//Available Main Elements
var carbon = new Element {Name = "Carbon"};
var hydrogen = new Element {Name = "Hydrogen"};
var oxygen = new Element {Name = "Oxygen"};
var nitrogen = new Element {Name = "Nitrogen"};
//Example Research
var steam = new Research(name : "Steam", requiredElements: null, requiredResearches: /*Fire*/ & /*Water*/ & /*Iron*/);
So from the last snippet of code [which is just to explain] the player want to research the Steam that for instance needs 3 more researches in order to be researched... one of which the Iron also needs 1 more research to be researched and so on [maybe less maybe more or maybe no requirements at all]...
Concluding that the Question is : How could I create such nesting so that when a player tries to do a research the system quickly looks at the researches he have done and the research he wants to do [including it's nested ones] and If the player did not meet the requirements it just returns a tree with what things he want's to achieve ?
After all, I just want to thank you in advance and I am waiting for your very valuable support...

I would remove the requirement logic out of the Research objects themselves. For simplicity say it was this:
public class Research
{
public string Name { get; set; }
}
Then, I would keep a list of the requirements in a Dictonary where each Research contains a bucket of other Researches:
Dictionary<Research, List<Research>> requiredResearches =
new Dictionary<Research, List<Research>>();
// the list of Researches the player has completed
List<Research> playersResearched = new List<Research>;
For example, "Steam" would contain "Fire", "Water" and "Iron". And maybe "Iron" contains "Tin".
Next, given a Research, we could look at all of it's requierements including requirements of requirements:
// e.g. research is "Steam" and returns "Fire", "Water", "Iron", "Tin"
var chainOfRequirements = GetReq(requiredResearches, research);
That calls a recursive function like this:
public IList<Research> GetReq(Dictionary<Research, List<Research>> reqs,
Research target)
{
var chain = new List<Research>();
if(reqs.ContainsKey(target))
{
foreach(var item in reqs[target])
{
chain.Add(item);
chain.AddRange(GetReq(reqs, item));
}
}
return chain;
}
What you are returned is a flat list of requirements (including requirements of requirements). At that point, a little query against the players list of Researches can return to you which ones that are missing:
var missing = chainOfRequirements.Where (c =>
playerResearches.Where (r => r == c).Any () == false).Distinct();
TO ENABLE COMPARING DICTIONARY USING "NAME"
public sealed class NameEqualityComparer : IEqualityComparer<Research>
{
public bool Equals(Research x, Research y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null)) return false;
if (ReferenceEquals(y, null)) return false;
if (x.GetType() != y.GetType()) return false;
return string.Equals(x.Name, y.Name);
}
public int GetHashCode(Research obj)
{
return (obj.Name != null ? obj.Name.GetHashCode() : 0);
}
}
Here is proof of concept.

I don't know C# well enough to provide code, but you could make each Research have an Array of type Research, that would hold the Research that must be done to be able to make the actual Research, then you only need to iterate the Array checking if all of them are completed.
You don't even need to check the requirements of the requirements, as if they are completed, they already have all requirements completed.
If the Research don't have any requirements you just let the Array empty.

I suggest that you make your own requirementsTree class, which would need to be a linked list with at least the following members:
a requirementsTree[] prerequisiteResearch property, containing all of the research required for that particular item.
a bool isResearched property, indicating if the player has in fact researched the item.
a method, say, bool isEligibleToResearch(), which loops through all of the items in prerequisiteResearch to check if the player has already researched them.
With this I think you'd have a well-structured and extensible requirements class.

I can't think of any specific things that would prevent this from happening, but I can see why you'd be hesitant to just jump into coding it without having thought through the cases. To try to give some pointers, here are some functions I would imagine you having by the end:
// Having a function to retrieve a unique variable by its name (backed by a Dictionary<string, Research>)
// is often handy for me, especially if you decide to script the requirements tree in a text file.
// If you have enough references passed around that you can do this without a static method, all
// the better.
Research.getResearchByName(string name)
// A recursive function. If this research has not been completed, it adds itself to the set, as well
// as any prerequisites (by calling this function on its prerequisites). The top-level, public
// version of this function would create the set, and then return it after performing this check. If
// the Set is empty, then the player can start the research.
Research.addUnresearched_Internal(Set<Research> unresearched)
I think the main issue with my approach here is that I only thought to use a Set, rather than a Tree;
but with some bit of variation, you might be able to do better than me.

One possibility would be to add bool completed to the Element and Research classes. You could then have a function that checks for completed == false for any of its sub-researches.
bool CanCompleteResearch(Research r)
{
for (Research sub in r.requiredResearches)
{
// No need to recursively check 'sub'; in order for 'sub' to be marked as
// completed, its sub-researches must've been already completed.
if (!sub.completed)
return false;
}
return true;
}
I'm sure there's some one-liner trick you can do with LINQ.
EDIT: this only works if a research tree is not being used in more than one place at once (i.e. if you had the research objects shared across multiple player instances).
EDIT 2: In order to figure out all the missing research, you can use a simple recursive function:
void ListMissingResearch(Research r)
{
for (Research sub in r.requiredResearches)
{
if (!sub.completed)
{
// print message saying "Research <r> requires research <sub>"
ListMissingResearch(sub); // list any missing sub-sub-research
}
}
}

It sounds like you want to do something like this:
public class Research
{
private Collection<Research> prerequisites
public Collection<Research> Prerequisites
{
get { return this.prerequisistes; }
}
public bool IsComplete { get; set; }
public IEnumerable<Research> RequiredResearch()
{
if (this.IsComplete)
{
return new Research[0];
}
else
{
return new[] { this }.Concat(
this.Prerequisites.SelectMany(r => r.RequiredResearch()));
}
}
}
If you're making a multi-player, it might have to be something like this:
public class Player
{
private Collection<Research> completedResearch
public Collection<Research> CompletedResearch
{
get { return this.completedResearch; }
}
}
public class Research
{
private Collection<Research> prerequisites
public Collection<Research> Prerequisites
{
get { return this.prerequisistes; }
}
public IEnumerable<Research> RequiredResearch(Player player)
{
if (player.CompletedResearch.Contains(this))
{
return new Research[0];
}
else
{
return new[] { this }.Concat(
this.Prerequisites.SelectMany(r => r.RequiredResearch(player)));
}
}
}
Both these methods will return the current research if it has not been completed (instead of just it's prerequisites). You could simply do a .Skip(1) on the result to ignore the current one, though.

You could use a function like this in your research class that just takes in an enumerable list of Researchs you use to check that the player has the prerequisits. This assumes there is a local list or some other enumerable of Researches called Prereqs in the Research class.
public bool CanHas(IEnumerable<Research> researches)
{
return Prereqs.All((pr) => researches.Contains(pr) && pr.CanHas(researches));
}
The function just recursivly checks each Prereq to see if it is in the list passed in, and then checks that prereqs prereqs. All is a linq extention method that just returns true if all of the elements in the enumerable meet the criteria. If there are no elements, it returns true (all zero of the elements meet the criteria) so this will terminate when you get down to a Research with no Prereqs.
Note: This does a depth first search and is not smart about the same research being a sub-research of more then one prerequisite.

Related

Determine execution flow with nullchecks to operate components as best as possible

Many times I find myself in the need of checking which type of componenent am I handling to make the corresponding operations.
For example:
bool isFooAType = someGameObject.GetComponent<FooA>() != null;
bool isFooBType = someGameObject.GetComponent<FooB>() != null;
if (isFooAType) {
FooA myFooA = someGameObject.GetComponent<FooA>();
//FooA Operations....
}
if (isFooBType) {
FooA myFooB = someGameObject.GetComponent<FooB>();
//FooB Operations....
}
Is there a more condensed or more elegant way to determine the flow of execution depending on the component type to handle the corresponding operations and even maybe avoid doing GetComponent twice (one to check if its null + get again to operate the component in the code successively)?
As mentioned there is TryGetComponent so you do simply
if (someGameObject.TryGetComponent<FooA>(out var fooA))
{
fooA.DoSomething();
}
if (someGameObject.TryGetComponent<FooB>(out var fooB))
{
fooB.DoSomehtingElse();
}
If this is not available (and only then) e.g. due to older Unity versions rather still make the call ONCE and do
var fooA = someGameObject.GetComponent<FooA>();
var fooB = someGameObject.GetComponent<FooB>();
if (fooA)
{
fooA.DoSomething();
}
if (fooB)
{
fooB.DoSomehtingElse();
}
In general you might want both to be exclusive by using else if.
And in particular if both are basically implementing the same method you would rather use a common base class or interface and have only one single TryGetComponent or GetComponent call.

How to stop adding two of the same ID to a list? (C# Multithreading)

I've got an issue which is probably easily solvable, but for some reason I can't wrap my head around...
I have a single list, which contains a class which contains some information. One of these is an ID, which starts from 0 and increases by one with each submission.
When running multiple threads, they submit a different variation of the same ID. This should not be possible, as it checks whether it can be added just before I literally call the List<>().Add.
Any suggestions on how I can avoid this?
Main method:
public static bool AddToList(List<ExampleItem> itemList, List<Xxx> xxx, ExampleItem newItem)
{
ExampleItem lastItem = itemList[itemList.Count - 1];
// We must validate the old item one more time before we progress. This is to prevent duplicates.
if(Validation.ValidateIntegrity(newItem, lastItem))
{
itemList.Add(newItem);
return true;
}
else
return false;
}
Validation method:
public static bool ValidateBlockIntegrity(ExampleItem newItem, ExampleItem lastItem)
{
// We check to see if the ID is correct
if (lastItem.id != newItem.id - 1)
{
Console.WriteLine("ERROR: Invalid ID. It has been rejected.");
return false;
}
// If we made it this far, the item is valid.
return true;
}
Thanks for the suggestions from #mjwills and whoever deleted their answer, I was able to figure out a good method.
I'm now using a ConcurrentDictionary<long, ExampleClass> which means I can both index and add without risking the issue of having duplicated ID's - exactly what I needed.

Elegant way to prevent StackOverflow in Recursion

I'm trying to port this Genetic Algorithm,
and I made a recursive function for advancing from one generation to another.
However, as I'm new to recursion in C# (and in general), I evidently bumped into StackOverflowException when there were too many generations (more than around 4500).
In order to solve the problem, I made Generation() return a bool, so when the genetic algorithm reachs max fitness (goal), it returns true. Else it returns Generation().
If it's about to overflow (Generation > 4500), it returns false.
Now In Main(), to keep Generation() running until it returns true, I use a while loop, so it will start over the recursion until it completes.
This is way more efficient than doing Task.Run, so I went for this approach.
Is this good practice? Are there any more elegant ways of preventing StackOverflows without sacrificing performance?
Population.cs:
class Population
{
public int GenerationNumber { get; private set; }
public int TotalGenerationNumber { get; private set; }
public const int StackGenerationLimit = 4500;
public Population()
{
GenerationNumber = 0;
TotalGenerationNumber = 0;
}
public bool Generation()
{
// Work
// if(HasReachedGoal) return true;
GenerationNumber++;
if(GenerationNumber > StackGenerationLimit)
{
return false;
} else
{
return Generation();
}
}
public void ResetStack()
{
TotalGenerationNumber += GenerationNumber; // I store the total number of generation for information purposes
GenerationNumber = 0; // Reset the recursion depth value
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
Population population = new Population();
while (!population.Generation()) // Until it reaches its goal
{
population.ResetStack();
}
Console.WriteLine("End. Generations: " + population.TotalGenerationNumber);
}
}
The best way to avoid stack overflow is to not use recursion. You're already half way to the answer with your workaround. Now you just need to ask yourself the question of what you gain from recursion any more? If your return Generation(); statement in the Generation function were instead changed to return false; then you would go back to the main loop where it would call Generation() again.
Of course having made this change there are now a lot of other tidy ups you can do. You no longer need your stack reset, you no longer need the if statement that checks for the generation limit and all your repetitions are done from the while loop.
So your two methods:
public bool Generation()
{
TotalGenerationNumber++;
// Work
return HasReachedGoal;
}
static void Main(string[] args)
{
Population population = new Population();
bool hasCompleted = false;
while (!hasCompleted) // Until it reaches its goal
{
hasCompleted = population.Generation();
}
Console.WriteLine("End. Generations: " + population.TotalGenerationNumber);
}
Note that in the tidyup I've introduced a bool variable called hasCompleted since I find it more readable to use a variable for the while condition and prefer to have the work inside the loop itself.
I think in this case, you would be better off preping the while loop and sending in the data you want to check into the .Generation call. then if it returns false, you update the data. Something like this:
Population population = new Population();
var input = new InputDto() { ... };
while (!population.Generation(input)) // Until it reaches its goal
{
// update input
}
This prevents a too deeply nested call that gets the error you are describing.

Current state object - C#

For my current 'testing the waters' project, I'm trying to not use any Try-Catch blocks but instead catch each error (other than fatal) in other ways.
Now, when I say catch errors, my very contrived program makes one error which is easy to avoid; It tries to divide by 0 and this can be prevented by an If statement. To keep it simple I have only 1 C# file, with 1 class and two methods. I guess this is like a template, where the Constructor starts a process:
public class myObject
{
public myObject()
{
Object objOne = methodOne();
methodThree(objOne);
}
public object methodOne()
{
//logic to create a return object
int x = 0;
//I've added a condition to ensure the maths is possible to avoid raising an exception when, for this example, it fails
if (x > 0)
int y = 5 / x;
return object;
}
public void procesObjects(Object objOne)
{
//logic
}
}
So, as you can see in methodOne() I've added the if statement to ensure it checks that the maths isn't dividing by 0. However, since I've caught it, my application continues which is not desired. I need a way to cease the application and log the failing for debugging.
So, this is what I think could work:
Create a class called Tracking which for this example, is very simple (or would a struct be better?).
public class Tracking
{
StringBuilder logMessage = new StringBuilder();
bool readonly hasFailed;
}
I can then update my code to:
public class myObject
{
Tracking tracking = new Tracking();
public myObject()
{
Object objOne = methodOne();
if (!tracking.hasFailed)
methodThree(objOne);
if (tracking.hasFailed)
ExteranlCallToLog(tracking);
}
public object methodOne()
{
//logic
int x = 0;
//I've added a condition to ensure the maths is possible to avoid raising an exception when, for this example, it fails
if (x > 0)
int y = 5 / x;
else
{
tracking.hasFailed = true;
tracking.logMessage.AppendLine("Cannot divide by 0");
}
//may also need to check that the object is OK to return
return object;
}
public void procesObjects(Object objOne)
{
//logic
}
}
So, I hope you can see what I'm trying to achieve but I have 3 questions.
Should my tracking object (as it is in this example) be a class or a struct?
I'm concerned my code is going to become very noisy. I'm wondering if when the system fails, it raises an event within the Tracking object which logs and then somehow closes the program would be better?
Any other ideas are very welcome.
Again, I appreciate it may be simpler and easier to use Try-Catch blocks but I'm purposely trying to avoid them for my own education.
EDIT
The reason for the above was due to reading this blog: Vexing exceptions - Fabulous Adventures In Coding - Site Home - MSDN Blogs
Seriously, Dave - try catch blocks are there for a reason. Use them.
Reading between the lines, it looks like you want to track custom information when something goes wrong. Have you considered extending System.Exception to create your own bespoke implementation suited to your needs?
Something along the lines of:-
public class TrackingException : System.Exception
{
// put custom properties here.
}
That way, when you detect that something has gone wrong, you can still use try/catch handling, but throw an exception that contains pertinent information for your needs.

Is this design for data validation on a class a good idea?

I've got this class, let's call it Refund (because that's what it's called). I want to validate some things about this Refund and the Customer it's attached to, and I want to make these validations re-orderable, because the first one that trips will be stored as the reject reason on the Refund, and also some of them are likely to be more resource-intensive than others and more likely to be tripped, so I'd like to be able to easily reorder their execution so that I could squeeze some performance out if I need to.
All of the validation methods will take a Refund object and return a boolean denoting whether the validation has passed or failed. So, I was thinking, why not make a queue (or other data structure) to hold delegates/lambdas/anonymous functions, each representing a validation method? Then, just passing the Refund into some kind of static Validate(Refund refundToValidate) method on some Validator class. This method would walk through the array of delegates, calling each in sequence, and returning false if one of them produced false.
Is this a good idea or a stupid idea? If it's a good idea, can you point me to a resource somewhere or name a pattern that I am inadvertantly implementing, so that I know I'm doing it right? If it's a stupid idea, why and what should I be doing differently?
EDIT: here's what I've got so far-
public static class Validator
{
delegate REFUNDDENIALREASONS validationHandler(BatchRefund refundToValidate);
public static List<REFUNDDENIALREASONS> ValidateRefund(BatchRefund refundToValidate)
{
List<Delegate> Validations = new List<Delegate>();
List<REFUNDDENIALREASONS> DenialReasons = new List<REFUNDDENIALREASONS>();
Validations = new List<Delegate>();
validationHandler blockHandler = ValidateBlocks;
Validations.Add(blockHandler);
validationHandler accountHandler = ValidateCustomerAccountStatus;
Validations.Add(accountHandler);
foreach (validationHandler v in Validations)
{
DenialReasons.Add(v(refundToValidate));
}
return DenialReasons;
}
public static REFUNDDENIALREASONS ValidateCustomerAccountStatus(BatchRefund refundToHandle)
{
REFUNDDENIALREASONS denialReason;
switch (refundToHandle.RefundCustomer.CustStatus)
{
case "C":
denialReason = REFUNDDENIALREASONS.None;
break;
case "Y":
denialReason = REFUNDDENIALREASONS.AccounthasrecentChargebackNSF;
break;
default:
denialReason = REFUNDDENIALREASONS.Fraud;
break;
}
return denialReason;
}
public static REFUNDDENIALREASONS ValidateBlocks(BatchRefund refundToHandle)
{
List<CustomerBlock> blocks = refundToHandle.RefundCustomer.Blocks;
//add new codes to block here
string[] illegalblockcodes = new string[] { "L1", "C1" };
foreach (string code in illegalblockcodes)
if (blocks.Exists(b => b.BkClassCode == code))
{
return REFUNDDENIALREASONS.Fraud;
}
return REFUNDDENIALREASONS.None;
}
}
You're basically describing a tweak on the Chain-of-responsibility design pattern. There are advantages and disadvantages to this, but it is a good option if you want the flexibility of adding other operations onto your queue at any point in time.
Not necessarily a bad idea. Do you intend to keep track of which validation failed? If you're using a static method that runs it through a queue how are you going to tell?

Categories

Resources