This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 1 year ago.
I 'm creating a Text Base arena rpg where each day new monsters are add to the list, but only one monster get add to the list repeatly with the same stats which for some reason keeps increasing each day.
What i need are that diferent objects with diferent values are created than add to a list, the second part works well.
This method calls the creator.
public static List<Monster> MonsterOfTheDay()
{
int count = 0;
List<Monster> MonstersListOfTheDay = new List<Monster>();
while(count <= 5)
{
MonstersListOfTheDay.Add(Creator());
count++;
}
return MonstersListOfTheDay;
}
This are the creator
public static Monster Creator()
{
Random random = new Random();
Monster monsterChoosen = monsterListPrefab.Find(m => m.Id == random.Next(0, monsterListPrefab.Count -1));
monsterChoosen.Level = random.Next(monsterChoosen.Level, monsterChoosen.Level + 3);
//1Offensive, 2Defensive, 3Balance
monsterChoosen.Type = (Types)typeList.GetValue(random.Next(1, typeList.Length));
Console.WriteLine("Estou Aqui");
int atributes = monsterChoosen.Level * 3;
int spend = 0;
Console.WriteLine("Estou Aqui");
while(spend != atributes)
{
int chance = random.Next(0, 100);
if(monsterChoosen.Type == Types.Offensive)
{
if(chance >= 0 && chance <= 60)
{
monsterChoosen.Str++;
spend++;
}
if(chance >= 61 && chance <= 70)
{
monsterChoosen.Int++;
spend++;
}
if(chance >= 71 && chance <= 85)
{
monsterChoosen.Agi++;
spend++;
}
if(chance >= 86 && chance <= 100)
{
monsterChoosen.Vig++;
spend++;
}
}
else if(monsterChoosen.Type == Types.Defensive)
{
if(chance >= 0 && chance <= 60)
{
monsterChoosen.Vig++;
spend++;
}
if(chance >= 61 && chance <= 70)
{
monsterChoosen.Str++;
spend++;
}
if(chance >= 71 && chance <= 85)
{
monsterChoosen.Int++;
spend++;
}
if(chance >= 86 && chance <= 100)
{
monsterChoosen.Agi++;
spend++;
}
}
else if(monsterChoosen.Type == Types.Balance)
{
if(chance >= 0 && chance <= 25)
{
monsterChoosen.Str++;
spend++;
}
if(chance >= 26 && chance <= 50)
{
monsterChoosen.Int++;
spend++;
}
if(chance >= 51 && chance <= 75)
{
monsterChoosen.Agi++;
spend++;
}
if(chance >= 76 && chance <= 100)
{
monsterChoosen.Vig++;
spend++;
}
}
else if(monsterChoosen.Type == Types.Prefab)
{
spend++;
}
else
{
Console.WriteLine("Error");
}
}
return monsterChoosen;
}
I chance the initial 3 lines of the Creator method, now its working properly, the reason is, as Phillipp said in the game developer stack, the old code keep the information of the monsterChoosen variable and won't generate a new one when called again, keeping the same result and only increasing its stats and level, now with the new line of the variable, monsterChoosen can update every time its called.
Random random = new Random();
int randId = random.Next(2);
Monster monsterChoosen = new Monster(monsterListPrefab.Find(m => m.Id == randId));
Related
How do i use operands in this code? What can i do to resolve this problem? Any suggestions or links to tutorials would be appreciated.
Operator '%' cannot be applied to operands of type 'string' 'int'
int i = 0;
double[] arr1 = new double[20];
for (i = 0; i < 20; i++)
{
Console.Write("Enter a number (0=stop): ");
var year = Console.ReadLine();
if (year == "0") break;
arr1[i] = int.Parse(year);
while (year != 0)
{
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
Console.WriteLine($"{year} is a leap year.");
}
else if (year < 0)
{
Console.WriteLine($"Year must be positive!");
}
else
{
Console.WriteLine($"{year} is not a leap year.");
}`
You are close. You are already parsing the string to an int. Just use that instead of the string year when doing your calculations. Also, I'm not sure what you're trying to do with that while loop but I don't think you need it. It seems to just cause your program to go in an infinite loop because while is evaluating year but there is no opportunity to change the year value within the while loop.
void Main()
{
int i = 0;
double[] arr1 = new double[20];
for (i = 0; i < 20; i++)
{
Console.Write("Enter a number (0=stop): ");
var line = Console.ReadLine();
int numYear = int.Parse(line);
arr1[i] = numYear;
string message = "" ;
if (line != "0")
{
if (numYear < 0)
{
message = "Year must be positive!";
}
else if ((numYear % 4 == 0) && (numYear % 100 != 0)) || (numYear % 400 == 0))
{
message = $"{numYear} is a leap year.");
}
else
{
message = $"{numYear} is not a leap year.");
}
Console.WriteLine(message);
}
}
}
This is not the actual code but it's what I want to do.
for loop is must but the nested if else loop inside should be executed according to the value of count_final which can be random between 1 to 3.
Like if the value of count_final is 3, all if...else loop should be considered. but if the value of count_final is 2, then only if...(1st)else if and else part only be executed. And if count_final=1 then only if and else part is executed (not any else-if).
Thought of putting another if...else within every if...else and checking count_final, but what if I'm not getting values of count2 and count3 when count_final=1.
Same, when count_final=2, I'm not getting the value of count3.
Ask in comment if you don't understand my question.
int count_final=Session["abc"];
//count_final=1;
//count_final=2;
//count_final=3;
for(int i=1;i<=10;i++)
{
if ((count1 <= count5) && (count1 <= count6))
{
Label1.Text="Hello1";
}
else if (count2 <= count4 && count2 <= count6)
{
Label2.Text="Hello2";
}
else if (count3 <= count4 && count3 <= count5)
{
Label3.Text="Hello3";
}
else
{
Label1.Text="Hello1";
}
}
Seems you have collection of "conditions" where amount of executed conditions depend on value of finalCount.
var rules = new Func<string>[]
{
() => (count1 <= count5 && count1 <= count6) ? "Hello1" : null,
() => (count2 <= count4 && count2 <= count6) ? "Hello2" : null,
() => (count3 <= count4 && count3 <= count5) ? "Hello3" : null
};
Label1.Text = rules.Take(finalCount)
.Select(rule => rule())
.Where(result => result != null)
.DefaultIfEmpty("Hello1")
.First();
Of course this solution is assuming that finalCount is always 1, 2 or 3.
DefaultIfEmpty is playing role of last else - will be used all conditions fails.
if i understand right.. which is a little unlikely
just add more criteria to your ifs!
if ((count1 <= count5) && (count1 <= count6))
{
if (count_final == 3 || count_final == 2) Label1.Text="Hello1";
}
else if (count2 <= count4 && count2 <= count6)
{
if (count_final == 3) Label2.Text="Hello2";
}
else if (count3 <= count4 && count3 <= count5)
{
if (count_final == 3) Label3.Text="Hello3";
}
else
{
if (count_final == 3 || count_final == 1) Label1.Text="Hello1";
}
Remembering that from what I understood there will be loops in that can achieve nothing, eg, if count_final == 2 and its not less or equal to count5 or count6, nothing will happen, same as for count_final == 1, if it matches any of the first bits the last else wont happen.
I suggest extending the conditions of your else if statements:
int count_final=Session["abc"];
//count_final=1;
//count_final=2;
//count_final=3;
for(int i=1; i<=10; i++)
{
if ((count1 <= count5) && (count1 <= count6))
{
Label1.Text="Hello1";
}
else if (count_final >= 2 && count2 <= count4 && count2 <= count6)
{
Label2.Text="Hello2";
}
else if (count_final >= 3 && count3 <= count4 && count3 <= count5)
{
Label3.Text="Hello3";
}
else
{
Label1.Text="Hello1";
}
}
When count_final == 1 this will not try to evaluate count2, count3 or count4 (which I understand is a requirement) because && will not evaluate its right hand side when there is false on the left.
Is this what you are looking for? To use less if/else statements:
int count_final = Session["abc"]; // random between 1 and 3
for(int i=1; i <= 10; i++)
{
switch(count_final)
{
case 3:
Label1.Text="Hello1";
// no break; so all gets executed
case 2:
Label2.Text="Hello2";
case 1:
Label3.Text="Hello3";
default: Label1.Text="Hello1";
}
}
I'm trying to make a GameClock like a real clock, but with a custom time.
The clock is running but it is delaying and I can't find the problem. Thanks for help.
IEnumerator Start()
{
while (true) {
Sec = DateTime.Now.Second;
if (Hour == 23 && Min == 59 && Sec == 0){
Hour = 0;
Min = 0;
} else if (Min == 59 && Sec == 0){
Min = 0;
Hour += 1;
} else if (Sec == 0) {
Min += 1;
}
yield return new WaitForSeconds (1f);
}
}
i think it should be like
while (true) {
Sec = DateTime.Now.Second;
if (Hour == 23 && Min == 59 && Sec == 59){
Hour = 0;
Min = 0;
} else if (Min == 59 && Sec == 59){
Min = 0;
Hour += 1;
} else if (Sec == 59) {
Min += 1;
}
yield return new WaitForSeconds (1f);
}
I don't get why you are doing all this work when you can just print out easily:
Debug.Log(System.DateTime.Now.ToString("hh:mm:ss"));
Debug.Log(System.DateTime.Now.Hour.ToString());
Debug.Log(System.DateTime.Now.Minute.ToString());
Debug.Log(System.DateTime.Now.Second.ToString());
I am programming a console "game" and I need to declare a "hp" of character in IF statements which depends on level of this character.
if ((char_level > 0) && (char_level < 4))
{
char_hp = 100;
}
if ((level > 4) && (level < 6))
{
char_hp = 120;
}
if ((level > 6) && (level < 8))
{
char_hp = 150;
}
if ((level > 8) && (level < 10))
{
char_hp = 180;
}
Then I need to use it later in code in a fight. After a successful fight character gets a new level and after that, program will get back to check these IF statements and if level is bigger than 4, character's hp will be increased to 120. But declaration of char_hp in IF statements does not change the value of hp in general and when the next fight comes after reaching level 4, character's hp is still like at the end of previous battle was. I am new in C# programming and I have tried everything but I can't solve it, if it is possible.
The same problem is with the "hp" of enemy that is randomly generated...then I need to use it in that fight
if((level>0) && (level<4))
{
random_enemy_hp = RND.Next(89, 111);
goto enemy;
}
if((level>4) && (level<6))
{
random_enemy_hp = RND.Next(109, 141);
goto enemy;
}
if ((level > 6) && (level < 8))
{
random_enemy_hp = RND.Next(149, 184);
goto enemy;
}
if ((level > 8) && (level < 10))
{
random_enemy_hp = RND.Next(189, 221);
goto enemy;
}
EDIT: I meant "saving values to variables" in IF statements, so I can use them later in code. This is how my code starts, then there are "Console.WriteLine()"-s, principe of a fight and statements shown above.
string name;
int char_hp = 100;
int level = 1;
int random_enemy_hp;
Random RND = new Random();
You're completely on the wrong track. You should be doing something like:
int[] charLevelHp = { 100, 100, 100, 100,
120, 120, 120,
150, 150,
180, 180 };
int charLevel = 1;
int charHp = charLevelHp[charLevel];
I can't help but notice that you're comparing with char_level for your first couple if-statement, but you're comparing to level for your subsequent if-statements
if ((char_level > 0) && (char_level < 4))
{
char_hp = 100;
}
if ((level > 4) && (level < 6))
{
char_hp = 120;
}
I think you might have intended to use char_level for all of the conditions.
if ((char_level > 0) && (char_level < 4))
{
char_hp = 100;
}
if ((char_level > 4) && (char_level< 6))
{
char_hp = 120;
}
If that's the issue, it would be consistent with the kinds of errors you're seeing.
I have a class obj, which has three properties: firstValue, secondValue, thirdValue, all of which range from 0 to 255.
I have a List containing objects of class obj and must divide them into 32 different regions according to the values of firstValue, secondValue and thirdValue. I have been successful using a nested if-else statement like this:
if (obj.firstValue < 15 )
{
if(obj.secondValue <200)
{
if(obj.thirdValue <125)
maincolor[0]++;
else
maincolor[1]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[2]++;
else
maincolor[3]++;
}
}
else if (obj.firstValue < 41)
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[4]++;
else
maincolor[5]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[6]++;
else
maincolor[7]++;
}
}
else if (obj.firstValue < 90)
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[8]++;
else
maincolor[9]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[10]++;
else
maincolor[11]++;
}
}
else if (obj.firstValue < 128)
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[12]++;
else
maincolor[13]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[14]++;
else
maincolor[15]++;
}
}
else if (obj.firstValue < 166)
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[16]++;
else
maincolor[17]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[18]++;
else
maincolor[19]++;
}
}
else if (obj.firstValue < 196)
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[20]++;
else
maincolor[21]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[22]++;
else
maincolor[23]++;
}
}
else if (obj.firstValue < 205)
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[24]++;
else
maincolor[25]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[26]++;
else
maincolor[27]++;
}
}
else
{
if (obj.secondValue < 200)
{
if (obj.thirdValue < 125)
maincolor[28]++;
else
maincolor[29]++;
}
else
{
if (obj.thirdValue < 125)
maincolor[30]++;
else
maincolor[31]++;
}
}
I use maincolor[i] to record the maximum number of the region.
The above method works, but I would like to know if there is any way to make it more readable and less of a performance cost?
Untested, but you get the drift.
EDIT: I've reversed the algorithm to allow early bailout.
int[] firstCutoffs = new int[] { 15, 41, 90, 128, 166, 196, 205 };
int index;
for (int n = 0; obj.firstValue > firstCutoffs[n] && n < firstCutoffs.Length; n++)
index += 4;
if (obj.secondValue >= 200 )
index += 2;
if (obj.thirdValue >= 125 )
index ++;
maincolor[index]++;
When you have three nested if conditions, you can be almost certain that you're doing something wrong.
C# is an object oriented language, so you have to think object!
For instance:
class ColorRange
{
public Range RedRange { get; set; }
public Range GreenRange { get; set; }
public Range BlueRange { get; set; }
}
class Range
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public bool IsInRange(int value)
{
return value >= this.Minimum && value < this.Maximum;
}
}
Then make a GetColorRange method somewhere:
public ColorRange GetColorRange(int red, int green, int blue)
{
foreach (var colorRange in this.Ranges)
{
if (colorRange.RedRange.IsInRange(red)
&& colorRange.GreenRange.IsInRange(green)
&& colorRange.BlueRange.IsInRange(blue))
{
return colorRange;
}
}
return null;
/*
Or with Linq:
return this.Ranges.FirstOrDefault(colorRange =>
colorRange.RedRange.IsInRange(red)
&& colorRange.GreenRange.IsInRange(green)
&& colorRange.BlueRange.IsInRange(blue));
*/
}
Usage:
var colorRange = GetColorRange(20, 175, 200);
// increment the count of this color range in your array
Of course, you're not supposed to use this code 'as is'. It's just to show you how you could redesign your algorithm.
This answer is almost similar to most of the answers here. I just want to stress the use of the break once you found a matching value here:
int[] limitList = new int[] { 15, 41, 90, 128, 166, 196, 205 };
int index = 0;
foreach(int val in limitList)
{
if (obj.firstValue < val)
break; //break on first encounter
index += 4;
}
if (obj.secondValue >= 200)
index+=2;
if (obj.thirdValue >=125)
index++;
maincolor[index]++;
To make the code more readable you could use a 3-dimension array to store the main color category.
int[,,] mainColorCategories = new int [8,2,2];
(note, there are 8 categories for first value, 2 for second and third)
Populate this accordingly with the indices into the main colour array. Then to implement your code you'd implement three functions to determine the indices into this array. These functions need to perform the "if-else-if" evaluations you perform in your code snippet.
int firstValueIndex = getFirstValueIndex(obj.firstValue);
int secondValueIndex = getSecondValueIndex(obj.secondValue);
int thirdValueIndex = getThirdValueIndex(obj.thirdValue);
Then you can increment the correct main color array
int mainColorCat = mainColorCategories[firstValueIndex,secondValueIndex,thirdValueIndex];
maincolor[mainColorCat]++;
I liked this question, I have tried this with a little of LinQ
Dictionary<int,int> firstValue = new Dictionary<int,int>();
firstValue.Add(15,0);
firstValue.Add(41,4);
firstValue.Add(90,8);
firstValue.Add(128,12);
firstValue.Add(166,16);
firstValue.Add(196,20);
firstValue.Add(205,24);
firstValue.Add(256,28);
int mainIndex = 0;
KeyValuePair<int,int> firstIndex = firstValue.FirstOrDefault(x => obj.firstValue < x.Key);
mainIndex = firstIndex.Value;
mainIndex += (obj.secondValue < 200 ? 0 : 2);
mainIndex += (obj.thirdValue < 125 ? 0 : 1);
maincolor[mainIndex]++;
First, I have stored all of your test condition values for the firstValue in a Dictionary with the proper base index to the maincolor, then is simply a math operation to add the remainder values to the index. The advantage is the clear indication of your limits in the Dictionary add methods.
I thought I'd throw this in to the pot for your consideration now that you've accepted an answer.
int index = 0;
if (obj.firstValue < 15)
index = 0;
else if (obj.firstValue < 41)
index = 4;
else if (obj.firstValue < 90)
index = 8;
else if (obj.firstValue < 128)
index = 12;
else if (obj.firstValue < 166)
index = 16;
else if (obj.firstValue < 196)
index = 20;
else if (obj.firstValue < 205)
index = 24;
else
index = 28;
if (obj.secondValue >= 200)
index += 2;
if (obj.thirdValue >= 125)
index++;
maincolor[index]++;
Its much more easier on the eye compared to your original posted coded and has the same
performance.
I was interested to see what the performance difference was between your original code vs my code vs the other answers posted and its become clear to me that using a loop will hurt your performance. I commented #GazTheDestroyer answer that it wouldn't be any faster (See Loop Unwinding > en.wikipedia.org/wiki/Loop_unwinding).
So I wrote a little program to compare the different answers and found that generally the loop type answers are much slower eg #mbm answer. The caveat here is that the performance hit becomes noticeable only when you have a large number of objects to iterate through so in my app I tested with 1000000 items (objects with 1st, 2nd, and 3rd properties).
Just to give you an idea of results for 1000000 items:
Your original code and my example code above executes in about 120 milliseconds
Both #mbm and #Steve answers (using loops) execute in about 650 and 750 milliseconds (respectively). Much, much slower!
I've uploaded the code for the program to github > https://github.com/mouters/SO12295374_SpeedTest so feel free to download and test.
You can try to gain some readability by using LINQ:
// be allObjects an IEnumerable<obj>
maincolor[0] = allObjects.Count(o => o.firstValue < 15 && o.secondValue < 200 && o.thirdValue < 125);