So I'm working on a game that uses a coordinate system, and I want to populate the map with a certain number of trees. The way I'm doing it (and it may not be the best way) is picking a random set of coordinates, checking to see if those coordinates are in the list of locations with trees in them, and if not adding the tree to the map, and adding those coordinates to the list. My instinct was to store the coordinates as an array, however I can't seem to figure out the syntax for it. Here's what I have:
int boardWidth = 10;
int boardHeight = 10;
int numTrees = 75;
List<int[]> hasTree = new List<int[]>();
public Transform tree;
Transform[,] SetTrees(Transform[,] map) {
int treex = Random.Range(0,boardWidth-1);
int treey = Random.Range(0,boardHeight-1);
int[] treeCoords = new int[] { treex,treey };
int treeCount = 0;
while(treeCount < numTrees){
if (hasTree.Contains(treeCoords)){
treex = Random.Range(0,boardWidth-1);
treey = Random.Range(0,boardHeight-1);
}
else{
map[treex,treey] = (Transform)Instantiate(tree, new Vector3(i*tileWidth, 10, j*tileHeight), Quaternion.AngleAxis(90, Vector3.left));
hasTree.Add(treeCoords);
treex = Random.Range(0,boardWidth-1);
treey = Random.Range(0,boardHeight-1);
treeCount++;
}
}
return(map);
}
Any thoughts?
If I were you I'd try something like this:
int boardWidth = 10;
int boardHeight = 10;
int numTrees = 75;
var rnd = new Random();
var query =
from x in Enumerable.Range(0, boardWidth)
from y in Enumerable.Range(0, boardHeight)
orderby rnd.NextDouble()
select new { x, y };
var board = new bool[boardWidth, boardHeight];
foreach (var pair in query.Take(numTrees))
{
board[pair.x, pair.y] = true;
}
Keep It Simple Silly:
Transform[,] SetTrees(Transform[,] map) {
for(int treeCount = 0; treeCount < numTrees; treeCount++){
int treex = Random.Range(0,boardWidth-1);
int treey = Random.Range(0,boardHeight-1);
map[treex,treey] = new TreeTransform(treex, treey}
}
return(map);
}
Bury the details of Tree creation in its constructor TreeTransform, where it belongs.
Who cares about a creation ordering of the trees on the board? it has no use.
There is no reason for the number of trees to be exact, so just ignore duplicates.
Simplify the code then it might be easier to determine your best course of action.
I simplify by breaking down the problem until its so simple I can't really see how not to do it !!!
I am guessing how some of this code works here but I think you want something like this ...
Transform[,] SetTrees(Transform[,] map) {
for (int i = 0; i < numTrees; i++){
if(!AddTreeTo(map)){
--i;
}
}
return(map);
}
bool AddTreeToMap(Transform[,] map)
{
int[] treeCoord = GetRandomCoord(map.Width, map.Height);
if (!map[treeCoord[0],treeCoord[1]].HasTree()){
map[treex,treey] = (Transform)Instantiate(tree, new Vector3(i*tileWidth, 10, j*tileHeight), Quaternion.AngleAxis(90, Vector3.left));
map[treeCoord[0],treeCoord[1]].Add(treeCoords);
return true;
}
return false;
}
int[] GetRandomTreeCoord(int maxX, int maxY)
{
int treex = Random.Range(0,maxX-1);
int treey = Random.Range(0,maxY-1);
int[] treeCoords = new int[] { treex,treey };
return treeCoords;
}
Related
I did this
public int[] sceneIndex;
public Text[] texts;
IEnumerator ChoosingModes()
{
string[] modes = new string[] { "Cocks", "Tanks", "Cars" };
sceneIndex = new int[] { };
for (int i = 0; i < 5; i++)
{
int x = Random.Range(0, modes.Length);
texts[i].text = modes[x];
sceneIndex[i] = x + 3;
yield return new WaitForSeconds(0.75f);
}
}
It obviously doesn't work, what to do with my in array named 'sceneIndex'?
When you do sceneIndex = new int[] { };, you're locking the length of the length of sceneIndex to 0. Instead, try either sceneIndex = new int[number or scenes]; (locking the length of sceneIndex to the number of scenes you have) or just doing nothing. Since the array is public, you can set the values in the inspector and you won't have to define it in the code.
Please check the code below. I am trying to set value to a random property of a int list. Problem is that even after i set 5 to a random list this value getting inserted to that property. What am I doing wrong here?
var TransactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
TransactionList.Add(0);
}
var randTransaction = TransactionList.OrderBy(x => Guid.NewGuid()).FirstOrDefault();
//here i am trying to set 5 value to a random TrnasactionList but this not being set
randTransaction = 5;
Try like below. new Random().Next(0, 59); will return value between 0 and 59. Or you can better set it like new Random().Next(0, TransactionList.Count); for it to be dynamic with list.
new Random().Next(minValue, maxValue); The maxValue for the upper-bound in the Next() method is exclusive—the range includes minValue, maxValue-1, and all numbers in between.
var TransactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
TransactionList.Add(0);
}
// var index = new Random().Next(0, 59);
// Below will work for dynamic length of list.
var index = new Random().Next(0, TransactionList.Count);
TransactionList[index] = 5;
If you don't mind the original list getting sorted you could do this:
class Program
{
static void Main(string[] args)
{
var transactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
//I initialized the list with i instead of 0 to better see sorting in place
transactionList.Add(i);
}
transactionList.Sort(new RandomComparer());
//changed it to 99 to spot it more easily
transactionList[0] = 99;
foreach (var i in transactionList)
Console.WriteLine(i);
}
}
public class RandomComparer : IComparer<int>
{
private Random _random = new Random();
public int Compare(int x, int y)
{
return _random.Next(-1, 2);
}
}
See it in action:
https://dotnetfiddle.net/NKuPdx
randTransaction is "int" data type, which is primitive data type.
if you want to set randTransaction that reflect to it's object, just set the object it self
I'm making a basic Deal or No Deal game, in doing so I have to pick 10 finalists from an array, at random, without repeats.
I have my structure and arrays set out like this
public struct People
{
public string firstname;
public string lastname;
public int age;
}
class Program
{
public static People[] People1 = new People[40];
public static People[] Finalists1 = new People[10];
public static People[] Finalist1 = new People[1];
And my finalists method set out like this
Random rand = new Random();
for (int i = 0; i < Finalists1.Length; i++)
{
num = rand.Next(0, People1.Length);
Finalists1[i].lastname = People1[num].lastname;
Finalists1[i].firstname = People1[num].firstname;
Finalists1[i].age = People1[num].age;
}
How can I eliminate duplicate entries, while maintaining 10 people in the array?
Since initial array doesn't contain duplicates, you can sort it in random order and pick up 10 top items:
Finalists1 = People1
.OrderByDescending(item => 1) // if people have some points, bonuses etc.
.ThenBy(item => Guid.NewGuid()) // shuffle among peers
.Take(10) // Take top 10
.ToArray(); // materialize as an array
If people are selected to the final are not completely random (e.g. contestant can earn points, bonuses etc.) change .OrderByDescending(item => 1), e.g.
.OrderByDescending(item => item.Bonuses)
If you don't want to use Linq, you can just draw Peoples from urn without returning:
private static Random random = new Random();
...
List<People> urn = new List<People>(People1);
for (int i = 0; i < Finalists1.Length; ++i) {
int index = random.Next(0, urn.Count);
Finalists1[i] = urn[index];
urn.RemoveAt(index);
}
You can hold a list or hash set of numbers you have already drawn. Then just roll the dice again to get another random number.
Random rand = new Random();
HashSet<int> drawnNumbers = new HashSet<int>();
for (int i = 0; i < Finalists1.Length; i++)
{
do
{
num = rand.Next(0, People1.Length);
}
while (drawnNumbers.Contains(num));
Finalists1[i] = People1[num];
}
You can change the type of Finalists1 to a HashSet, that does not allow duplicates.
Then change your loop to
while(Finalists1.Length < 10)
{
// random pick from array People1 (you don't need to create a new one)
num = rand.Next(0, People1.Length);
var toAdd = People1[num];
// add to hash-set. Object won't be added, if already existing in the set
Finalists1.Add(toAdd);
}
You probably need to override the Equals method of class People, if you really need to create a new object to add to the hash-set.
You can group people array and select distinct that way.
If you use List you can remove person from the list
`var peopleArray = new People[40];
var peopleCollection = peopleArray.GroupBy(p => new { p.age, p.firstname, p.lastname }).Select(grp => grp.FirstOrDefault()).ToList();
var finalists = new People[10];
var rand = new Random();
for (var i = 0; i < finalists.Length; i++)
{
var index = rand.Next(0, peopleCollection.Count);
var person = peopleCollection[index];
finalists[i].lastname = person.lastname;
finalists[i].firstname = person.firstname;
finalists[i].age = person.age;
peopleCollection.Remove(person);
}
shuffle and take the first 10, for example
People1.Shuffle();
Finalists1= People1.Take(10).ToArray();
you can find shuffle code from StackOverflow or search for "Fisher-Yates shuffle C#" Below methods are taken from This SO Post. Read the answers for more information on why GUID is not used etc..
public static class ThreadSafeRandom
{
[ThreadStatic] private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
}
}
static class MyExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
Swap each selected element in People1 to with the end of the array, and decrement an end-of-array index so that you're only selecting from what's left on the next iteration.
People tempPerson = new People;
int lastElem = People1.length - 1;
for (int i = 0; i < Finalists1.Length; i++)
{
num = rand.Next(0, lastElem + 1);
Finalists1[i] = People1[num];
//swap last entry in People1 with People1[num]
tempPerson = People1[num];
People1[num] = People1[lastElem];
People1[lastElem] = tempPerson;
lastElem--;
}
Sorry if there's a syntax error, I'm mostly using Java and C# these days.
BTW You don't have to set the fields individually since each array stores objects of type Person.
Heres a fun problem I have.
I have a function that returns a var of items;
var Items = new { sumList = SumList, ratesList = List, sum = List.Sum() };
return Items;
From a function that is dynamic:
public override dynamic GetRates()
and I return it to a function I else where and try to apply it to my code:
dynamic res = cl.mainC.GetRates();
List<double> MashkantaSumList = res.sumList;
Now when I try to apply it, it says the object doesnt exist. But if I look in the debugger the items are happily there as a generic list or what not.
How do I resolve this?
EDIT:
as per request I'll post the full code:
//virtual
public virtual dynamic TotalMashkanta(int i, double sum, double ribit, string[] discount)
{
return 0;
}
//override
public override dynamic TotalMashkanta(int i, double sum, double ribit, string[] discount)
{
double SumTemp = sum;
double monthlyRibit = ribit / 12;
Double permPayPerMont = Financial.Pmt(monthlyRibit, i, sum, 0, DueDate.EndOfPeriod);
List<double> MashkantaList = new List<double>();
List<double> MashkantaSumList = new List<double>();
for (int j = 1; j <= i; j++)
{
MashkantaList.Add(Mashkanta(j, sum, ribit, permPayPerMont) * (1 - CalcDiscount((j / 12) + 1, discount)));
SumTemp = getSum(j, sum, ribit, permPayPerMont * -1); ;
MashkantaSumList.Add(SumTemp);
}
var K_Mashkanta = new { sumList = MashkantaSumList, ratesList = MashkantaList, sum = MashkantaList.Sum() };
return K_Mashkanta;
}
//Function that calls the results
public void GetSilukinTable(string Path, string ClientID, DAL.Client client, string partner_checked, string insurance_Amount, string Premiya_Structure_Mashkanta, string Premiya_Life_Mashkanta, string Discount_Life_Mashkanta, string Loan_Period,string Loan_EndDate, string Bank, string Loan_Interest, string Loan_Amount, string Discount_Loan, string AgentNotes, string ManID)
{
BL.CalculateLogic.Companies t = BL.CalculateLogic.Companies.כלל;
if(ManID == "211") t = BL.CalculateLogic.Companies.הפניקס;
if(ManID == "207") t = BL.CalculateLogic.Companies.הראל;
if(ManID == "206") t = BL.CalculateLogic.Companies.מנורה;
if(ManID == "208") t = BL.CalculateLogic.Companies.הכשרה;
BL.CalculateLogic cl = new BL.CalculateLogic(client, t);
DateTime LoanEnd = DateTime.Now;
int months = 0;
if (DateTime.TryParse(Loan_EndDate, out LoanEnd))
months = BL.Calculating_Companies.Company.GetMonthsBetween(DateTime.Now, LoanEnd);
else
months = Int32.Parse(Loan_Period) * 12;
string[] Discount = Discount_Loan.Split('-');
dynamic res = cl.mainC.TotalMashkanta(months, Double.Parse(Loan_Amount), Double.Parse(Loan_Interest.Trim('%')), Discount);
var MashkantaSumList = res.sumList;
List<double> MashkantaList = res.ratesList;
List<double> MashkantaSumListPartner = new List<double>();
List<double> MashkantaListPartner = new List<double>();
List<double> MashkantaListSum = res.ratesList;
}
The compiler is happy about it because dynamic is compiled and checked at run time. Whatever the problem is, the types don't match. It evaluates this at run time, so you won't see issues at compile time. (Advice: use dynamic only when you really must! Else you will have this kind of problems all the time!)
I tried your code using this and it works fine:
static dynamic GetRates()
{
List<double> SumList = new List<double>();
List<double> List = new List<double>();
var Items = new { sumList = SumList, ratesList = List, sum = List.Sum() };
return Items;
}
static void Main(string[] args)
{
dynamic res = GetRates();
List<double> MashkantaSumList = res.sumList;
}
I'm trying to create a class wide array in C#, in a Windows Mobile Phone 8.1 project, so that when I create a method I can
What I did at first was:
public sealed partial class GamePage : Page
{
int Score = 0;
int count = 0;
private DispatcherTimer Timer;
public ColorsClass color = new ColorsClass();
public int RandBlue = 0;
int RandGreen = 0;
int RandRed = 0;
int RandYellow = 0;
int RandPurple = 0;
int RandYellowGreen = 0;
int RandOrange = 0;
int RandGray = 0;
bool Equal = true;
int Fail;
int Hit;
int Lives = 10;
Rectangle[] Block = { Block01, Block02, Block03, Block04, Block05, Block06, Block07, Block08, Block09, Block10, Block11, Block12 };
int[] RandomColors = { RandBlue, RandGreen, RandRed, RandYellow, RandPurple, RandYellowGreen, RandGray };
...
}
But it gives me the message that "a field initializer cannot reference the non-static field, method or property..."
Then I tried this option, that I saw when I was search in the internet:
public sealed partial class GamePage : Page
{
int Score = 0;
int count = 0;
private DispatcherTimer Timer;
public ColorsClass color = new ColorsClass();
public int RandBlue = 0;
int RandGreen = 0;
int RandRed = 0;
int RandYellow = 0;
int RandPurple = 0;
int RandYellowGreen = 0;
int RandOrange = 0;
int RandGray = 0;
bool Equal = true;
int Fail;
int Hit;
int Lives = 10;
int []
Random rand = new Random();
public GamePage()
{
this.InitializeComponent();
DispatchTheTime();
RandomColors = new int[] { RandBlue, RandGreen, RandRed, RandYellow, RandPurple, RandYellowGreen, RandGray };
...
}
This way I can reach the array through the methods I created, but the array values are always null..
What can I do?
Everytime when you create a new GamePage you are filling your array with the content of the variables RandGreen, RandRed, ...
At this time, these variables are set to 0. Thus your array contains only 0s. Even if you later assign other values to RandGreen, RandRed, ... the values within the array will not change.
I hope this example will make it clearer:
RandBlue = 0;
var RandomColors = new int[] { RandBlue, RandGreen };
// RandColors[0] is 0
RandBlue = 5;
// RandColors[0] is still 0
Edit:
The error message "a field initializer cannot reference the non-static field, method or property..." should be self-explaining. You could make your color variables const in order to make it work. But I suppose this would not make any sense for you.
Keep in mind that integers are valuetypes. If you create an array of integers like with the RandomColors, you'll just put a copy of your value in the array. At this point, RandGreen and RandomColors[1] point to different memory locations and a change of either won't propagate to the other.
You have to decide whether you want to keep your values in a lot of fields like you actually declared or if you want to keep your integers in an array.
You are propably better off using a Dictionary for your usecase and only access the integers from there.
On class level declare your RandomColors:
Dictionary<string, int> RandomColors = new Dictionary<string, int>();
public GamePage()
{
RandomColors.Add("RandGreen", 0);
RandomColors.Add("RandRed", 0);
//change like this:
RandomColors["RandGreen"] = 5;
//access like this:
int x = RandomColors["RandGreen"];
}