c# panel image only updates half the time - c#

For my programming class we are required to make a memory match game. When the player clicks on a panel an image is displayed. The player clicks on two panels, if the images match they are removed, if they are different they are turned face down.
The problem I am having with this is that only the image from the first panel gets displayed, even though I am using the same line of code to display the images from both panels, and use Thread.Sleep to pause the program after the second tile has been picked. I don't understand why this is happening, any help would be appreciated.
private void tile_Click(object sender, EventArgs e)
{
string tileName = (sender as Panel).Name;
tileNum = Convert.ToInt16(tileName.Substring(5)) - 1;
//figure out if tile is locked
if (panelArray[tileNum].isLocked == false)
{
pickNum++;
//although the following line of code is used to display the picture that is stored in the tile array
//what is happening is that it will only display the picture of the first tile that has been picked.
//when a second tile is picked my program seems to ignore this line completely, any ideas?
panelArray[tileNum].thisPanel.BackgroundImage = tiles[tileNum].tileImage;
if (pickNum == 1)
{
pick1 = tileNum;
panelArray[tileNum].isLocked = true;
}
else
{
pick2 = tileNum;
UpdateGameState();
}
}
}
private void UpdateGameState()
{
Thread.Sleep(1500);
if (tiles[pick1].tag == tiles[pick2].tag)//compares tags to see if they match.
{
RemoveTiles();
}
else
{
ResetTiles();
}
pickNum = 0;
guess += 1;
guessDisplay.Text = Convert.ToString(guess);
if (correct == 8)
{
CalculateScore();
}
}

try this:
(sender as Panel).BackgroundImage = tiles[tileNum].tileImage;
you have to be sure that your tile_Click method is associated to both panel...

Related

A random picturebox won't move when coded in Timer

I don't know if I still have missing on this but whenever you want to add PictureBox, you just find it on Toolbox and drag it on the UI. But what I did is I coded it by adding PictureBox then what I want is I have to move it to the right. I coded it on a Timer and this is how I do.
private void enemyMove_Tick(object sender, EventArgs e)
{
GameMenu menu = new GameMenu();
if (menu.cmbox_Level.Text.Equals("Easy"))
{
this.Controls.Add(menu.EnemyTank);
menu.EnemyTank.Width = 26;
menu.EnemyTank.Height = 32;
menu.EnemyTank.BackgroundImage = Properties.Resources.Tank_RIGHT_v_2;
menu.EnemyTank.BackgroundImageLayout = ImageLayout.Stretch;
menu.EnemyTank.Left += 2;
}
}
Don't ask me if the Timer is started. Yes it already started, it was coded on the Form. But somehow when I start the program it doesn't move. But then I tried adding PictureBox, this time I tried dragging it to UI then add an Image on it, then coded it by moving to the right. When I start the program it works. But what I want is that whenever I start the button it will just make the random PictureBox move to the right. Idk what's the missing in here.
I made some assumptions. If I my assumptions aren't correct, please update your post for details. Following content is copied from my comment.
A new GameMenu will always create a new EnemyTank.
A EnemyTank's default Left value is fixed;
Your enemyMove_Tick is keep creating GameMenu and EnemyTank.
That is, every tick, a EnemyTank is created and value changed to "default value plus 2" in your code.
To avoid it, you have to keep EnemyTank instance somewhere instead of keep creating it.
Here's a example.
GameMenu m_menu;
void YourConstructor()
{
// InitializeComponent();
// something else in your form constructor
m_menu = new GameMenu();
m_menu.EnemyTank.Width = 26;
m_menu.EnemyTank.Height = 32;
m_menu.EnemyTank.BackgroundImage = Properties.Resources.Tank_RIGHT_v_2;
m_menu.EnemyTank.BackgroundImageLayout = ImageLayout.Stretch;
this.Controls.Add( m_menu.EnemyTank );
}
private void enemyMove_Tick(object sender, EventArgs e)
{
if (menu.cmbox_Level.Text.Equals("Easy"))
{
m_menu.EnemyTank.Left += 2;
}
}

Drawing Rectangles on an image from a different class

I am attempting to generate a set of rectangles on an image. To achieve this, I call a method that is present in a seperate class (Because multiple forms need to call this function.) Let's say I have Form A and Form B that both need to draw said set of rectangles:
From Form A it works just fine, from Form B it doesn't draw anything, but it doesn't return an exception either.
To make sure I haven't missed anything, I went as far as to copy and paste the function calls from both forms so the two of them are identical. I have also triple checked any semantic errors but have been unable to find any.
The function call from Form A is as follows:
private void PbPreview_Click(object sender, EventArgs e)
{
if (NewPage) //This bool is true when the user is displaying a new page(Image)
{
StartingY = MousePosition.Y - 76; //Save the Y position of the click in a float variable
Form1.MainController.DrawRect(StartingY, PbPreview.Image); //Function call
NewPage = false; //Set the new Page bool to false to prevent overdrawing
}
}
The function call from Form B is as follows:
private void PbFactuur_Click(object sender, EventArgs e)
{
if (NewPage) //Same use as the NewPage bool from above
{
MouseY = MousePosition.Y - 76; //Saving mouse position
Form1.MainController.DrawRect(MouseY, PbFactuur.Image); //Function call
NewPage = false; //Set new page to false to prevent overdrawing
MessageBox.Show("I have executed the function"); //Debug info
}
}
And here is the code that is present within the function:
public void DrawRect(float Ypos, Image DrawSubject)
{
try
{
foreach (Rectangle R in Form1.nieuwBedrijf.Rects)
{
Rectangle TempRect = R;
TempRect.Y = Convert.ToInt32(Ypos);
Graphics G = Graphics.FromImage(DrawSubject);
G.DrawRectangle(Pens.Black, TempRect.X * Form1.nieuwBedrijf.ScaleX, TempRect.Y * Form1.nieuwBedrijf.ScaleY, TempRect.Width * Form1.nieuwBedrijf.ScaleX, 1920);
}
}
catch
{
MessageBox.Show("No rectangles have been defined yet.");
}
}
Sidenote: Rects is a list of user defined rectangles.
The expected result would be that at the location where the user clicks, the set of rectangles will appear. But in reality, nothing appears at all.
The application doesn't return any sort of error message, and with the use of breakpoints and messageboxes I have been able to verify that the function does execute.
I hope anyone is able to point me to a potential solution to this problem.
Many thanks in advance
~Melvin
After some tinkering around I have found the following solution:
The rectangles were actually being drawn, but it was not being shown on screen. To have the rectangles show up on screen, I had to add the following line of code:
private void PbFactuur_Click(object sender, EventArgs e)
{
if (NewPage) //Same use as the NewPage bool from above
{
MouseY = MousePosition.Y - 76; //Saving mouse position
Form1.MainController.DrawRect(MouseY, PbFactuur.Image); //Function call
NewPage = false; //Set new page to false to prevent overdrawing
MessageBox.Show("I have executed the function"); //Debug info
Refresh();//<----- This line fixed the problem
}
}

Detecting first or second Mouse Button Release?

I want to know how to detect if the user has released the mouse button the first time, or the times after that:
Pseudo-Code:
if *first* (Input.GetMouseButtonUp(0))
{
do something
}
if *second, third, fourth..etc.* (Input.GetMouseButtonUp(0))
{
do something else
}
I really have no idea on how to accomplish this. I'm sure it's pretty simple though!
This is only an idea, but you could do this using a flag variable, like this:
private static bool WasFirstTimeReleased = false;
if (Input.GetMouseButtonUp(0))
{
if (!WasFirstTimeReleased)
{
WasFirstTimeRelease = true;
//do your stuff for first time
}
else
{
//do your stuff for all other times
}
}
Generally, you have to remember somewhere how many times button was released. Just create field in yours class:
private int clicks = 0;
then:
if (Input.GetMouseButtonUp(0))
{
if(clicks == 0)
{
// do something on first click
}
else
{
// do something on further click
}
clicks++;
}
If the object where you store clicks counter is created each time you press mouse button then mark counter using static word.
Keep track of mouse clicks:
int _leftUp;
void Update()
{
var leftUp = Input.GetMouseButtonUp(0);
if (leftUp) _leftUp++;
// etc ...
}
Easiest way to accomplish this would be to use a counter to check the number of times the user has released the button.
private int releaseCounter = 0;
And then in an if statement:
if (Input.GetMouseButtonUp(0)) {
releaseCounter++;
//If you know on which release you want the code to be executed,
//replace the x with that number.
if (releaseCounter == x) {
//your code here
}
//If you want the code to be executed at set intervals.
//replace the x with the interval number.
if(releaseCounter%x == 0) {
//your code here
}
}
Hope I helped.

C# WinForm + Barcode Scanner input, TextChanged Error

UPDATE: SOLUTION AT END
I have a Winform, label1 will display some info returned from a SQL Search using the input (MemberID) received from barcode scanner via txtBoxCatchScanner.
Scenario is people swiping their MemberID Cards under the scanner as they pass through reception and the Winform automatically doing a Search on that MemberID and returning their info including for example "Expired Membership" etc on the receptionist's PC which has the winForm in a corner of her desktop.
I have the Below Code working fine on first swipe (eg. first person)
The number MemberID, for example 00888 comes up in the text box, ADO.NET pulls the data from SQL and displays it fine.
one thing to note maybe, the cursor is at the end of the memberID: 00888|
All good so far, THEN:
when swipe 2 (eg. next person) happens
their number (say, 00999) gets put onto the end of the first in the txtBox eg: 0088800999 so naturally when TextChanged Fires it searches for 0088800999 instead of 00999 ....
I've tried:
txtBoxCatchScanner.Clear();
and
txtBoxCatchScanner.Text = "";
and
reloading the form
at the end of my code to "refresh" the text box
but i guess they trigger the TextChanged Event
How can i refocus or ... clear the old number and cursor back to start of txtBox after the previous swipe has done its stuff...
I'm a beginner so I'm sure the code below is pretty crap....
But if anyone has time, please let me know how fix it to do what i want.
UPDATE:
Ok after much experimenting I''ve managed to get this 1/2 working now hopefully someone more experience can help me to completion! :P
if (txtBoxCatchScanner.Text.Length == 5)
{
label1.Text = txtBoxCatchScanner.Text; // just a label for testing .. shows the memmber ID
txtBoxCatchScanner.Select(0, 5);
}
SO scan 1, say 00888 , then that gets highlighted, scan 2 , say 00997 ... sweet! overwrites (not appends to) 00888 and does it's thing ... scan 2 0011289 ... DOH!!
Problem: not all barcodes are 5 digits!! they are random lengths!! Memeber ID range from 2 digit (eg. 25) to 10 digits, and would grow in the future...
Edit: Something I've discovered that is that the barcodes are read as indvidual key presses. I think this is why answer 1 below does not work and while the big probmlems:
for example with 00675 the input (?output) from the scanner is:
Down: Do
Up: Do
Down: Do
Up: Do
Down: D6
Up: D6
Down: D7
Up: D7
Down: D5
Up: D5
down: Retunn
Up: Return
other info: barcode scanner is: an Opticon OPL6845 USB
Thanks
private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
//Get BarCode
//VALIDATE: Is a Number
double numTest = 0;
if (Double.TryParse(txtBoxCatchScanner.Text, out numTest))
{
//IS A NUMBER
member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
//SEARCH
//Search Member by MemberID (barcode)
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
//PLAY SIREN aLERT SOUND
//C:\\WORKTEMP\\siren.wav
SoundPlayer simpleSound =
new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
}
else
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
////
//lblMemberName.Text = "";
//lblMemberID.Text = "";
//lblMemberID.Text = "";
}
SOLUTION:
The System won't let me answer my own question for another 3 hours, as I'm a newbie only 1 post, so will put here:
First thanks everyone for your help and Patience.
I Have finally figured a solition, not fully tested yet as its 2am and bed time.
following along from my updates where I had success but hit the variable length of MemberID problem. I've now overcome that with the Code below:
namespace SCAN_TESTING
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)Keys.Return)
{
e.Handled = true;
int barcodeLength = txtBoxCatchScanner.TextLength;
txtBoxCatchScanner.Select(0, barcodeLength);
//TEST
label3.Text = barcodeLength.ToString();
//TEST
label2.Text = txtBoxCatchScanner.Text;
}
}
I'll add this to my previous "real" code and test in the morning
But at this stage is doing exactly what I want! =]
Update: Tested it .. works exactly what needed:
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)Keys.Return)
{
e.Handled = true;
int barcodeLength = txtBoxCatchScanner.TextLength;
txtBoxCatchScanner.Select(0, barcodeLength);
//
//INSERT ORGINAL CODE HERE. No Changes were needed.
//
}//end of if e.KeyValue ...
}//end txtBoxCatchScanner_KeyUp
Hope that helps anyone in the future!! :)
Thanks again for the 2 very good solutions, I can see how they work, and learnt alot.
Just didn't work in my case - more likely due to myself or my error/not understanding, or scanner type.
I´m not exactly sure what the actual problem is.
txtBoxCatchScanner.Clear();
txtBoxCatchScanner.Text = "";
both trigger the "Changed" Event.
But they also clear the box. So that should be what you want to do.
You could check at the beginning if the box is actually empty, and return in case it is. Like:
if(txtBoxCatchScanner.Text == "" |txtBoxCatchScanner.Text == string.Empty)
return;
So nothing else happens, if the box is empty.
If I misunderstood your problem, please specify and I will try to help.
Regards
EDIT:
Your function should work if it looked something like this:
private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
if(txtBoxCatchScanner.Text == "" | txtBoxCatchScanner.Text == string.Empty)
return; // Leave function if the box is empty
//Get BarCode
//VALIDATE: Is a Number
int numTest = 0;
if (int.TryParse(txtBoxCatchScanner.Text, out numTest))
{
//IS A NUMBER
//member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
member.MemberID = numTest; // you already converted to a number...
//SEARCH
//Search Member by MemberID (barcode)
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
//PLAY SIREN aLERT SOUND
//C:\\WORKTEMP\\siren.wav
SoundPlayer simpleSound =
new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
}
else
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
////
//lblMemberName.Text = "";
//lblMemberID.Text = "";
//lblMemberID.Text = "";
}
txtBoxCatchScanner.Clear();
}
The barcode scanner you use seems to function as a HID - a keyboard emulation. Every simple barcode scanner I know (and I'm working with them on a daily basis) has the option of specifying a suffix for the scanned barcode. Change the suffix to CRLF and add a default button to your form. Scanning a barcode that ends with CRLF will then automatically "push the button".
Move the code that performs the checks from TextChanged event in to the event handler for the buttons Click event and remove the TextChanged event handler. Then, when the button is clicked, also clear the text box and set the focus back to the text box.
You should be good to go, now.
You can easily check whether the barcode scanner already has the correct suffix configured: Open up Notepad and scan some barcodes. If they all appear on separate lines, then everything's fine. Otherwise you'll need to scan some configuration barcodes from the scanner's manual.
To sum it all up, this should be the code for the button's Click event:
private void btnCheckMember_Click(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
string memberText = txtBoxCatchScanner.Text.Trim();
txtBoxCatchScanner.Text = String.Empty;
int numTest = 0;
if (String.IsNullOrEmpty(memberText) ||!Int32.TryParse(memberText, out numTest))
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
return;
}
member.MemberID = numTest;
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
SoundPlayer simpleSound = new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
This solution avoids the following problems:
The event being triggered upon every character added/removed from the content of the text box (which is also the case when scanning a barcode: They are added one by one as if they were entered on a keyboard)
Resulting from 1. the problem that a member check is performed upon every entered character
Resulting from 2. the problem that member XYZ will never be found if there is a member XY in the database, as the check stops after finding XY
Resulting from 3. the problem that member XY will also not be found, but only member Z, because in 3. the text box is cleared and Z is the only character being entered.
The best way to clear the textBox on the next textChange event.
Insert this line
txtBoxCatchScanner.SelectAll();
at the end of TextChange function.. This will select the text, so that i can be replaced easily on the next event.

Tic Tac Toe - C# - Having trouble completing checks

So here's the deal, I'm trying to compare images in a local resource for X and O, and if they're the same in the winCondition array, to message the user they won.
The problem I'm finding is that b1.Image isn't giving me the proper comparison. It's comparing this:
+ b1.Image {System.Drawing.Bitmap} System.Drawing.Image {System.Drawing.Bitmap}
when I want it to compare the image names instead.
One of these problems is that when turnNumber = 5, it says I won, when I haven't. I believe this is due to the b1.Image problem. Once I click another square, it checks for the win again.
I want to disable the buttons once a game is completed, however I don't know how to do this.
Would it be as simple as:
foreach (Button btnEnabled in buttonArray)
{
btnEnabled.Enabled = false;
}
Here is the code, and again, thank you for any help. I have been struggling with this for a few days.
namespace BGreinAssignment2
{
public partial class frmTicTacToe : Form
{
//Global variables
private bool player1Turn = false;
private bool player2Turn = true;
private int[,] winCondition =
{
{0,1,2}, //Horizontal top
{3,4,5}, //Horizontal Middle
{6,7,8}, //Horizontal Bottom
{0,3,6}, //Vertical Left
{1,4,7}, //Vertical Middle
{2,5,8}, //Vertical Right
{0,4,8}, //Diagonal Top Left to Bottom Right or Vice-Versa
{2,4,6} //Diagonal Top Right to Bottom Left or Vice-Versa
};
private Button[] buttonArray;
private int turnNumber = 0;
public frmTicTacToe()
{
InitializeComponent();
}
//Creates the button array for checks and sets X to go first.
private void frmTicTacToe_Load(object sender, EventArgs e)
{
//Creates button array for checking if image is there/check for beginning of game
buttonArray = new Button[9] {btnTopLeft, btnTopMid, btnTopRight, btnMidLeft, btnMid, btnMidRight, btnBotLeft, btnBotMid, btnBotRight};
//Sets player 1 to go first to satisfy the "X always goes first"
player1Turn = true;
player2Turn = false;
}
/// <summary>
/// Checks the buttons if the images don't create a win condition through the winCheck method,
/// displays message box to user with "Draw!" break is included so it doesn't say "Draw!" for each button it checks.
/// </summary>
private void drawCheck()
{
foreach (Button checkDraw in buttonArray)
{
if (checkDraw.Image != null)
{
MessageBox.Show("Draw!");
break;
}
}
}
/// <summary>
/// Checks the win condition to see if the images are the same. If they are, it will show a message box with the winner.
/// </summary>
/// <param name="btnChecks">Creates an array to check the button images</param>
/// <returns>If there is a winner, returns true and shows message box</returns>
private bool winCheck(Button[] btnChecks)
{
bool win = false;
for (int i = 0; i < 8; i++)
{
int a = winCondition[i, 0], b = winCondition[i, 1], c = winCondition[i, 2];
Button b1 = btnChecks[a], b2 = btnChecks[b], b3 = btnChecks[c];
if (b1.Image == null || b2.Image == null || b3.Image == null)
{
continue;
}
if (b1.Image == b2.Image && b2.Image == b3.Image)
{
win = true;
MessageBox.Show("Game over. " + b1.Image + " Wins!");
}
}
return win;
}
//If player chooses top left square
private void btnTopLeft_Click(object sender, EventArgs e)
{
if (btnTopLeft.Image == null)
{
if (player1Turn == true)
{
if (turnNumber == 0)
{
btnTopLeft.Image = BGreinAssignment2.Properties.Resources.tic_tac_toe_X;
player1Turn = false;
player2Turn = true;
turnNumber++;
}
else
{
btnTopLeft.Image = BGreinAssignment2.Properties.Resources.tic_tac_toe_X;
player1Turn = false;
player2Turn = true;
turnNumber++;
if (turnNumber >= 5)
{
winCheck(buttonArray);
}
if (turnNumber == 9)
{
drawCheck();
}
}
}
else
{
btnTopLeft.Image = BGreinAssignment2.Properties.Resources.tic_tac_toe_O;
player1Turn = true;
player2Turn = false;
turnNumber++;
if (turnNumber <= 5)
{
winCheck(buttonArray);
}
if (turnNumber == 9)
{
drawCheck();
}
}
}
else
{
MessageBox.Show("This space has already been selected");
}
}
//Excluded rest of code (just button clicks, repeats of same for 9 squares)
/// <summary>
/// Resets the game for the player.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPlayAgain_Click(object sender, EventArgs e)
{
//For each button, set image to null then reset turn counter and set turn to player 1.
foreach (Button btnSpaces in buttonArray)
{
btnSpaces.Image = null;
}
turnNumber = 0;
player1Turn = true;
player2Turn = false;
}
}
}
As you discovered, comparing Images directly is not the answer. I haven't tested this, but I suspect it's because each Image could have very different properties, despite being loaded from the same resource. For example, if one button was only 20-pixels square, and another was 50, the Height and Width properties would be different. See the documentation for some other properties.
A better way to handle this, as #John3136 said, is to split the model away from the drawing. This could be as simple as using the Tag property on each button to store either an "O" or an "X". You'd check everything the same as you do now, except you'd be comparing b1.Tag == b2.Tag && b2.Tag == b3.Tag. A better, but more complicated way, would be to have an array of something to represent your game board. As with any programming problem, there's many possible ways to do it - char[9] would be the simplest, although string[] or bool?[] could work, creating an enum and storing an array of that, or an array of arrays of any of the above. (Also List<> instead of an array, eventually). In either case, you'd have to update your model at the same time as you update the image, but you're then doing a much simpler comparison to test for victory.
You're entirely correct about disabling the buttons - but here's a question for you. What happens if someone clicks on a button that the other player has already clicked? Sure, you can alert the user, but it still looks like a valid choice. Why not disable it as soon as it's clicked?
I'm also going to go a bit further afield and give you a tip for the "//Excluded rest of code (just button clicks, repeats of same for 9 squares)" line. If you're going to repeat the same code more than twice (and some people would say more than once), you're better off making a function which takes whatever will differentiate it as an argument. For example, you could have
//If player chooses top left square
private void btnTopLeft_Click(object sender, EventArgs e)
{
DoClick(btnTopLeft);
}
//If player chooses top center square
private void ptnTopCenter_CLick(object sender, EventArgs e)
{
DoClick(btnTopCenter);
}
private void DoClick(Button button)
{
// Manipulate button appropriately
}
This isn't doing anything you don't already know how to do - you're already calling other functions, and passing buttons around in arguments (see winCheck()). It's just a way of thinking which will reduce the amount of code you need to write, and thus the places you need to fix any given bug.

Categories

Resources