I've been looking for a while and i couldn't find anything that would help me with my problem, but sorry if i missed something.
So for school we had to learn VB and make a game, and i chose to make Sudoku. I found VB easy to understand so i decided to try a different language to see if it was the same. C# was my choice. I decided to start off by making the Sudoku game again and compare it to my VB game.
In the VB code i was able to make an array of all the textboxes that make up the 9x9 grid from the code:
For Y = 0 to 8
For X = 0 to 8
Grid(X, Y) = New Windows.Forms.TextBox
Pencil(X, Y) = New Windows.Forms.TextBox
With Grid(X, Y)
.BackColor = Grid(X, Y).BackColor
.Name = Asc(97 + X) & Y + 1
.Location = New System.Drawing.Point(35 + 50 * X + (FindBox(X) - 1) * 15, 50 + 50 * Y + (FindBox(Y) - 1) * 15)
.Size = New System.Drawing.Size(50, 50)
.Multiline = True
.MaxLength = 1
.Font = New Font(Grid(X, Y).Font.Name, Grid(X, Y).Font.Size + 10)
.TextAlign = HorizontalAlignment.Center
.TabIndex = (X + 1) + (Y * 9) + 1
.BorderStyle = BorderStyle.FixedSingle
End With
Me.Controls.Add(Grid(X, Y))
next
next
This meant i could easily refer to the Sudoku textbox's as a grid coordinate in the array. I attempted to replicate this in C# and ran into a problem almost instantly
public partial class Form1 : Form
{
TextBox[,] Grid = new TextBox[8,8];
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int Y = 0; Y < 9; Y++)
{
for (int X = 0; X < 9; X++)
{
TextBox TBox = new TextBox();
Grid[X, Y] = TBox;
TBox.Location = new Point(50 + X * 100, 50 + Y * 50);
this.Controls.Add(TBox);
}
}
}
This code runs, but for some reason it only runs till Y = 7, then stops and does not loop any more times. This code works fine until i try to add anything that links the textbox's to the array (In this case Grid[X,Y] = TBox). I've tried it without using TBox (And just straight away using the array, but the same problem persists).
Just wondering if anyone can enlighten me as to why adding the line "Grid[X, Y] = TBox;" can completely ruin a nested for loop.
Thanks in advance, sorry if i didn't say enough/Said too much.
There is an important difference between C# and VB.NET in the context of arrays. Just a simple example. In C# the following array has exactly 10 elements and allowed indexes are from 0 to 9:
int[] array= new int[10];
In VB.NET the following array has 11 elements and allowed indexes are from 0 to 10:
Dim array(10) as Integer
You translated you code from VB.NET to C# without taking this difference into account and it is why you have problems. To fix this problem you should use:
TextBox[,] Grid = new TextBox[9,9];
Instead of:
TextBox[,] Grid = new TextBox[8,8];
It doesn't just stop.You get a IndexOutOfRangeException
Change this
new TextBox[8,8]
to this
new TextBox[9,9]
Or make the for loops "< 8"
Related
This is the method in question:
Color[][] ChopUpTiles()
{
int numTilesPerRow = terrainTiles.width / tileResolution;
int numRows = terrainTiles.height / tileResolution;
Color[][] tiles = new Color[numTilesPerRow * numRows][];
for (int y = 0; y < numRows; y++)
{
for (int x = 0; x < numTilesPerRow; x++)
{
tiles[y * numTilesPerRow + x] = terrainTiles.GetPixels(x * tileResolution , y * tileResolution, tileResolution, tileResolution);
}
}
return tiles;
}
It's a pretty basic function, and works - as long as the tileset in question only has one row. If it has more then a single row, it freaks out. Suddenly, using "tiles[1]" no longer returns tile 1. Instead, it returns... tile 15. I have no idea why it's acting this way, or where the math is wrong. Can someone spot what's going on?
Don't you mean tiles[y][numTilesPerRow + x] or tiles[y][x] or something along those lines? because i don't know what you are trying to do, but you are retrieving an entire row not a tile itself.
also, i think Color[][] tiles = new Color[numTilesPerRow * numRows][]; should be Color[][] tiles = new Color[numRows][numTilesPerRow]; or am i wrong?
Basically, you have a multi-dimensional Array yet you are treating it as a single-dimensional Array
I'm not sure if the title is correct because I wasn't sure how to explain it. I've encountered many scenarios where being able to dynamically modify part of a variable name such a suffixing integer could save me a great deal of time and keep my code much cleaner but I'm not sure how to do it. Here's an example of my most recent encounter.
I have 9 PictureBox's in a 3 x 3 grid. Each PictureBox has a name of cell followed by it's number so cell1, cell2, cell3 etc. I want to get the background colour of each of these cells and assign them to a variable whilst converting them to strings... something like this:
for (int i = 1; i < 10; i++)
{
string ci = celli.BackColor.ToString();
}
Is there a way I can have the i variable insert only it's numeric value to the placeholder rather than appending an i to the variable name? Can I wrap it in some sort of bracket? I've tried Googleing this but I'm finding it difficult to search for using just keywords.
Thanks in advance.
You are probably using a visual form editor, the best way to do this whould probably be to generate the grid by code (and not visually).
Another solution is to make it a matrix:
PictureBox[,] cell = new PictureBox[,] {
{ cell1, cell2, cell3 },
{ cell4, cell5, cell6 },
{ cell7, cell8, cell9 }
};
string[,] c = new string[3, 3];
for(int y=0; y<3; y++)
for(int x=0; x<3; x++)
c[x, y] = cell[x, y].BackColor.ToString();
Good luck with your code.
You would like to generate a list or collection of all your pictureboxes so that you can access them by specifying their index. One way is to generate the PictureBoxes on runtime:
Like this:
List<PictureBox> myPics = new List<PictureBox>();
int picWidth = 100;
int picHeight = 100;
for (x = 0; x <= this.Width; x += picWidth) {
for (y = 0; y <= this.Height; y += picHeight) {
PictureBox pic = new PictureBox();
pic.Image = pic.Image;
// Your image
pic.Location = new Point(x, y);
this.Controls.Add(pic);
myPics.Add(pic);
}
}
// Do something with myPics...
The other method is that when you do have all the pictureboxes on your form already, you can iterate through all the controls, check which ones are pictureboxes and then check their Name property to identify their index. Then do something with them accordingly.
foreach (void ctrl_loopVariable in this.Controls) {
ctrl = ctrl_loopVariable;
if (ctrl.GetType() == typeof(PictureBox)) {
if (ctrl.Name == "your picture box name to test") {
// Do something here with ctrl
}
}
}
(The above code is converted from VB to C#, excuse conversion issues)
Your intend here is to dynamically reference those controls.
In order to achieve this, there is two options:
You create those controls dynamically
You create dynamic references for the controls created by your form-designer
The first point is explained ny Shreyas Kapur's answer.
The second could be cone like this,
readonly Dictionary<Point,PictureBox> _dynamicMappedBoxes =
new Dictionary<Point,PictureBox>();
// Call this once in the beginning ofr your program
void createDynamicMapping()
{
foreach(PictureBox box in Controls.OfType<PictureBox>())
{
Point coords = getCoordinatesFromName(box);
_dynamicMappedBoxes.Add(coords, box);
}
}
Point getCoordinatesFromName(PictrueBox box)
{
int x = int.Parse(box.Name.SubString(IdontKnow);
int y = int.Parse(box.Name.SubString(IdontKnow);
retrun new Point(x,y);
}
//usage
string colorName = dynamicMappedBoxes[new Point(x,y)].BackColor.ToString();
I get an error Index was outside the bounds of the array, im trying to do some simple math and holding it in my list.
List<int> integerList = new List<int>();
for (int a = 0; a < textBox1.Text.Length; a++)
{
for (int b = 8; b > 1 ; b--)
{
integerList.Add(int.Parse(textBox1.Text[a * b].ToString())); //this line
}
}
listBox1.DataSource = integerList;
What I am trying to achieve is this, a user must enter a 7 digit number into the textbox say for instance 4565457, I wanted to store this number in my integerList, then take each number starting from the beginning of the users input and multiply down from 8 untill 2 is reached.
For instance:
4 x 8
5 x 7
6 x 6
5 x 5
4 x 4
5 x 3
7 x 2
I wanted to then store the sum of these multiplications for later use.
It's probably the textBox1.Text that's out of bounds. Try adding a check before using the indexer:
if (a*b < textBox1.Length)
integerList.Add(int.Parse(textBox1.Text[a * b].ToString())); //this line
Try this (since you probably want to calc the value of your a number by the value of b):
List<int> integerList = new List<int>();
for (int a = 0; a < textBox1.Text.Length; a++)
{
for (int b = 8; b > 1 ; b--)
{
integerList.Add(int.Parse(textBox1.Text[a].ToString()) * b); //this line
}
}
listBox1.DataSource = integerList;
The index a*b is outside the bounds of the TextBox content. You have to put in place safeguards to make sure you don't index the string content of the textbox using an index that is out of bounds
This line textBox1.Text[a * b] is likely the source of the problem. There's no bounds checking and a * b likely evaluates to an integer greater than the final index of textBox1. I don't have an great solution for you because I don't really understand what you're trying to do... The expression inside the inner for loop just generally does not make much sense.
You could simply check that a * b is less than textBox1.Text.Length in order to prevent the exception but that probably won't make the code do what you actually want it to.
Sorry didn't got time to read the edited question. According to new description, if user enters 4565457 you want to multiply each character in that string from position 0 to last (6 in this case) with 8 - position. Following loop single for loop will do the trick.
List<int> integerList = new List<int>();
var l = textBox1.Text.Length;
for (int a = 0, b = 8; a < l && b > 1; a++, b--)
{
integerList.Add((Convert.ToInt16(textBox1.Text[a]) * b)); //this line
}
listBox1.DataSource = integerList;
At the end of loop, listBox1 will contain following values:
416
371
324
265
208
159
110
Try this:
List<int> integerList = new List<int>();
var l = textBox1.Text.Length;
for (int a = 0; a < l; a++)
{
for (int b = 8; b > 1 && (a*b) < l ; b--)
{
integerList.Add(int.Parse(textBox1.Text[a * b].ToString())); //this line
}
}
listBox1.DataSource = integerList;
a * b is getting past the length of text in textbox so adding && (a*b) > l will keep this in control.
It's kind of hard to explain the problem I'm having but let's give it a try :)
The small game I'm working on creates a bunch of nodes that are filled with two kinds of resources.
Each node has an iron value and a gold value.
I want to divide these nodes into two areas, so both areas have about the same amount of gold. However, the difference in iron may not be greater than a certain number (let's pick 50 for this example)
The gold/iron ratios are pretty much random, by the way. Here's an example :
gold 75 iron 30
gold 35 iron 70
gold 65 iron 35
Solution for the above situation : 1 and 3 go to area1, 2 goes to area2.
I'm having a lot of trouble trying to automate this process. I've tried iterating through the list of nodes and always passing the node to the area with the smaller amount of iron but that almost never works.
Trying to reassign some nodes from the richer area proves difficult as well, since some nodes have well above 50 iron.
I don't necessarily need to find the best solution (the one with the smallest difference in gold), although that would be optimal.
Any ideas or input are appreciated.
I've had a bit of a play with this and this is what I've got so far, should give a good starting point. I've randomly generated a list of gold and iron pairs (I've used Point because it was simpler for me to work with but anything would work.)
The idea is to take a group of small value golds and swap them with a single larger value gold from the other list. Which in most cases will talk equivilent amounts of gold, but swap a larger value of iron with a smaller one.
private void button2_Click(object sender, EventArgs e)
{
var GoldIron = new List<Point>(
new Point[]{
new Point(16,23),new Point(16,28),new Point(19,44),new Point(21,29),
new Point(23,16),new Point(24,82),new Point(27,85),new Point(31,63),
new Point(31,78),new Point(32,65),new Point(41,23),new Point(43,79),
new Point(44,76),new Point(45,23),new Point(47,16),new Point(50,15),
new Point(50,37),new Point(52,28),new Point(52,58),new Point(52,71),
new Point(61,39),new Point(61,75),new Point(63,59),new Point(68,25),
new Point(68,61),new Point(70,24),new Point(71,75),new Point(74,78),
new Point(77,59),new Point(82,27)}
);
listBox1.DataSource = GoldIron;
//Split into 2 lists based on the gold amount
var Left = new List<Point>();
var Right = new List<Point>();
var SumGold = GoldIron.Sum(P => P.X);
var SumIron = GoldIron.Sum(P => P.Y);
label2.Text = SumGold.ToString();
label1.Text = SumIron.ToString();
var LeftGold = 0;
Int32 i = 0;
while (LeftGold < SumGold / 2)
{
LeftGold += GoldIron[i].X;
Left.Add(GoldIron[i++]);
}
while (i < GoldIron.Count)
{
Right.Add(GoldIron[i++]);
}
Int32 LIndex = 0;
//Start Algorithm
Int32 LeftIron = Left.Sum(P => P.Y);
Int32 RightIron = Right.Sum(P => P.Y);
while (LeftIron - RightIron > 50 || RightIron - LeftIron > 50)
{
if (LeftIron < RightIron)
{
List<Point> TempList = Left;
Left = Right;
Right = TempList;
LIndex = 0;
}
Int32 SmallestRight = Right[LIndex].X;
LeftGold = 0;
i = 0;
while (LeftGold < SmallestRight)
{
LeftGold += Right[i++].X;
}
Point Temp = Right[LIndex];
Right.RemoveAt(LIndex);
Right.AddRange(Left.Take(i));
Left.RemoveRange(0, i);
Left.Add(Temp);
LIndex += i;
//Sort
Left.Sort(CompareGold);
Right.Sort(CompareGold);
LeftIron = Left.Sum(P => P.Y);
RightIron = Right.Sum(P => P.Y);
}
listBox2.DataSource = Left;
SumGold = Left.Sum(P => P.X);
SumIron = Left.Sum(P => P.Y);
label4.Text = SumGold.ToString();
label3.Text = SumIron.ToString();
listBox3.DataSource = Right;
SumGold = Right.Sum(P => P.X);
SumIron = Right.Sum(P => P.Y);
label6.Text = SumGold.ToString();
label5.Text = SumIron.ToString();
}
And the result:
I'm not sure what kind of terminology to use in this so please edit the title to fit as necessary.
For learning purposes, I'm trying to make a screensaver that displays images randomly from a specified folder. Yes, Windows already comes with this but again, learning purposes. Though I'd prefer to learn the proper way the first time instead of having to go back through and relearn how to properly do things.
Now I already have it randomly choosing images and displaying them, etc. What I'd like to do is randomize based on how many times a specific image has been loaded.
For example:
Image 1: 0 views(20%) : 1 view (19%)
Image 2: 0 views(20%) : 0 views(24%)
Image 3: 0 views(20%) : 1 view (19%)
Image 4: 0 views(20%) : 2 views(14%)
Image 5: 0 views(20%) : 0 views(24%)
This way Image 2 and Image 5 would have the highest chance of being shown next.
I've been at this for a while but I'm not sure what's wrong as it's simply grabbing the next pic along the list. I tried to group them by finding all the pictures with the same number of views and then randomizing through that list but it doesn't seem to exactly work the greatest. Here's the code I have for displaying the pictures:
Random rnd = new Random();
string file = "";
int totalViews = 0;
List<string> array = new List<string>();
void ShowPicture()
{
array.Clear();
label1.Text = "";
foreach (Screen screen in Screen.AllScreens)
{
bool done = false;
while (!done)
{
int rand = rnd.Next(100), total;
foreach (string info in files.Keys)
{
total = (100 / files.Count) - (files[info] * (files.Count - 1)) + totalViews;
if (total >= rand)
{
foreach (string tmp in files.Keys) if (total >= files[tmp]) array.Add(tmp);
label1.Text = "Percentage for image: " + total;
done = true;
break;
}
}
}
file = array[rnd.Next(array.Count)];
files[file]++;
totalViews++;
Image image = Image.FromFile(file);
pictureBox1.Image = image;
label1.Text += "\nTotal Views: " + totalViews;
}
}
I hope this is clear enough and thanks in advance.
I think you're making more work for yourself than it needs to be.
I'm not entirely sure what your variables all do, but this is how I would solve the problem (setup and error checking code etc. removed for clarity):
int totalViews; // Assuming this stores the total number of images that
// have been shown so far (4 in your example)
double [] fileWeighting; // How to weight each file
int [] fileViews; // How many times each file has been seen in total
// Note Sum(fileViews) = totalViews
for(int i = 0; i < files.Count; i++) {
fileWeighting[i] = ((double)totalViews - (double)fileViews[i]) /
(double)totalViews;
}
double rndChoice = Random.NextDouble();
double acc = 0;
for (int j = 0; j < files.Count; j++) {
if ( (rndChoice - acc) < fileWeighting[j] ) {
// Display image j
break;
}
acc += fileWeighting[j];
}
Basically we build an array of file weightings based on their view count (lower views mean higher weightings). These weightings add up to 1 (e.g. [0.19, 0.24, 0.19, 0.14, 0.24]) and effectively divide up the 0 to 1 number line:
|--------|-----------|-------|------|---------|
0 1
(0.19) (0.24) (0.19) (0.14) (0.24) - Weightings
0 1 2 3 4 - Corresponding images
We then choose a random number between 0 and 1 (rndChoice) - this is the position in the number line we have chosen. The second loop simply finds which image lies at that point in the number line, and that image gets displayd.
I found the idee when looking at this link.
Basically, multiply the weight with the random number when sorting the list.
So try this
List<KeyValuePair<string, decimal>> list = new List<KeyValuePair<string, decimal>>();
for (int iItem = 0; iItem < 10; iItem++)
list.Add(new KeyValuePair<string, decimal>(iItem.ToString(), iItem/10m));
Random rnd = new Random();
list.Sort( delegate(KeyValuePair<string, decimal> item1, KeyValuePair<string, decimal> item2)
{
if (item1.Value == item2.Value)
return 0;
decimal weight1 = 1 / (item1.Value == 0 ? 0.01m : item1.Value);
decimal weight2 = 1 / (item2.Value == 0 ? 0.01m : item2.Value);
return (weight1 * rnd.Next()).CompareTo(weight2 * rnd.Next());
});
list.Reverse();