views:

146

answers:

7

Everything is working up to here, I just need to create the method that checks whether someone has won.

Any suggestions on how to tackle this problem effectively?

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

namespace TresEnRaya
{
    public partial class Form1 : Form
    {
        string[,] tablero;
        bool jugador = true;

        public Form1()
        {
            InitializeComponent();
            AsignarTags();
            tablero = new string[3, 3];

            button1.Click += clickHandler;
            button2.Click += clickHandler;
            button3.Click += clickHandler;
            button4.Click += clickHandler;
            button5.Click += clickHandler;
            button6.Click += clickHandler;
            button7.Click += clickHandler;
            button8.Click += clickHandler;
            button9.Click += clickHandler;
        }

        private void AsignarTags()
        {
            button1.Tag = new Posicion() { X = 0, Y = 0 };
            button2.Tag = new Posicion() { X = 0, Y = 1 };
            button3.Tag = new Posicion() { X = 0, Y = 2 };
            button4.Tag = new Posicion() { X = 1, Y = 0 };
            button5.Tag = new Posicion() { X = 1, Y = 1 };
            button6.Tag = new Posicion() { X = 1, Y = 2 };
            button7.Tag = new Posicion() { X = 2, Y = 0 };
            button8.Tag = new Posicion() { X = 2, Y = 1 };
            button9.Tag = new Posicion() { X = 2, Y = 2 };
        }

        private void CambiarSimbolo(Button button)
        {
            Posicion objPosicion = (Posicion)button.Tag;

            if (jugador == true)
            {
                tablero[objPosicion.X, objPosicion.Y] = "X";
                button.Text = "X";
                button.Enabled = false;
                jugador = false;
            }
            else
            {
                tablero[objPosicion.X, objPosicion.Y] = "Y";
                button.Text = "Y";
                button.Enabled = false;
                jugador = true;
            }

            VerificarGanador();
        }

        private void VerificarGanador()
        {
            //THE MAGIC GOES HERE. WINGARDIUM LEVIO-Sah
        }

        private void clickHandler(object sender, EventArgs e)
        {
            Button myButton = (Button)sender;
            switch (myButton.Name)
            {
                case "button1":
                    CambiarSimbolo(myButton);                    
                    break;

                case "button2":
                    CambiarSimbolo(myButton);
                    break;

                case "button3":
                    CambiarSimbolo(myButton);
                    break;

                case "button4":
                    CambiarSimbolo(myButton);
                    break;

                case "button5":
                    CambiarSimbolo(myButton);
                    break;

                case "button6":
                    CambiarSimbolo(myButton);
                    break;

                case "button7":
                    CambiarSimbolo(myButton);
                    break;

                case "button8":
                    CambiarSimbolo(myButton);
                    break;

                case "button9":
                    CambiarSimbolo(myButton);
                    break;
            }
        }        
    }
}

Thanks for the help.

+1  A: 

Well, there are only 8 possible winning combinations, you could simply check each of them against a set of templates representing winning positions.

In retrospect, I would actually modify your data structure to be an MD-array of numbers rather than strings, with:

  0 => blank cell
  1 => player A (X)
 -1 => player B (O)

You could then just see if the sum across any row, column, or diagonal is equal to either +3 or -3.

LBushkin
A: 

For 3x3, I'd brute force it. There's bound to be a better answer, but there are only 8 winning conditions (vert1,vert2,vert3,horiz1,horiz2,horiz3,cross from top left, cross from bottom left)

for x = 0 to 2
   If pos(x,0)==pos(x,1)==pos(X,2)
        return pos(x,0)
for y = 0 to 2
    If pos(0,y)==pos(1,y)==pos(2,y)
        return pos(0,y)
if(pos(0,0)==pos(1,1)==Pos(2,2) || pos(0,2)==pos(1,1)==pos(2,0))
    return pos(1,1)
else
    return null
Kendrick
Yeah I guess I should just brute force it, huh?
Serg
A: 

What about this?

Button[][] matrix = new[]
{
    new []{ button1, button2, button3 },
    new []{ button4, button5, button6 },
    new []{ button7, button8, button9 },
    new []{ button1, button5, button9 },
    new []{ button3, button5, button7 },
    new []{ button1, button4, button7 },
    new []{ button2, button5, button8 },
    new []{ button3, button6, button9 }
};
var result = matrix.FirstOrDefault(set => 
    set.All(button => button.Text == "X") || 
    set.All(button => button.Text == "Y"));
if(result != null)
{
    string winner = result.First().Text;
}
else
{
    // tie
}
Rubens Farias
+2  A: 

The most effective way is to know the location of the last X or O placed on the board and check only the directions that include this location. This way, you aren't using brute force to determine if a player has won.

Bernard
Good point. If you know one point then you can reduce the horizontal and vertical comparisons to a single if - (x,y)==((x+1)%3,y)==((x+2)%3,y) || (x,y)==(x,(y+1)%3)==(x,(y+2)%3) I'm not sure you can abstract the corner to corner condition though. I actually like @abelenky's solution the best, but this is a good example of thinking about all the data you have available to you when solving a problem or optimising a solution.
Kendrick
+1  A: 

Like others have said, brute force is good.

However, I would prefer to list the nodes, rather than loop them, as @Kendrick did.

For example:

TicTacVector winVectors[] = 
{
    {"Top Row",    {0,0}, {0,1}, {0,2}},
    {"Middle Row", {1,0}, {1,1}, {1,2}},
    [...]
    {"Diagonal 1", {0,2}, {1,1}, {2,0}}
};   

(note: pseudo-code. Won't actually compile!)

A bit more intensive in the hand-coding, but I think its also easier to see whats going on.

abelenky
I'm sure there is at least one language in which your code is legal and will compile.
Peter Recore
+1  A: 

Exhaustive search.

yellowsnow
+3  A: 

I once saw a technique that kept 8 different counters, 1 for each winning direction.

Initialize the counters to zero.
When an X is placed, add 1 to the counters for that row, column, and diagonal.
When an O is placed, subtract 1 from the counters for the row, column and diagonal.

If any counter reaches 3 or -3, you know you have a winner.
+3 implies that X won.
-3 implies that O won.

Which counter reached +/-3 tells you which row/column/diagonal won.

abelenky