4

trying to make a tic-tac-toe game actually. So if there's a better way I would like to know too! So I have a grid [0,8], and the user's positions are stored in an array. Great. Next I want to see if the columns match up. So let's say first row is (0,1,2). My question is if the user has an array like array(1,5,6,0,2), so he won. How can I match it efficiently? I was thinking of doing something like this but doesn't look efficient:

$user= array(1,5,6,0,2);
in_array(0,$user) && in_array(1,$user) && in_array(2,$user)

I also thought about switch case but still face the question how do I find multiple values at once.

5
  • 1
    You might use array_intersect() to compare an array representing a row [0,1,2] with the user's array and verify the output of the intersection has count() == 3, meaning all 3 were matched. Among the expansive set of PHP array functions there are many which could be used to suit your needs one way or another. Are you planning to keep a list of possible values that constitute a row (simple), or would you want those to be determined algorithmically (a little harder)? Commented Nov 7, 2014 at 15:25
  • This might be of interest: ocf.berkeley.edu/~yosenl/extras/alphabeta/alphabeta.html Commented Nov 7, 2014 at 15:26
  • For a tic-tac-toe I would choose to operate with a two-dimensional matrix a.k.a. array, filled with three possible values 0 (unoccupied space), 1 (x) and -1 (o), and then count the sums for the rows, columns and diagonals. Commented Nov 7, 2014 at 15:50
  • TicTacToe is fairly simple since there are only 8 ways to win 3 horiz, 3 vert, 2 diag). Simply see if any of the 8 "winning" arrays are a subset of the $user array. Commented Nov 7, 2014 at 15:52
  • Thanks guys. I love all the answers, pretty interesting. Commented Nov 7, 2014 at 17:45

2 Answers 2

1

I agree that with such a small number of possible combinations to win, the solution can be kept very simple. I would do it using array_diff.

function has_won($user) {
    // returns false if the user has not won, otherwise 
    // returns the first winning combination found.
    $wins = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
    foreach ($wins as $win) {
        if (!array_diff($win, $user)) return $win;
        // array_diff returns the values in the first argument
        // not present in any subsequent arguments. So if its 
        // result is empty, the user has winning combination.
    }
    return false;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Note for future readers: using empty() directly in this context will require PHP 5.5. With 5.4 and below, it would be a parse error since the result of array_diff() is not a variable. The array_diff() would first need to be stored in a variable, in turn passed to empty(). 5.5 can operate on the result of an expression however.
@MichaelBerkowski Excellent point; thank you. I should mention that in the answer.
Why are you using empty here in the first place, especially when it requires all these caveats? Just write !array_diff(..), it's the exact same thing!
@deceze Of course! That certainly does simplify things. Thank you.
1

I will not make a claim that this is the most efficient method, but it reduces the number of operations considerably compared with && chaining and multiple in_array() calls.

What we'll do is keep a 2-dimensional array of possible win-combinations: rows, columns, diagonals, as sub-arrays. Then in a foreach loop over that 2D array, test the user's current array state against the row combination with array_intersect(). If the entire winning combination is present in the user's array, the result of array_intersect() will be 3, which you can test with count().

Since one match is enough for a win, you can break out of the loop on the first match to declare a win.

$combinations = array(
  // Rows
  array(0,1,2),
  array(3,4,5),
  array(6,7,8),
  // Columns
  array(0,3,6),
  array(1,4,7),
  array(2,5,8),
  // Diagonals
  array(0,4,8),
  array(2,4,6),
);

// Loop over the array of winners and test array_intersect()
// If 3 values intersect, the full win combination was matched
foreach ($combinations as $combination) {
   if (count(array_intersect($combination, $user)) == 3) {
      // User wins! Take whatever action necessary...
      // Exit the loop
       break;
   }
}

Here's a demonstration in which 2 of 3 sets for $user are winners: http://codepad.viper-7.com/Mvu0wa

There are algorithmic ways of generating the winning combinations rather than hard-coding them, but there are only eight possible combinations so it isn't that hard, and the point here is the use of array_intersect() to find a subset of the user's current placements.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.