Method doesn't check if tic-tac-toe game won, only returns first combo

WIN

Create a WIN method that accepts a board as an argument and returns
false/nil if there is no win combination present in the board and
returns the winning combination indexes as an array if there is a win.
To clarify: this method should not return who won (aka X or O), but
rather how they won – by means of the winning combination.

Iterate over the possible win combinations defined in WIN_COMBINATIONS
and check if the board has the same player token in each index of a
winning combination.

That is a very verbose and explicit example of how you might iterate
over a nested array of WIN_COMBINATIONS and checking each win
combination index against the value of the board at that position.

For example, on a board that has a winning combination in the top row,
#‘win’ should return [0,1,2], the indexes in the board that created the
win:

Board with winning X in the top row.

board = [“X”, “X”, “X”, " ", " ", " ", " ", " ", " "]

win(board) #=> [0,1,2]
A board with a diagonal win would function as follows:

Board with winning X in the right diagonal.

board = [“X”, “O”, “X”, “O”, “X”, “O”, “X”, “X”, “O”]

X | O | X

-----------

O | X | O

-----------

X | X | O

win(board) #=> [2,4,6]
A board with no win would return false/nil:

board = [" ", " ", " ", " ", " ", " ", " ", " ", " "]
win(board) #=> nil
You should be able to iterate over the combinations defined in
WIN_COMBINATIONS using each or a higher-level iterator to return the
correct board indexes that created the win.

Your method should work for both boards that win with an “X” or boards
that win with an “O”. We’ve provided you with a helper method called
position_taken? that takes a board and an index as arguments and returns
true or false based on whether that position on the board has been
filled.

so here is what I have so far:

WIN_COMBINATIONS =
[[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 4, 8],
[2, 4, 6],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8]]

def win(board)

combo = 0
while combo < WIN_COMBINATIONS.length
current_combo = WIN_COMBINATIONS[combo]

current_combo.all? { |position|
  board[position[0]] == "X" && board[position[1]] == "X" &&

board[position[2]] == “X” || board[position[0]] == “O” &&
board[position[1]] == “O” && board[position[2]] == “O”
}

if current_combo.all? == true
  return current_combo
else return false
end

combo += 1

end

end

I’ve tried many things, but whenever I test it and pass the method a
board, it always seems to only return the first combo. Would greatly
appreciate the help.

combo = 0

You can do this without an explicit loop

with the #each method: WIN_COMBINATIONS.each{|current_combo|…}

while combo < WIN_COMBINATIONS.length

# Current_combo is now [0, 1, 2]
current_combo = WIN_COMBINATIONS[combo]

# Now you are iteration of each entry of [0,1,2],
# checking whether the block returns true for
# each of 0,1, and 2.
current_combo.all? { |position|

  # First iteration: Position is now 0.
  # Applying the [n] operator on an *integer*
  # gives the n-th bit of the integer.
  # This is not what you want to do.
  board[position[0]] == "X" && board[position[1]] == "X" &&

board[position[2]] == “X” || board[position[0]] == “O” &&
board[position[1]] == “O” && board[position[2]] == “O”
}

# The #all? method returns true or false.
# But you have dropped the return value from
# the previous call.
# Now you are calling the all? method again,
# but without providing a block.
# The ruby documentation says this:
#   If the block is not given, Ruby adds an
#   implicit block of { |obj| obj } which will
#   cause all? to return true when none of the
#   collection members are false or nil.
# (cmp. 

Module: Enumerable (Ruby 2.2.3))
# This explains why it always returns the combo.
# current_combo.all? always evaluates to true in your case.
if current_combo.all? == true
return current_combo
else return false
end

combo += 1

end

What you want to do is iterate over each combo, and check whether the
array board has got only 'X’s or only 'O’s at these indices.

A bit of pseudo-code:

For each combo
return true if
for all indices i(board[i] = ‘X’)
or
for all indices i(board[i] = ‘O’)
otherwise return false

Thanks you!!

Do you mind elaborating what you mean when you say…

“# Applying the [n] operator on an integer
# gives the n-th bit of the integer.
# This is not what you want to do.”

Ok, so I got it working. Thanks for your help Desei. Here is my code:

def win(board)

combo = 0
while combo < WIN_COMBINATIONS.length
current_combo = WIN_COMBINATIONS[combo]

win1 = current_combo.all? { |position| board[position] == "X" }
win2 = current_combo.all? { |position| board[position] == "O" }

if win1 == true || win2 == true
  return current_combo
else
 false
end

combo += 1

end

end

One thing i noticed. If I “return false” rather than just “false” on the
last “if” statement, my code doesn’t work. Why is that?

Aren’t ‘return false’ and ‘false’ the same thing?

Do you mind elaborating what you mean
when you say…
“# Applying the [n] operator on an
integer
# gives the n-th bit of the integer.
# This is not what you want to do.”

You did two iterations, first over all combos, then over each indices.
Each indices is an integer (such as 3). Then you wrote position[0]. The
value of the variable position is eg. 3. And

3[0]
in ruby means the first bit of the integer 3 (11 in binary).

One thing i noticed. If I “return false” > rather than just “false” on the
last “if” statement, my code doesn’t
work. Why is that?

You can return once you find a combo that works.

When you write “return false”, you’re returning from the method if the
first combo does not work, before you even get to the other combos.

If you only write ‘false’, the if-statement returns false. But the
return value is discarded with no effect.

In other words, the else-branch does not do anything, and you proceed to
the next combo.

You can reduce the if-statement to

if win1 == true || win2 == true
return current_combo
end

or even

return current_combo if win1 == true || win2 == true

Note that pretty much everything has got a return value in ruby, so you
can do

x = if y==0
“y is 0”
else
“y is not zero”
end