Reference the form in a function of a class - c#

Here is my code for a CheckXWinner function, where I need to reference my Form in order to draw win lines:
public void CheckXWinner(Button[] buttonArray, Form1 frm)
{
int arrLength = buttonArray.Length;
int root = (int)Math.Sqrt(Convert.ToDouble(arrLength));
bool winner = false;//variable to keep the computer from going when Xwins
for (int i = 0; i < root; i++)
{
//Sets the counter for the winners back to zero
int d2Count = 0;
int d1Count = 0;
int hCount = 0;
int vCount = 0;
for(int j = 0; j < root; j++)
{
//increments the appropriate counter if the button contains an X
//Horizonal win
if (buttonArray[(i*root) + j].Text == "X")
{
hCount++;
if (hCount == root)
{
for (int z = (root - 1); z >= 0; z--)
{
buttonArray[(i*root) + z].BackColor = Color.IndianRed;
}
Xwins();
winner = true; //sets winner to true so computer does not take turn
}
}//end of Horizonal win
//Left to right diagonal
if (buttonArray[j + (j*root)].Text == "X")
{
d1Count++;
if (d1Count == root)
{
for (int z = (root - 1); z >= 0; z--)
{
buttonArray[z + (z * root)].BackColor = Color.IndianRed;
}
Xwins();
winner = true;
}
}//end of LTR win
//Right to left diagonal
if (buttonArray[(j*(root - 1)) + (root - 1)].Text == "X")
{
d2Count++;
if (d2Count == root)
{
for (int z = (root - 1); z >= 0; z--)
{
buttonArray[(z*(root - 1)) + (root - 1)].BackColor = Color.IndianRed;
}
Xwins();
winner = true;
}
}//end of RTL win
//Vertical win
if (buttonArray[i + (root*j)].Text == "X")
{
vCount++;
if (vCount == root)
{
for (int z = (root - 1); z >= 0; z--)
{
buttonArray[i + (root*z)].BackColor = Color.IndianRed;
}
Xwins();
winner = true;
}
}//end of vert win
}//end of for j loop
}//end of for loop
CheckDraw();
if (winner == false)
{
ComputerGoes(buttonArray);
};
}//end of CheckXWinner
In another part of this class I have the handler for all button clicks associated with the form:
//Handle any button clicks
private void button_click(object sender, EventArgs e)
{
Button b = (Button)sender;
b.Text = "X";
b.Enabled = false;
CheckXWinner(buttonArray, Form1 frm);
}
I have errors for the Form1 part of that call, how do I fix this???

Where you are passing Form1 frm you should actually pass a reference to an instance on Form1. Based on your comment to the suggestion of passing this it seems that the button handler is declared inside another form (not in Form1). If that's the case you should obtain/keep a reference to a Form1 instance and pass that in:
CheckXWinner(buttonArray, a_ref_to_form);
However, looking at your implementation of CheckXWinner it doesn't look like you are referencing frm anywhere anyway!
Rewrite the declaration of CheckXWinner as
public void CheckXWinner(Button[] buttonArray)
And call it like this:
CheckXWinner(buttonArray);

frm isn't declared anywhere when you pass it as a parameter.
pass "this" instead of Form1 frm.

Related

Problem with adding controls into panel in WinForm

I'm creating a chessboard for my game. I have 64 buttons, for some reason I just can add 4 buttons into the panel. This is my code
for (int i = 0; i < 16; i++)
{
for (int t = 0; t < 4; t++)
{
if (t == 0)
{
Button RedSquare = tmpRedSquare;
square[t, i] = RedSquare;
}
else if (t == 1)
{
Button BlueSquare = tmpBlueSquare;
square[t, i] = BlueSquare;
}
else if (t == 2)
{
Button GreenSquare = tmpGreenSquare;
square[t, i] = GreenSquare;
}
else if (t == 3)
{
Button YellowSquare = tmpYellowSquare;
square[t, i] = YellowSquare;
}
pnlChessBoard.Controls.Add(square[t, i]);
}
tmpRedSquare.Location = new Point(tmpRedSquare.Location.X, tmpRedSquare.Location.Y + Constant.SquareMiddleSpace);
tmpBlueSquare.Location = new Point(tmpBlueSquare.Location.X + Constant.SquareMiddleSpace, tmpBlueSquare.Location.Y);
tmpGreenSquare.Location = new Point(tmpBlueSquare.Location.X, tmpBlueSquare.Location.Y - Constant.SquareMiddleSpace);
tmpYellowSquare.Location = new Point(tmpYellowSquare.Location.X - Constant.SquareMiddleSpace, tmpYellowSquare.Location.Y);
}
I expected the result should be 64 buttons on the form. The result is I just see 4 buttons (first 4 buttons when executing), I have debugged and realize that the panel just contains 4 controls after the program executed.
The code always go through the command, and it also the problem:
pnlChessBoard.Controls.Add(square[t, i]);
I didn't know how the panel didn't add other 62 buttons. So what is the main problem?
I can see that you already have an instance of tmpRedSquare, tmpBlueSquare, tmpGreenSquare and tmpYellowSquare, and it seems that you are expecting those instances to appear multiple times in your panel. Well, that's not how it works, you need to create each time a new instance of the expected Button to be added and provide that to the pnlChessBoard.Controls.Add() method.
I recommend you to create methods responsible for creating a new instance of those buttons (like CreateRedSquare(), CreateBlueSquare(), etc.) when they are called, and then use the returned instance instead:
if (t == 0)
{
Button RedSquare = CreateRedSquare();
square[t, i] = RedSquare;
}
...
Also, you will have to rethink your logic around the Location of the button when it's added to the panel.
You have just using 4 buttons. You need to create new Button().
Here is my sample code. You may need to calculate back X and Y according to your design. Hope it works.
public Button CreateBtnRedSqure()
{
Button b = new Button();
b.BackColor = Color.Red;
.....
.....
return b;
}
int Y = 0;
for (int i = 0; i < 16; i++)
{
int X = 0;
for (int t = 0; t < 4; t++)
{
if (t == 0)
{
Button RedSquare = CreateBtnRedSqure();
RedSquare.Location = new Point(X, Y + Constant.SquareMiddleSpace);
square[t, i] = RedSquare;
}
else if (t == 1)
{
Button BlueSquare = CreateBtnBlueSqure();
BlueSquare = new Point(X, Y + Constant.SquareMiddleSpace);
square[t, i] = BlueSquare;
}
else if (t == 2)
{
Button GreenSquare = CreateBtnGreenSqure();
GreenSquare = new Point(X, Y + Constant.SquareMiddleSpace);
square[t, i] = GreenSquare;
}
else if (t == 3)
{
Button YellowSquare = CreateBtnYellowSqure();
YellowSquare = new Point(X, Y + Constant.SquareMiddleSpace);
square[t, i] = YellowSquare;
}
pnlChessBoard.Controls.Add(square[t, i]);
X = X + (*width of your btn size)
}
Y = Y + (* height of your btn size );
}

Need help setting up Win Condition for C# Connect Four Game

I'm trying to figure out how to set up my win condition (when the player lines up four chips as the same color horizontally, vertically, or diagonally). The win condition when met will display a win message, add 1 to a player win and player loss variable, add text to a list box, and clear the board.
I set up the board when the user presses the start button using the following code:
btnStartGame.Enabled = false;
btnStartGame.Visible = false;
btnExitGame.Enabled = true;
btnExitGame.Visible = true;
//This for loop creates the buttons used for the gameplay
for (int i = 0; i < gameButtons.Length; i++)
{
int index = i;
this.gameButtons[i] = new Button();
int x = 50 + (i % 7) * 50;
int y = 50 + (i / 7) * 50;
this.gameButtons[i].Location = new System.Drawing.Point(x, y);
this.gameButtons[i].Name = "btn" + (index + 1);
this.gameButtons[i].Size = new System.Drawing.Size(50, 50);
this.gameButtons[i].TabIndex = i;
this.gameButtons[i].UseVisualStyleBackColor = true;
this.gameButtons[i].Visible = true;
gameButtons[i].Click += (sender1, ex) => this.PlaceChip(sender1, index);
this.Controls.Add(gameButtons[i]);
From there main game play uses the following code for "dropping" chips into the columns:
private void PlaceChip(object sender, int index)
{
var pressedButton = (Button)sender;
if (pressedButton.BackColor == Color.BlanchedAlmond)
{
var newBackColor = black ? Color.Red : Color.Black;
var buttonToChangeIndex = index;
while (buttonToChangeIndex + 7 < gameButtons.Count() &&
gameButtons[buttonToChangeIndex + 7].BackColor == Color.BlanchedAlmond)
{
buttonToChangeIndex += 7;
}
gameButtons[buttonToChangeIndex].BackColor = newBackColor;
black = !black;
}
}
Currently my Win Condition code looks like the following, I just am not sure how I need to set this up correctly (assuming I am making a mistake somewhere) or how I call this and set up the arguments correctly when I call it.
private void WinCondition(int a, int b, int c, int d)
{
if (gameButtons[a].BackColor == gameButtons[b].BackColor && gameButtons[a].BackColor == gameButtons[c].BackColor && gameButtons[a].BackColor == gameButtons[d].BackColor)
{
gamesPlayed += 1;
do
{
if (gameButtons[a].BackColor == Color.Red)
{
MessageBox.Show("Player 1 Wins!");
player1wins += 1;
player2loss += 1;
lstScoreBoard.Items.Add("Player One");
//add to file
ResetBoard();
}
else
{
MessageBox.Show("Player 2 Wins!");
player2wins += 1;
player1loss += 1;
lstScoreBoard.Items.Add("Player Two");
ResetBoard();
}
if(gamesPlayed == 5)
{
MessageBox.Show("Maximum number of games have been played!\nWin board will now be reset!");
gamesPlayed = 0;
player1wins = 0;
player2wins = 0;
player1loss = 0;
player2loss = 0;
}
} while (gamesPlayed > 5);
}
}
If there is a better way to set up this win condition (In regards to the arguments etc) I am open for it! I'm at a loss for how to properly set it up!
If my description of what I need doesn't make sense feel free to ask and I will try to clarify!

C#, Having an issue with two buttons starting one method

If you're from the USA, and you've ever been to a Cracker Barrel, then you've probably played the board game where you have to jump pegs until you only have one left. It's similar to Chinese checkers, with just a pyramid, or a triangle.
I have a form that makes the buttons and adds them to the form, and I have a "TheBoard" class that has all of the rules for how jumping works on the form. In my form, I also have a button clicker method that needs to run all of this.
I seem to have hit a brick wall. I can't figure out the logic behind getting it to accept a second click, in order to move through the whole if statements in the board class. My parameter for the move method in the board class takes an int x, which is the button you click on as a parameter. I feel like I'm missing the second half of the move. How do I get my move method to register two button clicks (the starting location of the peg and the end location of the peg)?
Code for form:
public partial class Form1 : Form
{
private Button[] btn = new Button[15];
private TheBoard myboard = new TheBoard();
public Form1()
{
InitializeComponent();
int buttonsPerRow = 1;
int index = 0;
while (index < btn.Length)
{
int increment = this.Width / (buttonsPerRow + 1);
for (int j = 1; j <= buttonsPerRow; j++)
{
btn[index] = new Button
{
//other style elements of the button
Name = "btn" + index
}
btn[index].Click += new EventHandler(this.My_Click);
Controls.Add(btn[index]);
index++;
}
buttonsPerRow++;
}
}
private void My_Click(object sender, EventArgs e) {
myboard.getValues();
Button b = (Button)sender;
string bName = b.Name;
// Now pull off the btn
string num = bName.Substring(3, bName.Length - 3);
// Parsing the number to an int
int x = Int32.Parse(num);
myboard.move(x);
int[] color = myboard.getValues();
for (int i = 0; i < 15; i++)
{
color = myboard.getValues();
if (color[i] == TheBoard.hasPeg)
{
btn[i].BackColor = System.Drawing.Color.Yellow;
}
else
btn[i].BackColor = System.Drawing.Color.Black;
}//for
}
}
Code for TheBoard class:
class TheBoard
{
static public int hasPeg = 100;
static public int noPeg = 50;
private int[] board;
private int firstMove; //1st click
public TheBoard()
{
board = new int[15];
board[0] = noPeg;
for(int i = 1; i < 15; i++)
{
board[i] = hasPeg;
}
firstMove = -1; //giving last move a location, starting it at the beginning
}
public int move(int x)
{
if(firstMove == -1)
{
firstMove = x;
return 0;
}
// blank at 0
// if you click a blank your 1st move
if (firstMove == noPeg)
{
Console.WriteLine("You cant move if there isn't a peg.");
return 666;
}
// first---------------------------------------middle-----------------------end
if (firstMove == 1 && board[0] == hasPeg && board[3] == hasPeg && board[6] == noPeg)
{
RemovePeg(board[0], board[3], board[6]);
return 0;
}
if (firstMove == 1 && board[0] == hasPeg && board[2] == hasPeg && board[4] == noPeg)
{
RemovePeg(board[0], board[2], board[4]);
return 0;
}
//etc for remaining firstMove possibilities
firstMove = -1;
return 5;
}
private int RemovePeg(int first, int second, int goal) {
board[goal] = hasPeg;
board[first] = noPeg;
board[second] = noPeg;
return 0;
}
public int[] getValues()
{
return board;
}
}
I looked over the code and I think I understand your problem; you can select the starting peg but you don't have a way to select where it should go. With minimal edit to your code, I would store the first button click in a global variable and then the second button click knows that it is the second and initiates the board move with the two pieces of information (and resets the global variable).

C# - How to access property of an array object?

I dont know how to show clearly, so:
Example - I create an array of button like this:
Button[,] _button = new Button[3, 3];
public MainPage()
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
_button[i, j] = new Button();
_button[i, j].Name = "btn" + i.ToString() + j.ToString();
_button[i, j].Tag = 0;
//Add Click event Handler for each created button
_button[i, j].Click += _button_Click;
boardGrid.Children.Add(_button[i, j]);
Grid.SetRow(_button[i, j], i);
Grid.SetColumn(_button[i, j], j);
}
} // end MainPage()
private void _button_Click(object sender, RoutedEventArgs e)
{
Button b = (Button)sender;
if (...)
b.Tag = 1;
else
b.Tag = 2;
}// end Click Event
Now how can I compare the Tag of 2 buttons in that array like:
b[1,1].Tag == b[1,2].Tag ? ...<do st>... : ....<do st>...
If you need to find position of control in array consider to set Control.Tag to that position instead of search:
_button[i, j].Tag = new System.Drawing.Point{ X = j, Y = i};
And instead of searching just
Point position = (Point)((Button)sender).Tag;
Or if you need more information (like Position + 0/x/empty choice you have) - have custom class to hold all information you need:
enum CellState { Empty, Player1, Player2 };
class TicTacToeCell
{
public Point Position {get;set;}
public CellState State {get;set;}
}
Now when you have position and state - use _buttons array to index access other ones:
Check same row:
Point position = (Point)((Button)sender).Tag;
int player1CountInThisRow = 0;
for (var col = 0; col < 3; col++)
{
if (((TicTacToeCell)(_button[position.Y, col].Tag).State == CellState.Player1)
{
player1CountInThisRow ++;
}
}
This is more of a long-winded clarification than a definite answer, but it may uncover what you're really trying to do:
In the code that you show b is (presumably) a single Button, not an array of buttons. Do you mean:
_button[1,1].Tag == _button[1,2].Tag ? ...<do st>... : ....<do st>...
Or are you trying to compare b (the event sender) to a button relative to it in the array?

Movement on the console in c#

I'm working on a snake game right now, and am having difficulty with making sure the tail follows my head. I'm currently trying to get it to work, and I've tried about a dozen different ideas, all of which either make it stall out completely (e.g. snake appears to be frozen in one place), or the vertical motion happens at all points of the tail at once, instead of one movement following another. I'm also having some trouble with the Console.Clear() method that seems inescapable. Either I do it too many times and it deletes everything but the first point of my snake, or I don't and the old positions don't get erased. Here's the code (it's a test code, split from the actual game as I need to make sure the code works):
class Program
{
const int size = 10;
struct Sprite
{
public char[] ch;
public int[,] posXY;
public int directionX;
public int directionY;
}
static void Main(string[] args)
{
int startX = 10;
int startY;
Sprite player = new Sprite();
player.ch = new char[7];
player.posXY = new int[7,2];
for (int i = 0; i < player.ch.Length; i++)
{
player.ch[i] = '*';
}
for (int i = 0; i < 7; i++)
{
startY = 10;
player.posXY[i, 0] = startX;
player.posXY[i, 1] = startY;
startX--;
}
ConsoleKeyInfo cki = new ConsoleKeyInfo();
while (true)
{
update(cki, ref player);
draw(player);
Thread.Sleep(200);
}//end while
}//end main
static void update(ConsoleKeyInfo cki, ref Sprite player)
{
if (Console.KeyAvailable)
{
cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.LeftArrow || cki.Key == ConsoleKey.A)
{
player.directionX = -1;
player.directionY = 0;
}
if (cki.Key == ConsoleKey.RightArrow || cki.Key == ConsoleKey.D)
{
player.directionX = 1;
player.directionY = 0;
}
if (cki.Key == ConsoleKey.UpArrow || cki.Key == ConsoleKey.W)
{
player.directionX = 0;
player.directionY = -1;
}
if (cki.Key == ConsoleKey.DownArrow || cki.Key == ConsoleKey.S)
{
player.directionX = 0;
player.directionY = 1;
}
}//endif
for (int i = 0; i < 7; i++)
{
player.posXY[i, 0] = player.posXY[i, 0] + player.directionX;
player.posXY[i, 1] = player.posXY[i, 1] + player.directionY;
}
}//end update
static void draw(Sprite player)
{
Console.Clear();
for (int i = 0; i < 7; i++)
{
Console.SetCursorPosition(player.posXY[i, 0], player.posXY[i, 1]);
Console.Write(player.ch[i]);
}
}//end draw
}
P.S. I need to use a struct for my snake, using a Class isn't an option.
IMHO the best datastructure to describe the "snake" game is a queue. So that you can dequeue ("undraw") 1 "item" from the tail and enqueue ("draw") a new one with the new coordinates as the head.
If it happens to be on the "apple" you just skip one dequeue operation or enqueue twice.
If you are not familiar with the Queue data structure take a look at this fist: http://en.wikipedia.org/wiki/Queue_(abstract_data_type)
Look at the default Queue of .net framework here: http://msdn.microsoft.com/en-us/library/7977ey2c.aspx

Categories