Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 days ago.
Improve this question
I have a list that stores name and phone number, I would like to be able to do the following:
If the person did not answer me, at the time of running the code, delete the first one from the list, if the second did not answer, I delete the second from the list, if the third did not answer, I delete the third.
Example
Name PhoneNumber
----- ------------
Omar 8296326568
Juan 8296326554
Pedro 8296326456
Lucas 8296324554
So it would be to delete 1 by 1 every time I run the code
Name PhoneNumber
----- ------------
Juan 8296326554
Pedro 8296326456
Lucas 8296324554
Name PhoneNumber
----- ------------
Pedro 8296326456
Lucas 8296324554
Name PhoneNumber
----- ------------
Lucas 8296324554
until the list is empty.
I think what you are asking (and did not say) is that if a call is answered it needs to be removed from the list, but if a call is not answered it remains in the list, but the next number in the list is to be tried. The end result is when you reach the end of the list, you rinse and repeat trying the remaining numbers.
I have implemented this using a Queue<T>, or specifically a Queue<(string name, long phone)> internally in a class to handle this logic.
There is a helper class that simulates a phone call with only 25% chance of a number being answered.
The usage of this code is as follows:
static class Program
{
static void Main(string[] args)
{
PhoneQueue queue = new PhoneQueue();
queue.AddNumber("Omar", 8296326568);
queue.AddNumber("Juan", 8296326554);
queue.AddNumber("Pedro",8296326456);
queue.AddNumber("Lucas",8296324554);
foreach ((string name, long phone) in queue)
{
if (phone != 0)
{
Console.WriteLine($"Called {name}, {phone}");
}
}
}
}
with sample output:
Called Juan, 8296326554
Called Pedro, 8296326456
Called Lucas, 8296324554
Called Omar, 8296326568
Called Juan, 8296326554
Called Lucas, 8296324554
Called Juan, 8296326554
Called Lucas, 8296324554
Called Juan, 8296326554
Called Lucas, 8296324554
Called Juan, 8296326554
Called Lucas, 8296324554
Called Juan, 8296326554
Called Lucas, 8296324554
Called Juan, 8296326554
Called Lucas, 8296324554
Called Juan, 8296326554
Called Lucas, 8296324554
Called Lucas, 8296324554
Called Lucas, 8296324554
And here is the helper call functions:
public enum CallStatus
{
Unknown,
NotAnswered,
Answered,
}
public static class CallCenter
{
readonly static Random random = new Random();
public static CallStatus MakeCall(string name, long phone)
{
if (random.NextDouble() > 0.75)
{
return CallStatus.Answered;
}
return CallStatus.NotAnswered;
}
}
and the core of the business logic implemented in PhoneQueue as an enumerable collection (so that you can iterate over the numbers). Internally it uses a Queue<T> and the .Peek property to see what is next, and .Dequeue() to remove an item from the list and .Enqueue() to add a number to the list.
Look into the MoveNext() method, which makes the call and removes it from the list after the call. But if the call is not answered it re-inserts the number in the queue to be tried later.
public class PhoneQueue :
IEnumerable<(string name, long phone)>,
IEnumerator<(string name, long phone)>
{
readonly Queue<(string name, long phone)> queue;
public PhoneQueue()
{
this.queue = new Queue<(string name, long phone)>();
}
public void AddNumber(string name, long phone)
{
queue.Enqueue((name, phone));
}
public (string name, long phone) Current { get => queue.Count>0 ? queue.Peek() : (string.Empty, 0); }
public int Count { get => queue.Count; }
public bool MoveNext()
{
if (queue.Count == 0) return false;
(string name, long phone) = Current;
queue.Dequeue();
CallStatus status = CallCenter.MakeCall(name, phone);
if (status == CallStatus.NotAnswered)
{
queue.Enqueue((name, phone));
}
return true;
}
public void Reset()
{
queue.Clear();
}
public void Dispose()
{
}
object IEnumerator.Current { get => Current; }
public IEnumerator<(string name, long phone)> GetEnumerator()
{
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm trying to make functions to "send" NPCs to specific rooms by adding them to the room's humansHere list, and one to get this list (and print it later, but I don't need help with that). But I get this error message:
Argument 1: cannot convert from 'System.Collections.Generic.List<Game02.Human>' to 'Game02.Human'
Once I get that fixed, I'm sure I'll figure out the rest, so feel free to ignore this: I need to know how to call this function for specific rooms. Something like:
LivingRoom.GetHumansHere() or Kitchen.SetHumansHere(_lyndonJohnson). Or will this work as it is?
public class Room
{
public int ID { get; set; }
[...]
private List<Human> humansHere;
public List<Human> GetHumansHere()
{
return humansHere;
}
public void SetHumansHere(List<Human> x)
{
humansHere.Add(x);
}
}
public class Human : LivingCreature
{
public int Gold { get; set; }
public List<InventoryItem> Inventory { get; set; }
public Human(string name, int currentHitPoints, int maximumHitPoints, int gold) : base(name, currentHitPoints, maximumHitPoints)
{
Gold = gold;
}
}
Thank you to Dmitry for making it work, and thank you to Jonathan for explaining the problem:
The problem is you are trying to add a LIST of humans to a list rather than a single human to a list
Two possibilities:
If you want to add one person only, change method's signature:
public void SetHumansHere(Human person)
{
if (null == person)
throw new ArgumentNullException(nameof(person));
humansHere.Add(person);
}
If you want to add a collection of persons in one go, use AddRange
// IEnumerable<Human> - let's generalize the method
// and allow to add not only List, but other collections, say, array
public void SetHumansHere(IEnumerable<Human> persons)
{
if (null == persons)
throw new ArgumentNullException(nameof(persons));
humansHere.AddRange(persons);
}
you need to use List.AddRange, Adds the elements of the specified collection to the end of the List.
public void SetHumansHere(List<Human> x)
{
humansHere.AddRange(x);
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm working on an Card Game development in C#, and I don't know how to do the following:
I have my Card class, which has a List of actions that are attacks in which that card can perform.
These attacks are a custom class named Act (in which I called Rules in the example).
When I load my cards I call an Inicialize method that I created that inicialize the List of cards, as well as the List of Attacks of each card.
I Want to be able to express my Attacks as an multiple Method call with parameters that will be called only when I call that Attack for execute.
For example, something like that
ActionList = new List<CardRule>();
ActionList.Add(new CardRule()
{
Description = "Cause 20 damage, then causes burn status.",
Rules = Damage(20).CauseStatus(Status.Burn);
});
I want to define the action(which I called Rules) as an multiple method call, passing parameters,
And call that Rules.Execute() to perform all method call, etc..
I Know that its something related to delegates, but I don't know how to do this calling multiple methods with predefined parameters.
Thank you in advance and sorry for bad english, I'm new at Stack Overflow also..
Regards,
What you're looking for isn't actually a delegate, but a class which tracks what needs to be done. This is a pattern used often by fluent APIs, but it's relatively simple to create something for your example.
For your example, you may have an IActionConfiguration interface, for example:
public interface IActionConfiguration
{
void PerformAction(MyTarget target);
}
Now, you'll want a few different implementations. For example, one which represents damage:
class DamageActionConfiguration : IActionConfiguration
{
private int m_damageStrength;
public DamageActionConfiguration(int strength)
{
m_damageStrength = strength;
}
public void PerformAction(MyTarget target)
{
target.Health -= strength;
}
}
And another one to represent a status effect:
class CauseStatusActionConfiguration : IActionConfiguration
{
private Status m_status;
public CauseStatusActionConfiguration(Status status)
{
m_status = status;
}
public void PerformAction(MyTarget target)
{
target.StatusEffects.Add(m_status);
}
}
Now, you'll also one an implementation which represents multiple actions.
class CompositeActionConfiguration : IActionConfiguration
{
private IActionConfiguration m_firstWrappedConfiguration;
private IActionConfiguration m_secondWrappedConfiguration;
public CompositeActionConfiguration(IActionConfiguration first, IActionConfiguration second)
{
m_firstWrappedConfiguration = first;
m_secondWrappedConfiguration = second;
}
public void PerformAction(MyTarget target)
{
m_firstWrappedConfiguration.PerformAction();
m_secondWrappedConfiguration.PerformAction();
}
}
This is incredibly simplified, but good enough for our example. Now you have a class (CompositeActionConfiguration) which can represent multiple actions - all you need is the magic that lets you chain them together easily.
public static class ActionRules
{
//First, you want a few static methods which can start a chain:
public static IActionConfiguration Damage(int strength)
{
return new DamageActionConfiguration(strength);
}
public static IActionConfiguration Status(Status status)
{
return new CauseStatusActionConfiguration(status);
}
// Next, some extension methods which allow you to chain things together
// This is really the glue that makes this whole solution easy to use
public static IActionConfiguration WithDamage(this IActionConfiguration source, int strength)
{
return new CompositeActionConfiguration(source, Damage(strength));
}
public static IActionConfiguration WithStatus(this IActionConfiguration source, Status status)
{
return new CompositeActionConfiguration(source, Status(status));
}
}
That's it. This gives you a solution which does more or less what you want. You would define your Rules property as an IActionConfiguration, then you can consume it like this:
var card = new CardRule()
{
Description = "Cause 20 damage, then causes burn status.",
Rules = ActionRules.Damage(20).WithStatus(Status.Burn);
};
card.PerformAction(target);
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I am writting some code in C# and I noticed scenario like below. I wonder how can I make this more elegant and easy to maintain.
If I have following scenario with overloads
public void DoSmtg(string a) { DoSmtg(a, 0, 0f); }
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f); }
public void DoSmtg(string a, int x, double d) { // method logic }
say now I need to add another bool parameter. I would have to modify this to
public void DoSmtg(string a) { DoSmtg(a, 0, 0f, false); }
public void DoSmtg(string a, int x) { DoSmtg(a, x, 0f, false); }
public void DoSmtg(string a, int x, double d, bool doIt) { // method logic }
This is a very simple example. It is possible to have say 10 more versions of DoSmtg() method. Clearly, this code smells. While overloading is quite valid, it obviously makes it hard to maintain this code since:
there are many methods to be written
it is not obvious which method is called until careful investigation (especially if method has more parameters)
method gets poluted by growing parameter list
the new parameter added requires changes at many places (think about the methods above called from many different locations)
What would be an elegant, simple and good way to avoid something like this?
You could try adding all the parameters on one function, using default values and name the parameters when you call the function:
public void DoSmtg(string a, int x=0, double d=0f, bool doIt=false) {
// method logic
}
When calling the function, you would then do:
DoSmtg("yo!")
DoSmtg("yo!", d:0.59, doIt:true)
You could wrap all the parameters up in a POCO:
public class SomethingParameters
{
public string A { get; set; }
public int X { get; set; }
public double D { get; set; }
public bool DoIt { get; set; }
}
Then the method signature becomes:
public void DoSmtg(SomethingParameters parameters) { // method logic }
I like this pattern because it's easy to extend in the future. If you need to add five more parameters, or optional parameters, no problem!
You can call it like:
var parameters = new SomethingParameters()
{
A = "foobar",
X = 123,
D = 0.123,
DoIt = false
}
DoSmtg(parameters);
If you have a lot of code calling the old method signature that you don't want to break, you could keep your existing overloads but have them call the new one:
public void DoSmtg(string a, int x, double d, bool doIt)
=> DoSmtg(new SomethingParameters()
{
A = a,
X = x,
D = d,
DoIt = doIt
});
I prefer the option of using a separate class for parameters. But perhaps, as you said, you're already calling the method in multiple places and don't want to modify it.
In that case you can add an optional parameter:
public void DoSmtg(string a, int x, double d, bool doIt = false)
Nothing has to change anywhere else except that you can supply the parameter if you choose to.
If you find yourself doing this I'd still write the extra overload using a class anyway and start using that. Optional parameters can start to get messy too if there are too many of them.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am pretty sure that somewhere this question was answered but i could not find it.
I am looking up Objects from a list with name and quantity. The same Item can come up several times with different quantities. I want to add up the quantities.
bool addtolist = true; //the item is not part of the list
Item currentItem = FindItem(currentMats.Name); //Find the Item in the Catalogue
currentItem.Calc(currentMats.NeededQuantity, product.Runns, product.Level + 1); //Add quantities ect
CompleteList.Add(currentItem);
Here is the problem:
The first time the Algorithm runs all is ok.
The Problem comes up at the second run: the quantity is overridden the moment it hits line 2.
How can i force a new object and not a reference to the one in the storage?
A new instance of an object is only created when the new keyword is used. To get a copy, you'll have to create one
You could create a copy constructor and then a clone method on Item
public Item(Item otherItem){
variable1 = otherItem.variable1;
variable2 = otherItem.variable2;
...
}
public Item Clone(){
return new Item(this);
}
Then when you get the item, clone it
bool addtolist = true; //the item is not part of the list
Item currentItem = FindItem(currentMats.Name).Clone(); //Find the Item in the Catalogue
currentItem.Calc(currentMats.NeededQuantity, product.Runns, product.Level + 1); //Add quantities ect
CompleteList.Add(currentItem);`
Basically what you are doing is a histogram. LINQ has a built in method called GroupBy() that does this. See sample code below:
public class Material
{
public Material(string name, int quantity)
{
this.Name=name;
this.Quantity=quantity;
}
public string Name { get; private set; }
public int Quantity { get; private set; }
}
class Program
{
static void Main(string[] args)
{
List<Material> list=new List<Material>();
list.Add(new Material("AAA", 10));
list.Add(new Material("BBB", 20));
list.Add(new Material("CCC", 5));
list.Add(new Material("AAA", 5));
list.Add(new Material("CCC", 20));
Console.WriteLine("{0,6} {1,6}", "Mat", "Qty");
foreach(var item in list.GroupBy((mat) => mat.Name))
{
Console.WriteLine("{0,6} {1,6}", item.Key, item.Sum((mat) => mat.Quantity));
}
// Mat Qty
// AAA 15
// BBB 20
// CCC 25
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I want to print all the products with a price between 10 and 50 euro.
I have created 2 products in main and I call the method from the class Product in order to make the verification.But it gives me the else branch everytime, "No products".I understand what I'm doing wrong, I create an object reference from the class Product, then I call the method but it gives me the wrong output because in the method I create another object and for this object this price is 0 so it shows me that thing.
But how can I resolve this?
Here there are the classes:
the product class:
class Product
{
public int ProductId;
public string SKU;
public string Name;
public decimal Price;
public string Description;
public string Producer;
public virtual decimal GetPrice()
{
return Price;
}
public virtual String GetName()
{
return Name;
}
public void PrintPrice()
{
Product f = new Product();
if (f.GetPrice() > 10 && f.GetPrice() < 50)
Console.WriteLine("Product: {0}", f.GetName());
else
Console.WriteLine("No products priced between 10 and 50 lei.");
}
public Product() { }
the main where I ve been creating the objects:
static void Main(string[] args)
{
Product f = new Food(1, "green", "Papa", 15, "Good Quality", "Sana");
Product f1 = new Food(2, "white", "Papa1", 45, "Bad Quality", "Ariel");
f.PrintPrice();
f1.PrintPrice();
}
and I have also the food class but it inherits only the Product class so it's not relevant here.So what can I do?Thank you.
public void PrintPrice()
{
Product f = new Product();
....
}
At the moment, f is a new Product without any properties (including no price)
You should do something like
public void PrintPrice()
{
if (this.GetPrice() > 10 && this.GetPrice() < 50)
Console.WriteLine("Product: {0}", this.GetName());
else
Console.WriteLine("No products priced between 10 and 50 lei.");
}
You did not assign a value to the Price, so it's 0 and then you have the "No products"..try to assign a value to the product first