There is a form that each user is required to complete, it has 4 fields: date, bill code, amount and currency. Bill code has a drop down menu with a lot of options of 4 that options are valid (Health, Travel, Meal, Hotel). Bill code field cannot be left blank, and it should take only one of these 4 options. A user make 4 entries with each of the 4 bill codes. If user enters only Health and Travel, an error message should fire that Meal and Hotel records need to be added. This is what I got so far:
public bool ValidateBillCode(bills billArray[][])
{
for(int i = 0; i < billArray.Length; i++)
{
for(int j = 0; j < billArray[0].Length; j++)
{
if(billArray[i][j].IndexOf("Health") >= 0 ||
billArray[i][j].IndexOf("Travel") >= 0 ||
billArray[i][j].IndexOf("Meal") >= 0||
billArray[i][j].IndexOf("Hotel") >= 0)
{
return true;
}
else
{
return false;
}
}
}
}
But it doesn't make sure that all four of these are entered, and I'm not sure how to make an error message that would tell the user which of the four are missing. I will appreciate any help with this.
I believe you don't need any 2-dimensional or jagged array. You need to define a struct like:
public struct Bill
{
public string Date;
public string BillCode;
public string Amount;
public string Currency;
}
Then your ValidateBillCode() becomes like this:
public bool ValidateBillCode(Bill[] billArray)
{
bool healthEntered = false;
bool travelEntered = false;
bool mealEntered = false;
bool hotelEntered = false;
for (int i = 0; i < billArray.Length; i++)
{
if (billArray[i].BillCode == "Health")
healthEntered = true;
else if (billArray[i].BillCode == "Travel")
travelEntered = true;
else if (billArray[i].BillCode == "Meal")
mealEntered = true;
else if (billArray[i].BillCode == "Hotel")
hotelEntered = true;
}
return healthEntered && travelEntered && mealEntered && hotelEntered;
}
But this is just a very simplistic approach. For a more appropriate solution, you'd better to use class instead of struct, use enum for BillCode, DateTime for Date, and double for Amount.
I was asked to make a tic tac toe in windows form and i have to use 2D array
I am trying to store 1 in the array for each X and -1 for each 0
then i will add the values in each row ,column and diagonal and check if its 3 or -3
the problem is i don't know how to assign and i and j for each element in the array after i press on a corresponding button
private void storeInboard(int i, int j, object sender, EventArgs e)
{
{
if ((sender as Button).Text == "X")
board[i][j] = 1;
else if ((sender as Button).Text == "O")
board[i][j] = -1;
}
}
here i check for each column by giving its number
private bool checkCol(int col)
{
for (int i = 0; i < 3; i++)
{
rowSum += board[i][col];
if (colSum == 3 || colSum ==-3 )
return true;
else
colSum = 0;
}
return false;
}
checking for winner
private bool checkWinner()
{
return (checkCol(0) || checkCol(1) || checkCol(2) || checkDiag1() || checkDiag2() || checkRow(0) || checkRow(1) || checkRow(2));
}
here is the button click event >> its is assigned for all the buttons
private void button_click(object sender, EventArgs e)
{
if (turn)
{
(sender as Button).Text = "X";
}
else
(sender as Button).Text = "O";
turn = !turn;
turnCount++;
(sender as Button).Enabled = false;
if (checkWinner() && turnCount <=9)
MessageBox.Show("Winner !!!");
else
MessageBox.Show("Tie -.-");
so I just want to know how can i send an i and j for the event storeInboard for each button i click
thanks in advance
This question is not about arrays or some 2D stuff but binding information to winform controls.
You have several ways to do this.
1) In visual studio property panel fill buttons Tag property with an ordinal number one by one from left to right starting with zero. Left-upper button = 0, middle-upper = 1 and so on.
Then in button_click you can do something like:
var tag = int.Parse((string)((Button)sender).Tag);
int colIndex = tag % 3;
int rowIndex = tag / 3;
2) Maybe the buttons are placed in a Panel. Then you can iterate through the children of the parent panel in button_click and see if one equals to sender.
int c = 0;
foreach (var item in parentPanel.Controls)
{
if (item == sender)
break;
c++;
}
if (c<parentPanel.Controls.Count) // found
{
int colIndex = c % 3;
int rowIndex = c / 3;
}
// else -- ugh, something went wrong, maybe not only the buttons have this event
Much more solution is possible.
Is it possible to set a components visible attribute based on its name?
I have 12 "master" components (comboboxes) if you want to call them that and based on the selection in these I want to display anywhere from 1 to 16 textboxes. These are named in numeric order such as combobox1_textbox_0, combobox1_textbox_1 and so on. What I would like to do ideally is take the index of the combobox and pass it as a parameter to a method that sets the textboxes visible attribute to visible/hidden depending on the index passed into the method.
Is this possible? in pseudocode or what you call it I would like it to work something like this:
private void methodToSetVisibleAttribute(int indexFromMainComboBox)
{
for(int i = 0; i < 15; i++)
{
if(i < index)
{
combobox1_textbox_+i.Visible = true;
}
else
{
combobox1_textbox_+i.Visible = false;
}
}
}
I could do panels or something for the choices but seeing as all the selections from the combobox will use the same textboxes but in different amounts it seems like alot of work to make a panel for every possible selection not to mention difficult to expand the program later on.
Assuming you are using Windows Forms and not WPF, you can use ControlCollection.Find() to find controls by name:
var textBox = this.Controls.Find(string.Format("combobox1_textbox_{0}", i), true).OfType<ComboBox>().FirstOrDefault();
if (textBox != null)
textBox.Visible = (i < index);
else
Debug.Assert(false, "textbox not found"); // Or throw an exception if you prefer.
I'll suggest an alternative to your approach, maybe not quite what you're looking for:
Place your combo boxes in a List<ComboBox> and you can access them by an index number.
List<ComboBox> myCombos = new List<ComboBox>();
for (int i = 0; i < 16; i++)
{
ComboBox cb = new ComboBox();
//do what ever you need to do here. Set its location, add items, etc.
Form1.Controls.Add(cb); //Alternatively add it to another container.
myCombos.Add(cb); //Now it's in a list.
}
Modify them like this:
for(int i = 0; i < 15; i++)
{
if(i < index)
{
myCombos[i].Visible = true;
}
else
{
myCombos[i].Visible = false;
}
}
Or even more succintly:
for(int i = 0; i < 15; i++)
{
myCombos[i].Visible = i < index;
}
I want to add the exact value of textbox into datagridview my problem is if i will add another item the last item I add will also change. Here is the print screen of sample problem..
1st try
2nd try
This is my code.
int n = dataGridView3.Rows.Add();
for (int j = 0; j < dataGridView3.RowCount; j++)
{
if (dataGridView3.Rows[j].Cells[1].Value != null && (textBox4.Text == dataGridView3.Rows[j].Cells[4].Value.ToString()))
{
MessageBox.Show("Item Already on List!");
dataGridView3.Rows.Remove(dataGridView3.Rows[n]);
return;
}
else
{
dataGridView3.Rows[j].Cells[1].Value = textBox43.Text;
dataGridView3.Rows[j].Cells[4].Value = textBox4.Text;
dataGridView3.Rows[j].Cells[2].Value = DateTime.Now.ToShortDateString();
dataGridView3.Rows[j].Cells[3].Value = dateTimePicker3.Text;
dataGridView3.FirstDisplayedScrollingRowIndex = n;
dataGridView3.CurrentCell = dataGridView3.Rows[n].Cells[0];
dataGridView3.Rows[n].Selected = true;
}
}
You are looping over the complete array and if it is not yet on the list it goes in to the else part of your if. In that block you assign the current entered values to your row, for every single row you already have.
To fix that I separated the Check for duplicates and the Add part more clearly.
Do notice that if you would have run this through the debugger and stepped on each line of your code (hitting F10 in Visual Studio) you would have spotted this bug easily. Have a look at the blog from Scott Guthrie (among others) http://weblogs.asp.net/scottgu/debugging-tips-with-visual-studio-2010
// check if we already added that one
for (int j = 0; j < dataGridView3.RowCount; j++)
{
if (dataGridView3.Rows[j].Cells[1].Value != null && (textBox4.Text == dataGridView3.Rows[j].Cells[4].Value.ToString()))
{
MessageBox.Show("Item Already on List!");
return;
}
}
// lets add it!
int n = dataGridView3.Rows.Add();
dataGridView3.Rows[n].Cells[1].Value = textBox43.Text;
dataGridView3.Rows[n].Cells[4].Value = textBox4.Text;
dataGridView3.Rows[n].Cells[2].Value = DateTime.Now.ToShortDateString();
dataGridView3.Rows[n].Cells[3].Value = dateTimePicker3.Text;
dataGridView3.FirstDisplayedScrollingRowIndex = n;
dataGridView3.CurrentCell = dataGridView3.Rows[n].Cells[0];
dataGridView3.Rows[n].Selected = true;
here is the game board just to give you an idea of how it looks like (this board will be expanded to a 7x6)
what i want to do is detect a winner when 2 colors are in a row similar to the game "conmect four" taking into account diagonal combos too. BUT i want to do this with out using brute-force enumeration..
this the code that goes behind the program i have made I'm not asking for solution i just need a bit of help on an effective algorithm
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Button[] btns;
private Button[] btns2;
public Form1()
{
InitializeComponent();
btns = new Button[] { button2, button3 };
btns2 = new Button[] { button4, button5 };
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (var btn in btns)
{
btn.Enabled = false;
btn.BackColor = Color.LightCyan;
}
foreach (var btn in btns2)
{
btn.Enabled = false;
btn.BackColor = Color.LightCyan;
}
}
public int state;
int cc = 0;
private void button1_Click(object sender, EventArgs e)
{
foreach (var btn in btns)
{
{
if (!btn.Enabled)
{
btn.Enabled = true;
if (cc == 0)
{
cc = 1;
btn.BackColor = Color.Red;
}
else
{
cc = 0;
btn.BackColor = Color.Yellow;
}
return;
}
}
}
}
private void button6_Click(object sender, EventArgs e)
{
foreach (var btn in btns2)
{
if (!btn.Enabled)
{
btn.Enabled = true;
if (cc == 0)
{
cc = 1;
btn.BackColor = Color.Red;
}
else
{
cc = 0;
btn.BackColor = Color.Yellow;
}
return;
}
}
}
}
}
First, for efficiency and sanity, I'd keep the state of my board in a 2D array.
Second, for detecting win states, given that you start the game with a (presumably) empty board, you can only get into a win state when a button changes state. And if the button changing state puts you into a win state, then that button must be involved in that win state (i.e. it must be part of you line).
So...you don't need to brute-force the whole board. You only need to determine if the button that just changed state is part of a line. In other words, look only at the buttons to above, below, to the left and to the right (and maybe diagonal, your question wasn't clear if you included diagonals) to see if they are the same color as the one you changed. If any one of them is, then this is a win state. This is where using a 2D array will make you life much easier. If the button at (x, y) is changed, then you only need to check (x-1, y), (x+1, y), (x, y-1) and (x, y+1), (and maybe diagonals) making sure to do appropriate boundary checks, of course.
Extending this to 3, 4 or more in a row isn't much more difficult, except you need to remember you might be in the middle of a row rather than one end or the other.
Unoptimized Pseudo Code for 2 in a row (note, I've switched to compass points to avoid up-left, up-right, etc because I feel it gets a bit unwieldy):
// cell is the cell that last changes, it has an x and y property and a color property
// board is a member variable, a 2D array of cells. Note [0,0] is the upper-left (NW) corner of the board.
// boardHeight and boardWidth are member variable with the dimensions of the board
// board[boardWidth-1, boardHeight-1] is the lower-right (SE) corner of the board
// returns true for a win, false otherwise
function checkWin(cell) returns bool {
// check west
if (cell.x > 0 && board[cell.x - 1, cell.y].color == cell.color)
return true;
// check northwest
if (cell.x > 0 && cell.y > 0 && board[cell.x-1, cell.y-1].color == cell.color)
return true;
// check north
if (cell.y > 0 && board[cell.x, cell.y-1].color == cell.color)
return true;
// check northeast
if (cell.y > 0 && cell.x < boardWidth && board[cell.x+1, cell.y-1].color == cell.color)
return true;
// checking the other directions is left as an exercise for the reader, hopefully you get the point
return false;
}
If you are doing more than 2, I'd think about a recursive function to count the number of matching cells to the left, right, up, down, and diagnoals
// k is the number of cells in a row for a win
function checkWin(cell) returns bool {
// check west / east
int count = checkWest(cell);
if (count > k)
return true;
count += checkEast(cell);
if (count > k)
return true;
// check nw / se
count = checkNW(cell);
if (count > k)
return true;
count += checkSE(cell);
if (count > k)
return true;
// and so on, checking N/S and NE/SW
return false;
}
function checkWest(cell) returns int {
// base case, check the boundaries!
if (cell.x == 0)
return 0;
// base case, the cell next to this one doesn't match
if (board[cell.x-1,cell.y].color != cell.color)
return 0;
// recursion, check the next cell in the line
return 1 + checkWest(board[cell.x-1,cell.y]);
}
For an n by m board and a winning combo of k in a row:
int n, m, k;
byte[,] color = new byte[n, m]; // for two colors, a 0 would correspond to blue, 1 would be red, or however you like
for (int i = 0; i <= n - k; i++) // don't check all the way to the right because there's no room to win
{
for (int j = 0; j <= m - k; j++) // don't check all the way down because there's no room to win
{
// Check here for a win. Check for a win to the right, down right, and down
}
}