Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

C#

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

Get C# tic tack toe game to load

This is my first tic tac toe game. My code is not crashy at all but I have a feeling I don't have the code correctly placed to load the game and make it playable. Nothing happens when the form appears in VS.

Can anyone point me in the right direction to move the blocks around so the game loads and is playable?

It's a form application. Do I need a main method? Not sure where it goes or what it calls.

Thanks.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TicTacToe
{
    public partial class ticTacToefrm : Form
    {
        public ticTacToefrm()
        {
            InitializeComponent();
        }



        Label[,] grid = new Label[3, 3];
        char[,] game = new char[3, 3];

        int numClicks;
        bool isXTurn;



        public void resetGame()
        {


            Label[,] grid ={
                {label1, label2, label3},
                {label4, label5, label6},
                {label7, label8, label9}
            };




            char[,] game = {
                {' ', ' ', ' '},
                {' ', ' ', ' '},
                {' ', ' ', ' '}
            };

            numClicks = 0;
            isXTurn = true;
            lblStatus.Text = "Welcome to Tic-Tac-Toe";

            int row, col;
            for (row = 1; row <= 3; row++)
            {


                for (col = 2; col <= (row / col); col++)
                {
                    grid[row, col].Text = " ";
                    game[row, col] = ' ';
                }


            }



        }

        public void gameOver()
        {

            char winner = ' ';

            if (game[0, 0] == 'X' && (game[1, 1] == 'X' && game[2, 2] == 'X'))
            {
                if (game[0, 2] == 'X' && (game[1, 1] == 'X' && game[2, 0] == 'X'))
                {
                    if (game[0, 0] == 'X' && (game[0, 1] == 'X' && game[0, 2] == 'X'))
                    {
                        if (game[1, 0] == 'X' && (game[1, 1] == 'X' && game[1, 2] == 'X'))
                        {
                            if (game[2, 0] == 'X' && (game[2, 1] == 'X' && game[2, 2] == 'X'))
                            {
                                if (game[0, 0] == 'X' && (game[1, 0] == 'X' && game[2, 0] == 'X'))
                                {
                                    if (game[0, 1] == 'X' && (game[1, 1] == 'X' && game[1, 2] == 'X'))
                                    {
                                        if (game[0, 2] == 'X' && (game[1, 2] == 'X' && game[2, 2] == 'X'))
                                        {

                                            winner = 'X';


                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if (game[0, 0] == 'O' && (game[1, 1] == 'O' && game[2, 2] == 'O'))
                {
                    if (game[0, 2] == 'O' && (game[1, 1] == 'O' && game[2, 0] == 'O'))
                    {
                        if (game[0, 0] == 'O' && (game[0, 1] == 'O' && game[0, 2] == 'O'))
                        {
                            if (game[1, 0] == 'O' && (game[1, 1] == 'O' && game[1, 2] == 'O'))
                            {
                                if (game[2, 0] == 'O' && (game[2, 1] == 'O' && game[2, 2] == 'O'))
                                {
                                    if (game[0, 0] == 'O' && (game[1, 0] == 'O' && game[2, 0] == 'O'))
                                    {
                                        if (game[0, 1] == 'O' && (game[1, 1] == 'O' && game[1, 2] == 'O'))
                                        {
                                            if (game[0, 2] == 'O' && (game[1, 2] == 'O' && game[2, 2] == 'O'))
                                            {

                                                winner = 'O';
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


                else {
                    if (numClicks == 9)
                    {

                        lblStatus.Text = "The game ends in a tie.";



                    }
                    else {
                        lblStatus.Text = "Game Over:" + winner + " Won!!!";
                    }
                }
            }
        }


        private void ticTacToefrm_Load(object sender, EventArgs e)
        {

        }



        private void label1_Click(object sender, EventArgs e)
        {
            Label lbl = (Label)sender; // cast sender to a Label

            for (int row = 0; row < 3; row++)
            {
                for (int col = 0; col < 3; col++)
                {
                    if (lbl == grid[row, col])
                    {
                        if (lbl.Text != " ")
                        {
                            lblStatus.Text = "Invalid Move";
                            return;
                        }
                        else if (lbl.Text == " " && isXTurn == true)
                        {
                            lbl.Text = "X";
                            lbl.ForeColor = Color.Red;
                            game[row, col] = 'X';
                        }
                        else
                        {
                            lblStatus.Text = "O's Turn";
                            lbl.Text = "O";
                            lbl.ForeColor = Color.Blue;
                            game[row, col] = 'O';
                        }
                        isXTurn = !isXTurn;
                        numClicks++;
                        gameOver();
                    }
                }
            }
        }



        private void lblStatus_Click(object sender, EventArgs e)
        {

        }

        private void restartBtn_Click(object sender, EventArgs e)
        {
            resetGame();
            lblStatus.Text = "X's Turn";
        }
    }
}

12 Answers

Steven Parker
Steven Parker
231,269 Points

I don't think I've ever seen the word "crashy" before. :laughing: I assume you mean the code compiles without errors? Or that it runs even if it doesn't do what you expect?

You asked: "Do I need a main method?" Yes, but it's normally constructed by the framework for you and resides in a module named Program.cs. The last thing it does is start your form running. You probably do have it already.

Now as far as making the game play, I see where your form calls InitializeComponent, so if the rest of the game is totally event-driven, you should be good. But I only see one click handler for the grid so I assume you still have a bit of code to write. And you might want to take a look at your nested loops in resetGame, I could not quite understand what they should do!

That's about all I can tell at this time. There's several modules not shown here, so it's not possible to construct the game and try it out. For sharing purposes you might consider uploading your complete project to a github repo so you can share the link.

Steven Parker
Steven Parker
231,269 Points

I think you overlooked some of my previous comments.

Remember I told you that all the checks for "O" to win are inside the last test for "X" to win. That's why "O" cannot win — those checks are never made unless "X" has already won (in a specific way). This might be easier to see if you reformat the indentations (EDIT :arrow_right: ADVANCED :arrow_right: FORMAT DOCUMENT) and eliminate some of the blank lines.

Then in my suggested replacement for the last part of gameOver I had re-arranged your code but still used your test of numClicks to determine a tie, but your new code uses a completely new method and now a win for "X" might be called a tie and a real tie might not be detected.

Now in the resetGame code you declare local variables for grid and game, so the remaining code deals with those and the global ones remain unchanged. You also never clear the value in winner. And the final section of that function has a calculation in a loop and I'm unsure of the intention ... here it is with inline comments:

            int row, col;
            for (row = 1; row <= 3; row++)                // from 1 to 3 instead of 0 to 2?
            {
                for (col = 2; col <= (row / col); col++)  // col will always be larger than row/col
                {
                    grid[row, col].Text = " ";            // a space makes the cell an invalid move
                    game[row, col] = ' ';
                }
            }
Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

I have a GitHub account. I am trying to figure out how to push the project to it (I haven't done it in awhile.) I'll keep you posted.

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

I made some progress on my own today. I now just have a logic error to fix. The program makes Os and Xs. I can't remember how to push to Git but I will try to do that when I re-remember it. Thanks. I think this request was a little obnoxious on my part. Thanks for helping me.

Steven Parker
Steven Parker
231,269 Points

I'll take a look when you get it uploaded.

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

https://github.com/drnanjo/TTT

It's a zip file.

It loads now. I have a logic issue with the game play, and I should probably turn the code that clears the labels at the end into a for loop instead of the hideous repetition it now features (resetgame)

thanks for your willingness to help me. NJM

Steven Parker
Steven Parker
231,269 Points

The logic issue now is win recognition, right?

First, there's a stray semicolon on line 113. And it appears that all the checks for "O" to win are inside the last test for "X" to win. I'm guessing that's probably just a missing brace on line 127.

Then down below the win pattern testing (line 156 on) things look a bit more confused (shown here with blank lines removed):

Form1.cs
                else {
                    return false;
                    if (numClicks == 9) { isDone = true; }
                    lblStatus.Text = "The game ends in a tie.";
                }
                lblStatus.Text = "The winner is " + winner;
            } return isDone;

I'm not sure what that else is for, and you probably didn't mean to put code after a return statement. Also, I think you need to check for a win before you check for the tie. Perhaps something like this:

            if (isDone) {
                lblStatus.Text = "The winner is " + winner;
            }
            else if (numClicks == 9) {
                isDone = true;
                lblStatus.Text = "The game ends in a tie.";
            }
            return isDone;

Hopefully that will get you back on track and you can take it from here.

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

If you are still around, I've revised the code. I still have two problems:

X can win and there can be ties BUT O cannot win and the game doesn't fully reset (the first X placed triggers X wins so apparently the last game isn't actualy ended.)

Here's the repository address. I have something I can hand it for partial credit but I would really like to make it run correctly.

https://github.com/drnanjo/tictactoefriday

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

OK...thanks. I guess that was a little dense of me. I'll keep working on it. Thanks for these suggestions... NJM

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

"Remember I told you that all the checks for "O" to win are inside the last test for "X" to win. That's why "O" cannot win — those checks are never made unless "X" has already won (in a specific way). This might be easier to see if you reformat the indentations (EDIT :arrow_right: ADVANCED :arrow_right: FORMAT DOCUMENT) and eliminate some of the blank lines."

Should I be alternating the tests for lines will all Xs and Os? Just trying to make sure I understand. To paraphrase our fearless leader "Who could have known [TicTacToe] was so complicated?"

NJM

Steven Parker
Steven Parker
231,269 Points

I think interleaving tests would make the code harder to read, and harder to refactor if you ever wanted to reduce the code size by creating something like a checkWin(player) function.

Just make sure all the tests are sequential and not nested. As a visual indicator, after reformatting, all the if's should appear in the same column. Right now all the "O" tests will be indented further because they are inside the if block of the last "X" test.

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

I fixed the X wins problem, and now X wins in all ways not just the left right diagonal. I still cannot make O win. I have tried so many ways to rearrange the code. Here is my latest gameOver(); Any hint would be appreciated. Thanks.

   public void gameOver()

        {


            if ((game[0, 2] == 'O') && (game[0, 1] == 'O') && (game[0, 0] == 'O')
            || (game[0, 0] == 'O') && (game[0, 1] == 'O') && (game[0, 2] == 'O')
            || (game[0, 0] == 'O') && (game[1, 1] == 'O') && (game[2, 2] == 'O')
            || (game[1, 0] == 'O') && (game[1, 1] == 'O') && (game[1, 2] == 'O')
            || (game[2, 0] == 'O') && (game[2, 1] == 'O') && (game[2, 2] == 'O')
            || (game[0, 0] == 'O') && (game[1, 0] == 'O') && (game[2, 0] == 'O')
            || (game[0, 1] == 'O') && (game[1, 1] == 'O') && (game[1, 2] == 'O')
            || (game[0, 2] == 'O') && (game[1, 2] == 'O') && (game[2, 2] == 'O'))
            {
                isDone = true; winner = 'O';
                lblStatus.Text = "O wins!";

            }

            if ((game[0, 0] == 'X') && (game[1, 1] == 'X') && (game[2, 2] == 'X')
            || (game[0, 2] == 'X') && (game[1, 1] == 'X') && (game[2, 0] == 'X')
            || (game[0, 0] == 'X') && (game[0, 1] == 'X') && (game[0, 2] == 'X')
            || (game[1, 0] == 'X') && (game[1, 1] == 'X') && (game[1, 2] == 'X')
            || (game[2, 0] == 'X') && (game[2, 1] == 'X') && (game[2, 2] == 'X')
            || (game[0, 0] == 'X') && (game[1, 0] == 'X') && (game[2, 0] == 'X')
            || (game[0, 1] == 'X') && (game[1, 1] == 'X') && (game[1, 2] == 'X')
            || (game[0, 2] == 'X') && (game[1, 2] == 'X') && (game[2, 2] == 'X'))
            {



                isDone = true;
                winner = 'X';
                lblStatus.Text = "X wins!";




            }





            else if (numClicks == 9)
            {
                isDone = true;
                winner = 'T';
                lblStatus.Text = "It's a tie!";



            }



        }
Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

I was wrong and I deleted that post about the instructor. He supplied label1_Click which works just fine. I am feeling super dim. As I mentioned, I fixed the problem where X wins the game and then wins by placing one X on the next game. What I cannot fix is the problem where O can't win. I un-nested the code for gameover (above) so that it's a series of OR statements with an if, an else if, and another else if. But that still doesn't fix it. I tried putting O first (above) and that doesn't fix it. So I am stumped.

I understand not telling me the answer is good for me (really) but if you might drop a hint so I know what to look at to solve this issue. Thanks again.

Steven Parker
Steven Parker
231,269 Points

Offhand that looks pretty good, and I like how you combined the pattern tests into one. I'm not sure why that wouldn't work. Be sure to update your repo and I'll try building it again after the weekend.

But you still have those swapped values in the last cell of the 7th win pattern (for both sides).

Nancy Melucci
PLUS
Nancy Melucci
Courses Plus Student 36,143 Points

Thanks. I'll upload it soon. I would like it to work. regardless of the grade it earns.

Nancy M.

Steven Parker
Steven Parker
231,269 Points

You didn't "say when", but I noticed a newer download "TicTacToeFinal.zip" and tried it. "O" does win for me, except for down the middle column ("X" can't win that way either). That's because you still have those swapped values I've been talking about.

But either "X" or "O" can win by marking the top-middle, right-middle, and center boxes: :open_mouth:

O wins!
+-----+
|X|O|X|
|-+-+-|
| |O|O|
|-+-+-|
| | |X|
+-----+