I am trying to make the tic tac toe game in C# Windows Forms using the minimax algorithm as the opponent. So instead of making the best move, like preventing the player from winning or playing a move that allows it to get closer to winning, it moves to the following empty index on the board. So how could I fix the algorithm?
int evaluate(int[] grid)
{
for(int i = 0; i < 9; i += 3)
{
if (grid[i] == 0) continue;
if (grid[i] == grid[i + 1] && grid [i] == grid[i + 2])
return grid[i]==1 ? 10 :-10;
}
for (int i = 0; i < 3; i++)
{
if (grid[i] == 0) continue;
if (grid[i] == grid[i + 3] && grid[i] == grid[i + 6])
return grid[i] == 1 ? 10 : -10;
}
if ((grid[0] == grid[4] && grid[4] == grid[8]) || (grid[2] == grid[4] && grid[4] == grid[6]))
return grid[4] == 1 ? 10 : -10;
return 0;
}
bool isMovesLeft(int[] grid)
{
for(int i = 0; i< grid.Length; i++)
{
if (grid[i] == 0) return true;
}
return false;
}
int miniMax(int[] grid,int depth, bool isMax)
{
int isWon = evaluate(grid);
if (isWon == 10 || isWon == -10)
return isWon;
if(!isMovesLeft(grid))
return 0;
if (isMax)
{
int best = int.MinValue;
for(int i = 0;i< grid.Length;i++)
{
if (grid[i] == 0)
{
grid[i] = 1;
best = Math.Max(best,miniMax(grid, depth+1, !isMax));
grid[i] = 0;
}
}
return best;
}
else
{
int best = int.MaxValue;
for (int i = 0; i < grid.Length; i++)
{
if (grid[i] == 0)
{
grid[i] = 2;
best = Math.Min(best, miniMax(grid, depth+1, !isMax));
grid[i] = 0;
}
}
return best;
}
}
void moveByAI()
{
int best = int.MinValue;
int move = -1;
for(int i =0; i<9;i++)
{
if (grids[i]==0)
{
grids[i] = 2;
int locValue = miniMax(grids, 0, true);
grids[i] = 0;
if(locValue > best)
{
move = i;
best = locValue;
MessageBox.Show(""+i);
}
}
}
buttons[move].PerformClick();
}
Related
I've been trying to implement minimax algorithm in my C# chess engine for a week now and it makes legal moves but not meaningful moves. I cannot find the error, hopefully someone can spot it. I have tried to isolate the problem by testing each method and they all seem to work correctly except minimax.
public enum Piece
{
Empty, Pawn_W, Pawn_B, Knight_W, Knight_B,
Bishop_W, Bishop_B, Rook_W, Rook_B,
Queen_W, Queen_B, King_W, King_B
}
public bool IsPieceWhite(Piece piece)
{
if (piece == Piece.Pawn_W || piece == Piece.Knight_W ||
piece == Piece.Bishop_W || piece == Piece.Rook_W ||
piece == Piece.Queen_W || piece == Piece.King_W)
return true;
else return false;
}
public bool IsPieceBlack(Piece piece)
{
if (piece == Piece.Pawn_B || piece == Piece.Knight_B ||
piece == Piece.Bishop_B || piece == Piece.Rook_B ||
piece == Piece.Queen_B || piece == Piece.King_B)
return true;
else return false;
}
public int GetPieceWorth(Piece piece)
{
if (piece == Piece.Pawn_W || piece == Piece.Pawn_B)
return 1;
if (piece == Piece.Knight_W || piece == Piece.Knight_B)
return 3;
if (piece == Piece.Bishop_W || piece == Piece.Bishop_B)
return 3;
if (piece == Piece.Rook_W || piece == Piece.Rook_B)
return 5;
if (piece == Piece.Queen_W || piece == Piece.Queen_B)
return 9;
if (piece == Piece.King_W || piece == Piece.King_B)
return 9999999;
return 0;
}
Piece[,] CurrentBoard = GetStartingBoard();
Piece[,] bestMove;
public int depthB = 3;
public double minimax(Piece[,] board, int depth, bool maximizingPlayer)
{
if (depth == 0)
{
double result = EvaluatePosition(board, maximizingPlayer);
return result;
}
if (maximizingPlayer)
{
double best = Double.MinValue;
double value = Double.MinValue;
foreach (var move in GenerateMoves(board, maximizingPlayer))
{
Piece[,] clonedMove = CloneBoard(move);
value = Math.Max(value, minimax(clonedMove, depth - 1, false));
if (depth == depthB && value >= best)
{
best = value;
bestMove = clonedMove;
}
}
return value;
}
else
{
double best = Double.MaxValue;
double value = Double.MaxValue;
foreach (var move in GenerateMoves(board, maximizingPlayer))
{
Piece[,] clonedMove = CloneBoard(move);
value = Math.Min(value, minimax(clonedMove, depth - 1, true));
if (depth == depthB && value <= best)
{
best = value;
bestMove = clonedMove;
}
}
return value;
}
}
public Piece[,] CloneBoard(Piece[,] boardPos)
{
Piece[,] copy = boardPos.Clone() as Piece[,];
return copy;
}
public double EvaluatePosition(Piece[,] boardPos, bool ForWhite)
{
double eval = 0;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if (boardPos[i, j] != Piece.Empty)
{
if (IsPieceWhite(boardPos[i, j]))
{
eval += GetPieceWorth(boardPos[i, j]);
}
else if (IsPieceBlack(boardPos[i, j]))
{
eval -= GetPieceWorth(boardPos[i, j]);
}
}
}
}
if (ForWhite)
return eval;
else
return eval * -1;
}
//a-h,0-7
//Piece[,] board = new Piece[8, 8];
public static Piece[,] GetStartingBoard()
{
Piece[,] board = new Piece[8, 8];
for (int i = 0; i < 8; i++)
{
//initiate pawns
board[1, i] = Piece.Pawn_W;
board[6, i] = Piece.Pawn_B;
}
//white pieces
board[0, 0] = Piece.Rook_W;
board[0, 1] = Piece.Knight_W;
board[0, 2] = Piece.Bishop_W;
board[0, 3] = Piece.Queen_W;
board[0, 4] = Piece.King_W;
board[0, 5] = Piece.Bishop_W;
board[0, 6] = Piece.Knight_W;
board[0, 7] = Piece.Rook_W;
//black pieces
board[7, 0] = Piece.Rook_B;
board[7, 1] = Piece.Knight_B;
board[7, 2] = Piece.Bishop_B;
board[7, 3] = Piece.Queen_B;
board[7, 4] = Piece.King_B;
board[7, 5] = Piece.Bishop_B;
board[7, 6] = Piece.Knight_B;
board[7, 7] = Piece.Rook_B;
//test
//board[1, 4] = Piece.Pawn_B;
//board[6, 2] = Piece.Pawn_W;
return board;
}
I have uploaded a short clip of the engine playing against itself, to show the wierd moves: https://www.youtube.com/watch?v=A0HVgXYSciY
Finally was able to make the minimax function work. Thanks for all the help!
Working method:
public int minimax(Piece[,] board, int depth, bool maximizingPlayer, bool WhiteToPlay)
{
if (depth == 0)
{
int result = EvaluatePosition(board, WhiteToPlay);
return result;
}
var moves = GenerateMoves(board, WhiteToPlay);
if (maximizingPlayer)
{
int value = int.MinValue;
foreach (var move in moves)
{
int minmaxResult = minimax(move, depth - 1, false, !WhiteToPlay);
value = Math.Max(value, minmaxResult);
if (depth == depthB)
{
moveScores.Add(move, minmaxResult);
}
}
return value;
}
else
{
int value = int.MaxValue;
foreach (var move in moves)
{
int minmaxResult = minimax(move, depth - 1, true, !WhiteToPlay);
value = Math.Min(value, minmaxResult);
if (depth == depthB)
{
moveScores.Add(move, minmaxResult);
}
}
return value;
}
}
I've got two algorithms converting random 2d arrays (m х n or m х m) to 1d array. I'm wondering if there is a way to make them work als in the opposite direction and convert the result to 1d array saving the order of numbers. Here is the full code of my program and a picture to see how both of my algorithms work.enter image description here
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using static System.Math;
namespace MyProgram
{
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter number of rows:");
int n = int.Parse(Console.ReadLine());
Console.Write("Enter number of columns:");
int m = int.Parse(Console.ReadLine());
int[] arr1 = new int[n * m];
int[,] arr2 = new int[n, m];
int choice;
do
{
Console.WriteLine("Select option:");
Console.WriteLine("\t1: Diagonal");
Console.WriteLine("\t2: Spiral");
Console.WriteLine("\t3: Exit");
Console.Write("Your selection: ");
choice = int.Parse(Console.ReadLine());
switch (choice)
{
case 1:
{
SetArray(arr2);
PrintArray(arr2);
Diagonal(arr2, arr1);
PrintArray(arr1);
break;
}
case 2:
{
SetArray(arr2);
PrintArray(arr2);
Spiral(arr2, arr1);
PrintArray(arr1);
break;
}
}
Console.WriteLine();
Console.WriteLine();
} while (choice != 5);
}
static void Diagonal(int[,] array2, int[] array1)
{
int k = 0;
int row = 0;
int col = 0;
while (k < array1.Length)
{
array1[k] = array2[row, col];
if ((row + col) % 2 == 0)
{
if ((row == 0) && (col != array2.GetLength(1) - 1)) { col++; }
else
{
if (col == array2.GetLength(1) - 1) { row++; }
else { row--; col++; }
}
}
else
{
if ((col == 0) && (row != array2.GetLength(0) - 1)) { row++; }
else
{
if (row == array2.GetLength(0) - 1) { col++; }
else { row++; col--; }
}
}
k += 1;
}
}
private static void Spiral(int[,] array2, int[] array1)
{
int lengthX = array2.GetLength(0);
int lengthY = array2.GetLength(1);
int Product = lengthX * lengthY;
int CorrectY = 0;
int CorrectX = 0;
int Count = 0;
while (lengthX > 0 && lengthY > 0)
{
for (int j = CorrectY; j < lengthY && Count < Product; j++)
{
array1[Count] = array2[CorrectX, j];
Count++ ;
}
CorrectX++;
for (int i = CorrectX; i < lengthX && Count < Product; i++)
{
array1[Count] = array2[i, lengthY - 1];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthY-- ;
else break;
for (int j = lengthY - 1; j >= CorrectY && Count < Product; j--)
{
array1[Count] = array2[lengthX - 1, j];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthX-- ;
else break;
for (int i = lengthX - 1; i >= CorrectX && Count < Product; i--)
{
array1[Count] = array2[i, CorrectY];
Count++ ;
}
CorrectY++;
}
}
public static void SetArray(int[,] arr)
{
Random r = new Random();
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr[i, j] = r.Next(11, 99);
}
}
}
public static void SetArray(int[] arr)
{
Random r = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr[i] = r.Next(11, 99);
}
}
public static void PrintArray(int[] arr)
{
Console.Write("print 1d array:");
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + " ");
}
Console.WriteLine();
}
public static void PrintArray(int[,] arr)
{
Console.WriteLine("print 2d array:");
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.Write(arr[i, j] + " ");
}
Console.WriteLine();
}
}
}
}
Actually what you are asking is quite easy. Just change your algorithm methods to receive int rows, int cols and delegate like this
delegate void Apply(int row, int col, int index);
Then replace arr2.GetLength(0) with rows, arr2.GetLength(1) with cols, and array element assignments with delegate call.
Here is the updated Diagonal method (you can do the same with the other):
static void Diagonal(int rows, int cols, Apply action)
{
int k = 0;
int row = 0;
int col = 0;
int length = rows * cols;
while (k < length)
{
action(row, col, k);
if ((row + col) % 2 == 0)
{
if ((row == 0) && (col != cols - 1)) { col++; }
else
{
if (col == cols - 1) { row++; }
else { row--; col++; }
}
}
else
{
if ((col == 0) && (row != rows - 1)) { row++; }
else
{
if (row == rows - 1) { col++; }
else { row++; col--; }
}
}
k += 1;
}
}
and the usage:
SetArray(arr2);
PrintArray(arr2);
Diagonal(n, m, (r, c, i) => arr1[i] = arr2[r, c]);
PrintArray(arr1);
// Inverse
var arr3 = new int[n, m];
Diagonal(n, m, (r, c, i) => arr3[r, c] = arr1[i]);
PrintArray(arr3);
This seems to be working for me for backward Diagonal:
static void BackwardDiagonal(int[,] array2, int[] array1) {
int k = 0;
int row = 0;
int col = 0;
while (k < array1.Length) {
array2[row, col] = array1[k]; // just swap sides of the assignment...
if ((row + col) % 2 == 0) {
if ((row == 0) && (col != array2.GetLength(1) - 1)) { col++; } else {
if (col == array2.GetLength(1) - 1) { row++; } else { row--; col++; }
}
} else {
if ((col == 0) && (row != array2.GetLength(0) - 1)) { row++; } else {
if (row == array2.GetLength(0) - 1) { col++; } else { row++; col--; }
}
}
k += 1;
}
}
For backward Spiral:
private static void BackwardSpiral(int[,] array2, int[] array1)
{
int lengthX = array2.GetLength(0);
int lengthY = array2.GetLength(1);
int Product = lengthX * lengthY;
int CorrectY = 0;
int CorrectX = 0;
int Count = 0;
while (lengthX > 0 && lengthY > 0)
{
for (int j = CorrectY; j < lengthY && Count < Product; j++)
{
array2[CorrectX, j] = array1[Count]; // just swap sides of the assignment...
Count++ ;
}
CorrectX++;
for (int i = CorrectX; i < lengthX && Count < Product; i++)
{
array2[i, lengthY - 1] = array1[Count];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthY-- ;
else break;
for (int j = lengthY - 1; j >= CorrectY && Count < Product; j--)
{
array2[lengthX - 1, j] = array1[Count];
Count++ ;
}
if (lengthY > 0 && lengthX > 0) lengthX-- ;
else break;
for (int i = lengthX - 1; i >= CorrectX && Count < Product; i--)
{
array2[i, CorrectY] = array1[Count];
Count++ ;
}
CorrectY++;
}
}
I also added this to the switch statement to implement it:
case 4:
{
SetArray(arr2);
PrintArray(arr2);
Diagonal(arr2, arr1);
PrintArray(arr1);
int[,] arr3 = new int[n, m]; // new blank array to fill with arr1
BackwardDiagonal(arr3, arr1); // fill arr3 from backward Diagonal algorithm
PrintArray(arr3);
break;
}
case 5:
{
SetArray(arr2);
PrintArray(arr2);
Spiral(arr2, arr1);
PrintArray(arr1);
int[,] arr3 = new int[n, m]; // new blank array to fill with arr1
BackwardSpiral(arr3, arr1); // fill arr3 from backward Spiral algorithm
PrintArray(arr3);
break;
}
While you're at it, also make sure to have } while (choice != 3); at the end of your do loop so that you can exit the program!
This is my code for the back tracking logic.
private void backtrackLogic()
{
if (m == 0 && n != 0)
{
n--;
m = 8;
if(sudokuArray[n, m] == 0)
{
counter = copyArray[n, m];
copyArray[n, m] = 0;
if(counter == 9)
{
backtrackLogic();
}
}
else
{
backtrackLogic();
}
}
else if (m != 0)
{
m--;
if (sudokuArray[n, m] == 0)
{
counter = copyArray[n, m];
copyArray[n, m] = 0;
if (counter == 9)
{
backtrackLogic();
}
}
else
{
backtrackLogic();
}
}
else
{
Environment.Exit(0);
}
}
This is my code for the rest of the algorithm.
private void SolveButton_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
copyArray[i, j] = sudokuArray[i, j];
Console.Write(sudokuArray[i, j]);
}
}
counter = 1;
bool noOptions = false;
for (n = 0; n < 9; n++)
{
for (m = 0; m < 9; m++)
{
for (counter = 1; counter < 10; counter++)
{
if (sudokuArray[n, m] == 0)
{
if (checkRow(n, m, counter) && checkColumn(n, m, counter) && checkBox(n, m, counter))
{
copyArray[n, m] = counter;
printTextBox(n, m, counter);
Console.Write(counter);
break;
}
else if (counter == 9)
{
noOptions = true;
}
}
if (noOptions)
{
backtrackLogic();
noOptions = false;
}
}
}
}
for (int n = 0; n < 9; n++)
{
for (int m = 0; m < 9; m++)
{
Console.Write(copyArray[n, m]);
}
}
}
When running this code on difficult Sudoku problems, the program times out because of how long it takes to execute. Any help in the execution of the algorithm would be very helpful!
Currently, I am doing a log analyzer for my personal project.
My issue here is that I am new to c# and I have an performance issue with my tool.
Everytime the device(iOS) is interacted, I get an output syslog from a library and it comes in to the output handler.
public void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine, iosSyslogger form, string uuid)
{
string currentPath = System.Environment.CurrentDirectory;
bool exit = false;
if (exit == true) return;
try
{
form.BeginInvoke(new Action(() =>
{
form.insertLogText = outLine.Data;
}));
using (System.IO.StreamWriter file = new System.IO.StreamWriter(currentPath + #"\syslog" + uuid + ".txt", true))
{
file.WriteLine(outLine.Data);
}
}
catch
{
return ;
}
//*Most of the logic for outputing the log should be dealt from this output Handler
}
Then, I write the outline.Data to Data grid view. My concern is that I need to be able to search and filter through data gridview.
Curently I am using visibility = false for search filtering ( if the row does not match the given filter specification I set the row to visibility =false)
This requires the program to traverse the entire datagridview to check whether the condition is met.
Will there be any better way to filter and search within ?
(When I have thousands of lines of row, it takes at least 20 seconds to process it)
Below is the code for filtering, and searching through the results function.
private void searchResult(string term)
{
if (term != null)
{
int i = 0;
while (i < dataGridView1.Rows.Count - 1)
{
if (dataGridView1.Rows[i].Cells[3] == null)
{
i++;
continue;
}
if (dataGridView1.Rows[i].Visible == false)
{
i++;
continue;
}
else if (dataGridView1.Rows[i].Cells[2].Value.ToString().Contains(term) || dataGridView1.Rows[i].Cells[3].Value.ToString().Contains(term) || dataGridView1.Rows[i].Cells[4].Value.ToString().Contains(term))
{
string multirow = dataGridView1.Rows[i].Cells[5].Value.ToString();
int count = Convert.ToInt32(multirow);
if (count > 0)
{
int z = 0;
for (z = 0; z <= count; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
i = i + z;
}
else
{
dataGridView1.Rows[i].Visible = true;
i++;
}
}
else
{
dataGridView1.Rows[i].Visible = false;
i++;
}
}
}
}
public filteringThelist(){
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
dataGridView1.Rows[i].Visible = false;
int count1,count2,count3=0;
count1 = 1;
count2 = 1;
count3 = 1;
int z = 0;
foreach (KeyValuePair<string, string> entry in totalSelected)
{
if (entry.Value == "devicename" && dataGridView1.Rows[i].Cells[1].Value != null)
{
if (dataGridView1.Rows[i].Cells[1].Value.ToString().Trim().Equals(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
}
else if (devicename.CheckedItems.Count > 1&&count1!= devicename.CheckedItems.Count)
{
count1++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
else if (entry.Value == "process" && dataGridView1.Rows[i].Cells[2].Value != null)
{
if (dataGridView1.Rows[i].Cells[2].Value.ToString().Trim().Equals(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
}
else if (processlistname.CheckedItems.Count > 1 && count2 != processlistname.CheckedItems.Count)
{
count2++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
else if (entry.Value == "loglevel" && dataGridView1.Rows[i].Cells[3].Value != null)
{
if (dataGridView1.Rows[i].Cells[3].Value.ToString().Trim().Contains(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
continue;
}
else if (loglevelCheckBox.CheckedItems.Count > 1 && count3 != loglevelCheckBox.CheckedItems.Count)
{
count3++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
// do something with entry.Value or entry.Key
}
string multirow = dataGridView1.Rows[i].Cells[5].Value.ToString();
int count = Convert.ToInt32(multirow);
if (count > 0&& dataGridView1.Rows[i].Visible==false)
{
for (int k = 0; k <= count; k++)
{
dataGridView1.Rows[i + k].Visible = false;
}
}
i = i + z;
}
The performance problem is because your DataGridView is redrawing at each modification.
Don't fill the DataGridView directly from your Data. Rather create a DataTable and bind it to DataGridView with a BindingSource.
Then use the "Filter" property of the binding source to view extracts of dataTable in the DataGridView. The "Filter" property is a string whose content is similar to that of a WHERE SQL clause.
I have a tic tac toe program with a re-sizable grid. I have a CheckXWinner( ) function that checks for a horizonal, vertical, and both diagonal winning combos in the grid. The win check works great but after a certain combo has won, I need to highlight those winning buttons by turning them a different color, I'd say IndiaRed, and preferably drawing a line through them. I'd be happy with at least getting them turned red though.
public void CheckXWinner(Button[] buttonArray)
{
int arrLength = buttonArray.Length;
int hCount = 0;
int vCount = 0;
int d1Count = 0;
int d2Count = 0;
int root = (int)Math.Sqrt(Convert.ToDouble(arrLength));
for (int i = 0; i < root; i++)
{
//Sets the counter for the winners back to zero
d2Count = 0;
d1Count = 0;
hCount = 0;
vCount = 0;
for(int j = 0; j < root; j++)
{
//increments the appropriate counter if the button contains an X
if (buttonArray[ (i * root) + j ].Text == "X")
hCount++;
if (buttonArray[ j + (j * root)].Text == "X")
d1Count++;
if (buttonArray[(j * (root - 1)) + (root - 1)].Text == "X")
d2Count++;
if (buttonArray[ i + (root * j)].Text == "X")
vCount++;
}
//if the counter reaches the amount needed for a win, show win message
if ( hCount == root )
{
MessageBox.Show("Horizontal winner found !");
break;
}
else if ( vCount == root )
{
MessageBox.Show("Virtical winner found !");
break;
}
else if ( d1Count == root )
{
MessageBox.Show("Diagonal winner found !");
break;
}
else if (d2Count == root)
{
MessageBox.Show("Diagonal winner #2 found !");
break;
}
}//end of for loop
}//end of CheckXWinner
Once I have a winning count reached, how can i then go back and change the .backcolor properties of those buttons to IndiaRed?
I solved it like this:
public void CheckXWinner(Button[] buttonArray)
{
int arrLength = buttonArray.Length;
int root = (int)Math.Sqrt(Convert.ToDouble(arrLength));
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();
}
}//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();
}
}//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();
}
}//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();
}
}//end of vert win
}//end of for j loop
}//end of for loop
}//end of CheckXWinner