In part 2, we created the computer role in the Tic Tac Toe game, but as a dumb.
So now we are going to program the smart playing algorithm in C#.
We will consider two main points in the algorithm:
- Do we have a winning play? if yes lets play it and win! No? proceed to step 2.
- Check if the opponent has a winning move, block it if yes, continue to step 3 if no.
- Play like our old friend from part 2, yes it's the dumb.
HELPER METHODS
the NormalPCWrite method is not that easy, so we are going to create four helper methods.Get Coordinates
private void getCoordinates(int p, out int x, out int y) {//change the variables x and y to the correct coordinate switch (p) { case 1: x = 0; y = 0; break; case 2: x = 0; y = 1; break; case 3: x = 0; y = 2; break; case 4: x = 1; y = 0; break; case 5: x = 1; y = 1; break; case 6: x = 1; y = 2; break; case 7: x = 2; y = 0; break; case 8: x = 2; y = 1; break; default: x = 2; y = 2; break; } }
Clicked (+1 overload)
private bool clicked(int index) {//true if it was clicked, false if it's still clickable return (ButtonsIndexs.IndexOf(index.ToString()) == -1); } private bool clicked(int index,string p) {//checks if "p" is written on the button with index "index" int a,b; switch(index){ case 1:a=0;b=0;break; case 2:a=0;b=1;break; case 3:a=0;b=2;break; case 4:a=1;b=0;break; case 5:a=1;b=1;break; case 6:a=1;b=2;break; case 7:a=2;b=0;break; case 8:a=2;b=1;break; default:a=2;b=2;break; } if (p == "X") return (X[a, b]); return (O[a, b]); }
Write_buttonIndex
private void Write_buttonIndex(int index, string toWrite) {//Writing 'toWrite' in a button by knowing its index p switch (index) { case 1: Write(toWrite, button1); break; case 2: Write(toWrite, button2); break; case 3: Write(toWrite, button3); break; case 4: Write(toWrite, button4); break; case 5: Write(toWrite, button5); break; case 6: Write(toWrite, button6); break; case 7: Write(toWrite, button7); break; case 8: Write(toWrite, button8); break; default: Write(toWrite, button9); break; } }
check
private bool check(int i, int k, string toCheck,string toWrite) { //k=1 for rows, k=3 for columns, k=5-i for diagonals string P = (toWrite == "X") ? "O" : "X"; if ((clicked(i,toCheck) && clicked(i+k,toCheck) && !clicked(i + k + k))) { getCoordinates(i + k + k, out x, out y); Write_buttonIndex(i + k + k, toWrite); return true; } if ((clicked(i,toCheck) && clicked(i+k+k,toCheck) && !clicked(i + k))) { getCoordinates(i + k, out x, out y); Write_buttonIndex(i + k, toWrite); return true; } if ((clicked(i+k,toCheck) && clicked(i+k+k,toCheck) && !clicked(i))) { getCoordinates(i, out x, out y); Write_buttonIndex(i, toWrite); return true; } return false; }
Please read the helper methods carefully to understand well how they work. Now Finally lets write the NormalPCWrite method!
Normal level method
private void NormalPCWrite(string p) { string q = (p == "X") ? "O" : "X"; //Lets check if we can win if (!check(1, 1, p, p)) if (!check(4, 1, p, p)) if (!check(7, 1, p, p)) if (!check(1, 3, p, p)) if (!check(2, 3, p, p)) if (!check(3, 3, p, p)) if (!check(1, 4, p, p)) if (!check(3, 2, p, p)) if (!check(1, 1, q, p)) //It seems that we can't, let's defend if (!check(4, 1, q, p)) if (!check(7, 1, q, p)) if (!check(1, 3, q, p)) if (!check(2, 3, q, p)) if (!check(3, 3, q, p)) if (!check(1, 4, q, p)) if(!check(3, 2, q, p)) //play randomly EasyPCWrite(p); }
Note: this is not the best playing, as we can create a more smarter algorithm, which will avoid and even try to create TRAPS. Maybe you can do it? try to add one more difficulty, the Unbeatable.
For the best performance, please edit some of our previously created methods.
EDIT: resetVars()
private void resetVars() { ButtonsIndexs = "123456789"; finished = false; rnd = new Random(); O = new bool[3, 3]; X = new bool[3, 3]; }
EDIT: Form3_Load()
private void Form3_Load(object sender, EventArgs e) { difficulity = 0; resetVars(); }
EDIT: back_Click()
private void back_Click(object sender, EventArgs e) { if (difficulity == 0) easyRB.Checked = true; else normalRB.Checked = true; playAgainButton.PerformClick(); xLabel.Text = oLabel.Text = "0"; tableLayoutPanel1.Visible = false; this.Size = new Size(229, 300); }If you are working with me, you probably noticed while debugging, that if you click the close button (X) of the form, the debugger doesn't stop.
That's because you are closing a single form, while previous ones are hidden.
To solve this and to end the application process when the user click the (X) button, go to each form, look for an event called Form closing. double click it and add this line of code:
Application.Exit();Finally we are done! I wish you enjoyed this tutorial, go play some Tic Tac Toe now ;) see you later..