I want to make button array that include string and integer. I have 30 buttons and named B1, B2, ...., B30 and I want to change their color depend on the counter value. How can I do that? These are what I have done and I stuck
for(Cnt = 0; cnt < 30; cnt++)
{
Button[] Tombol = new Button[]{"B"+(cnt+1)};
Tombol[cnt].BackColor = Color.Red
}
The Control (custom) initialization in the Form (in your case, the Control being a Button) requires more than a simple declaration. Apart from giving name (which you do), two other important things to do are:
To add it to the Control parent
To locate it nicely
Thus, adding those considerations to the Button you are to create, you could do something like this
int noOfBtns = 30;
Button[] Tombols = new Button[30]; //actually, you may not need this at all
for (int cnt = 0; cnt < numOfBtns; cnt++)
{
Button tombol = new Button();
tombol.BackColor = Color.Red;
tombol.Location = new Point(5, cnt * 25); //Read (2) please formulate this more properly in your case
tombol.Name = "B" + (cnt + 1).ToString();
// others like size (maybe important depending on your need), color, etc
this.Controls.Add(tombol); //Read (1) this refers to the `Form` if the parent control you want to put your button to is `Form`. But change the `this` as you see fit
Tombols[cnt] = tombol; //again, actually you may not need this at all
}
Take care of how you formulate the location of your button, very important. The example I gave above is really simple formulation, which might not fit if your number of buttons grow large. But that gives you the basic idea on how important it is to set the location of the Button right.
You may need the array of Button at all, unless for some reason you want to list it. But even you want to list it, you should use List and List.Add instead of Array.
I suggest using Linq to generate the array:
Button[] Tombol = Enumerable
.Range(0, 30)
.Select(i => new Button() {
Text = String.Format("B{0}", i + 1),
BackColor = Color.Red,
//TODO: compute desired color as function of "i" like
// BackColor = Color.FromArgb(i * 8, 255 - i * 8, 128),
//TODO: assign Parent, Location, Size etc. like this:
// Parent = this,
// Location = new Point(10 + 40 * i, 10),
// Size = new Size(35, 20),
})
.ToArray();
I mean like this:
Button[] Tombol = new Button[30];
for(cnt = 0; cnt < 30; cnt++)
{
Tombol[cnt] = new Button
{
Text = "B" + (cnt+1),
BackColor = Color.Red
};
}
First you create the array and in the for loop you instantiate the actual buttons one by one.
You have to initialize the button array first
int numOfBtns = 30;
Button[] Tombol = new Button[numOfBtns];
and after you can fill required items
for (int cnt = 0; cnt < numOfBtns; cnt++)
{
// Name, Content, Foreground .. whatever
Tombol[cnt].Name = "B" + (cnt + 1);
}
At the moment you are recreating your array on each loop of your code rather than creating the array outside of the loop and then adding buttons to it in the loop.
In addition all your buttons are being created in the same position, so they are on top of each other meaning you can only see one of them.
Try something like this, based on a modified version of the code from this previous answer which creates the buttons, adds them to a list you can search and the sets the positions of the buttons too:
int top = 50;
int left = 100;
var buttons = new Dictionary<string, Button>();
for (int i = 0; i < 30; i++)
{
Button button = new Button();
buttons.Add("B"+i, button);
button.Left = left;
button.Top = top;
this.Controls.Add(button);
top += button.Height + 2;
button.BackColor = Color.Red;
}
You can then refer to an individual button later with the code:
buttons["B3"].BackColor= Color.Green;
Related
So I am trying to figure out why filling sudoku board in order of how I generate fields is many times faster then filling it which shuffled order, and I can't come to any reasonable conclusions.
Speed of filling and checking should be about the same no matter if fields are shuffled or not, only noticeable difference is the fact that filling boxes in a shuffled order causes the main loop to easily go for 60.000.000+ iterations not sure how many on average as I am not patient enough to check. And filling them in order of how they were generated gets finished in usually < 1.000 iterations rarely going over it and basically never going over 5.000.
I do understand that code doesn't follow C# standards too strictly but it's a project I am supposed to make and it's not my main language there are probably some possible optimizations but it's not what I am interested in all i want to know why shuffling the order of fill the boxes causes the process to take this much longer.
Edit: forgot to attach order of creating/filling boxes order of filling/creating boxes:
Edit2: more concise rephrased question:
The question is why generating an valid fully filled sudoku board in order from image creates a lot less invalid boards from which there is required backtracking, as compared to generating a board in a random order of choosing fields?
example of random order
Here is the code used for the project https://github.com/Piterm21/sudoku
And here are all the parts used in generation.
filledBox class:
public class filledBox
{
public int textBoxIndex;
public int value;
public int nextIndexToTry;
public int[] values;
public int lineIndex;
public int columnIndex;
public int groupIndex;
}
Here is a main loop:
filledBox[] boxes = this.shuffleBoxesCreateCheckingLists();
long iter = 0;
int nextIndexToFill = 0;
while (nextIndexToFill != 81) {
for (; boxes[nextIndexToFill].nextIndexToTry < 9; boxes[nextIndexToFill].nextIndexToTry++) {
// check if is valid
if (!createsError(boxes[nextIndexToFill])) {
boxes[nextIndexToFill].value = boxes[nextIndexToFill].values[boxes[nextIndexToFill].nextIndexToTry];
nextIndexToFill++;
break;
}
if (boxes[nextIndexToFill].nextIndexToTry == 8) {
boxes[nextIndexToFill].nextIndexToTry = 0;
boxes[nextIndexToFill].value = 0;
nextIndexToFill--;
boxes[nextIndexToFill].nextIndexToTry++;
while (boxes[nextIndexToFill].nextIndexToTry == 9) {
boxes[nextIndexToFill].nextIndexToTry = 0;
boxes[nextIndexToFill].value = 0;
nextIndexToFill--;
boxes[nextIndexToFill].nextIndexToTry++;
}
break;
}
}
iter++;
}
System.Diagnostics.Debug.WriteLine(iter);
Generation of boxes with setting of lists used for checking for errors:
List<filledBox>[] generationLines;
List<filledBox>[] generationColumns;
List<filledBox>[] generationGroups;
public filledBox[] shuffleBoxesCreateCheckingLists()
{
filledBox[] boxes = new filledBox[81];
for (int i = 0; i < 81; i++) {
boxes[i] = new filledBox();
boxes[i].values = new int[9]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
boxes[i].values = shuffle(boxes[i].values, true);
}
generationLines = new List<filledBox>[9];
generationColumns = new List<filledBox>[9];
generationGroups = new List<filledBox>[9];
for (int i = 0; i < 9; i++) {
generationLines[i] = new List<filledBox>();
generationColumns[i] = new List<filledBox>();
generationGroups[i] = new List<filledBox>();
}
int boxIndex = 0;
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
for (int innerY = 0; innerY < 3; innerY++) {
for (int innerX = 0; innerX < 3; innerX++) {
int subPanelIndex = x + y * 3;
int lineIndex = innerY + y * 3;
int columnIndex = innerX + x * 3;
boxes[boxIndex].textBoxIndex = boxIndex;
boxes[boxIndex].groupIndex = subPanelIndex;
boxes[boxIndex].columnIndex = columnIndex;
boxes[boxIndex].lineIndex = lineIndex;
boxes[boxIndex].nextIndexToTry = 0;
boxes[boxIndex].value = 0;
generationLines[lineIndex].Add(boxes[boxIndex]);
generationColumns[columnIndex].Add(boxes[boxIndex]);
generationGroups[subPanelIndex].Add(boxes[boxIndex]);
boxIndex++;
}
}
}
}
#if !fast
boxes = shuffle(boxes);
#endif
return boxes;
}
Shuffling code:
public T[] shuffle<T> (T[] array)
{
int i = array.Length;
while (i > 1) {
i--;
int j = rnd.Next(0, i - 1);
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
And code responsible for checking for errors:
public bool hasError (List<filledBox> list, filledBox box)
{
bool result = false;
foreach (filledBox filledBoxToCheck in list) {
if (filledBoxToCheck.value == box.values[box.nextIndexToTry]) {
if (box.lineIndex != filledBoxToCheck.lineIndex ||
box.columnIndex != filledBoxToCheck.columnIndex) {
result = true;
break;
}
}
}
return result;
}
public bool createsError (filledBox box)
{
bool result = false;
if (hasError(generationGroups[box.groupIndex], box)) {
result = true;
} else if (hasError(generationLines[box.lineIndex], box)) {
result = true;
} else if (hasError(generationColumns[box.columnIndex], box)) {
result = true;
}
return result;
}
The reason the shuffled order of visiting boxes is worse is that, for the first few boxes, you've increased the odds of filling them in independently. I'm calling a 3x3 region a box. You could visit each little square randomly, but I'll confine my analysis to fillng in one 3x3 box at a time. It should illustrate the problem.
Lets assume, whether you used the in-order or random method, you filled in the top left box first.
VISITING BOXES IN ORDER:
Now consider filling in the box next to it, that is, the top middle box. Just look at filling in the top row of that box, there are 6x5x4 = 120 ways to fill it in.
VISITING BOXES RANDOMLY:
Now consider instead choosing any box to fill in next. If you happen to choose a box that is not in the top row or left column, filling it in is unaffected by the way the first box was filled. The top row of that box can be filled in 9x8x7 = 504 ways.
Taking this further, if you fill in the boxes sequentially, say, across the top, the third box (the top right one), begins with only 3x2x1 = 6 ways to fill in the top row of it. Whereas, if you select the next box randomly, you might, at worst, select a box that is not in the same row or column of either of the first 2 boxes, which means that the top row of that box has yet again 9x8x7 = 504 ways of being filled in.
If you tried randomly selecting the order for each little square to be filled in, the first few might all be in different rows and columns. At worst, none of the first 9 squares will align meaning there will be 9^9 = 387,420,489 options. But filling them in across the top row, the choices are guaranteed to be 9! = 362,880.
This illustrates one of the strategies for how to approach backtracking. Ideally, you first solve parts of the problem that most tightly constrain the rest of the problem. For some problems sequential is better, and for some random is better.
So, I simply want to dynamically change my what label is currently edited through an array, to achieve as little code as possible.
This is what it looks like right now:
string[] poängLabels = new string[10];
for (int i = 3; i <= 9; i++)
{
poängLabels[i] = ("label{0}.Text" + i);
}
You should do it like this:
poängLabels[i] = ((Label)this.Controls.Find("label" + i)).Text;
or
poängLabels[i] = ((Label)this.Controls["label" + i]).Text;
You have to be able to enumerate controls somehow, putting (or having them) in the array is one option:
var result = new { label1, label2, ... }.Select(label => label.Text).ToArray();
I've got myself into a little bit of a jam. As I tried to code the entire alphabet into my app, I didn't really feel like typing the letters in one by one, so I used ASCII characters and used a for-loop and inserted them as buttons. So, now I need those buttons to click according to my needs, but somehow I cant seem to figure out what is the problem with the issue. The code is as follows:
private void Hangman_OnLoaded()
{
const int btnSize = 35;
var c = 0;
for (var i = 65; i <= 90; i++)
{
var btn = new Button {
Content = (char) i,
Click += GuessClick()
};
btn.Width = btn.Height = btnSize;
var margin = btn.Margin;
margin.Left = c += 37;
btn.Margin = margin;
GridMain.Children.Add(btn);
}
}
private void GuessClick(object sender, EventArgs e) {
var choice = sender as Button;
if (choice == null || !copyCurrent.Contains(choice.DataContext.ToString())) return;
var temp = copyCurrent.ToCharArray();
var find = copyCurrent.ToCharArray();
var guessChar = choice.DataContext.ToString().ElementAt(0);
for (var index = 0; index < find.Length; index++) {
if (find[index] == guessChar) {
temp[index] = guessChar;
}
}
copyCurrent = new string(temp);
DisplayTheWord();
}
I will take a stab at "Psychic Debugging" this code. There are lots of things that can be improved, changed, etc, but I am guessing this is where you may be having an issue:
var temp = copyCurrent.ToCharArray();
var find = copyCurrent.ToCharArray();
var guessChar = choice.DataContext.ToString().ElementAt(0);
for (var index = 0; index < find.Length; index++) {
if (find[index] == guessChar) {
temp[index] = guessChar;
}
}
copyCurrent = new string(temp);
No matter what the guessChar is, at the end of this block of code copyCurrent will be unchanged (as far as what the actual string content of copyCurrent is). First you make two arrays that are identical. Then you are looping through the find array looking for the guessChar. If you find the guessChar then you are "modifying" the temp array to have guessChar at the very same index where you found it in find. Since both arrays are identical, the end result is that no "change" takes place. Once you have executed the loop you are creating a new string from the temp array, but since both find and temp are identical and unchanged after this loop, you effectively are making a new string that is identical to the one you started with. I don't know what you are expecting this code to do, but I am assuming this is not it.
I am going to assume (from the load method name) that this is a game of hangman and that at the outset of the game copyCurrent has some content like "????" and that you have some other variable, maybe called answer and it would have the content, for example, "food". If that is the case, then you would just need to modify these two lines:
var temp = copyCurrent.ToCharArray();
var find = answer.ToCharArray();
My code is C# windows form
I have a file with data:
David One And Two/Three
Alex One Two Four And Five/Six
Amanda Two Seven/Ten
Micheal Seven/Nine
and trying to have them in array like
string[] Names = File.ReadAllLines("C:\Students\Name.txt", Encoding.Default);
and have them in Group of Radio Buttons
RadioButton[] n = new RadioButton[Names.Length];
for (int i = 0; i < Names.Length; i++)
{
n[i] = new RadioButton();
n[i].Text = Names[i];
n[i].Location = new Point(10, 10 + i * 20);
groupBox1.Controls.Add(n[i]);
}
But it shows as my attached image
I tried without Encoding.Default and Encoding.UTF8 but the same problem.
What is I'am doing wrong? Please see my image and help me. Thank you in advance!
I'm guessing your file contains empty lines at the end. You can try to remove them before creating a radio button:
for (int i = 0; i < Names.Length; i++)
{
var name = Names[i];
if(name.Trim() == string.Empty) continue;
n[i] = new RadioButton();
n[i].Text = Names[i];
n[i].Location = new Point(10, 10 + i * 20);
groupBox1.Controls.Add(n[i]);
}
If your text is trimmed you can try to increase the width of the control:
n[i].Width = 300; // Put a value which will show the entire text
im doing a slot machine game , its a simple one , that basically it will roll the image in the picurebox into a random image. using this code
PictureBox[] PictureboxArray = new PictureBox[5];
the 5 picureboxes are assigned using this line of code
PictureboxArray[0] = pbxK;
PictureboxArray[1] = pbxQueen;
PictureboxArray[2] = pbxKing;
PictureboxArray[3] = pbxJoker;
PictureboxArray[4] = pbxAce;
Images are assigned like that
Image[] Rollimage = new Image[5];
Rollimage[0] = Properties.Resources.K;
Rollimage[1] = Properties.Resources.Queen;
Rollimage[2] = Properties.Resources.King;
Rollimage[3] = Properties.Resources.Joker;
Rollimage[4] = Properties.Resources.Ace;
and the intial image of the picturebox are assigned like that
pbxK.Image = Rollimage[0];
pbxQueen.Image = Rollimage[1];
pbxKing.Image = Rollimage[2];
pbxJoker.Image = Rollimage[3];
pbxAce.Image = Rollimage[4];
the actual code for the image rolling is as follows
for (int i = 0; i <= 4; i++)
{
if (PictureboxArray[i].Enabled == true)
{
Roll[i] = Rnd.Next(0, 4);
}
PictureboxImage(PictureboxArray[i], Roll[i]);
}
rnd is a new random
Random Rnd = new Random();
Roll in an int for saving the index of the roll
int[] Roll = new int[5];
everything works fine and the pictures rolls different image every second of the time , as I predefined that, now what im trying to do is to assign this
int[] PictureValues = new int[]{100, 225, 550, 775, 1000};
to the images
Image[] Rollimage = new Image[5];
meaning that the first roll image which is Properties.Resources.K;has the actual value of 100
and so on , is there a way to do that ?
So.. if I understand your issue correctly, once the image is selected, you need a way to reverse it back to associate it with a value. One method could be the following:
Note: It appears that each picturebox that is showing, is named king / joker etc.. so if you are looking at the front of the 'slot machine' you see 5 boxes which are named pbxk, pbxQueen, pbxKing, pbxJoker, pbxAce but they don't necessarily display the image associated with their name..
int total = 0;
for(int i=0;i<Rollimage.Length;i++)
{
if(pbxk.Image.Equals(Rollimage[i]))
{
total += PictureValues[i];
}
if(pbxQueen...)
{
//Do the same thing for each pbx
}
}
The only thing I'm not 100% on is the comparison method. Additionally, you could use the picturebox's ImageLocation property to store the path to the image whenever you assign it, and then compare that against a filename to figure out what image is showing.
Example on how to compare images: Stack Overflow Image Compare
Given that example, you may want to try == using your current Image array.. if that doesn't work, you may need to define an array of bitmaps to compare against. Seems like a waste of memory to me, but it should work.
Edit
The following code sums the values of the images correctly. I just put together a quick sample program with 2 pictureboxes, a control button and a label, with two resources. This should demonstrate all of the techniques required to perform what you are needing.
public partial class Form1 : Form
{
PictureBox[] PictureboxArray = new PictureBox[2];
Image[] Rollimage = new Image[2];
int[] pictureValues = new int[2];
public Form1()
{
InitializeComponent();
pictureValues[0] = 100;
pictureValues[1] = 200;
Rollimage[0] = Properties.Resources.TitleBar;
Rollimage[1] = Properties.Resources.Untitled;
PictureboxArray[0] = this.pictureBox1;
PictureboxArray[1] = this.pictureBox2;
PictureboxArray[1].Image = Rollimage[0];
PictureboxArray[0].Image = Rollimage[0];
}
private void button1_Click(object sender, EventArgs e)
{
int total = 0;
for(int i = 0;i<Rollimage.Length;i++)
{
foreach(var box in PictureboxArray)
{
if(box.Image == Rollimage[i])
{
total += pictureValues[i];
}
}
}
label1.Text = total.ToString();
}
}