views:

733

answers:

3

What would be the best way to see (in a 2 player) game of Tic Tac Toe who won? Right now I'm using something similar to the following:

if (btnOne.Text == "X" && btnTwo.Text == "X" && btnThree.Text == "X")
{
    MessageBox.Show("X has won!", "X won!");
    return;
}
else
// I'm not going to write the rest but it's really just a bunch
// if statements.

So how do I get rid of the multiple if's?

+8  A: 

Something alongs:

rowSum == 3 || columnSum == 3 || diagnolSum == 3

.. ?

chakrit
Very mathy, I like it!
Lucas McCoy
Nice update, I think I may go with this method but I'll leave the question unanswered to see if anyone else can come up with something better (we gotta let 'em have a chance, right?).
Lucas McCoy
Extracted into another answer post.
chakrit
+1  A: 

Another simple way out would be to save the winnable positions as a data in an array and use a loop to check all possible winning conditions instead of multiple ifs statements

// winnable positions
var winnables = new[] {
    "012",
    "345",
    "678",
    "036",
    "147",
    "258",
    "048",
    "246"
};

// extracted from btnOne Two Three....
var gameState = new[] { "X", "O", "X", "whatever" };


string winner = null;

// check each winnable positions
foreach (var position in winnables) {

    var pos1 = int.Parse(position[0].ToString());
    var pos2 = int.Parse(position[1].ToString());
    var pos3 = int.Parse(position[2].ToString());

    if (gameState[pos1] == gameState[pos2] &&
        gameState[pos2] == gameState[pos3])
        winner = gameState[pos1];

}

// do we have a winner?
if (!string.IsNullOrEmpty(winner))
    /* we've got a winner */

Basically, don't use btnOne btnTwo btnThree, use a proper array of Buttons or an array that saves the game state in a more accessible format and it'll be easier to compute.

chakrit
The int.Parse is a little ugly though... but it helps keeps the winnable position easy to read.
chakrit
Well it really dosen't matter if it's 'ugly' because me and my friends are the only people who will ever use this.
Lucas McCoy
+1  A: 

If you store your buttons in a multidimenstional array, you can write some extension methods to get the rows, columns and diagonals.

public static class MultiDimensionalArrayExtensions
{
  public static IEnumerable<T> Row<T>(this T[,] array, int row)
  {
    var columnLower = array.GetLowerBound(1);
    var columnUpper = array.GetUpperBound(1);

    for (int i = columnLower; i <= columnUpper; i++)
    {
      yield return array[row, i];
    }
  }

  public static IEnumerable<T> Column<T>(this T[,] array, int column)
  {
    var rowLower = array.GetLowerBound(0);
    var rowUpper = array.GetUpperBound(0);

    for (int i = rowLower; i <= rowUpper; i++)
    {
      yield return array[i, column];
    }
  }

  public static IEnumerable<T> Diagonal<T>(this T[,] array,
                                           DiagonalDirection direction)
  {
    var rowLower = array.GetLowerBound(0);
    var rowUpper = array.GetUpperBound(0);
    var columnLower = array.GetLowerBound(1);
    var columnUpper = array.GetUpperBound(1);

    for (int row = rowLower, column = columnLower;
         row <= rowUpper && column <= columnUpper;
         row++, column++)
   {
      int realColumn = column;
      if (direction == DiagonalDirection.DownLeft)
        realColumn = columnUpper - columnLower - column;

      yield return array[row, realColumn];
    }
  }

  public enum DiagonalDirection
  {
    DownRight,
    DownLeft
  }
}

And if you use a TableLayoutPanel with 3 rows and 3 columns, you can easily create your buttons programmably and store it into a Button[3, 3] array.

Button[,] gameButtons = new Button[3, 3];

for (int row = 0; column <= 3; row++)
  for (int column = 0; column <= 3; column++)
  {
    Button button = new Button();
    // button...
    gameLayoutPanel.Items.Add(button);
    gameButtons[row, column] = button;
  }

And to check for a winner:

string player = "X";
Func<Button, bool> playerWin = b => b.Value == player;
gameButtons.Row(0).All(playerWin) ||
// ...
gameButtons.Column(0).All(playerWin) ||
// ...
gameButtons.Diagonal(DiagonalDirection.DownRight).All(playerWin) ||
// ...
Samuel