0

For some reason, this is not iterating over the collection. Throwing a pry in there shows that only the first index is getting looked at. [0,1,2] I'm sure I'm just tired and it's something small, but I'm drawing a black here,

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

def won?(board)
  WIN_COMBINATIONS.each do |combo|
    if board[combo[0]] != " " && board[combo[0]] == board[combo[1]] && board[combo[0]] == board[combo[2]]
      return combo
    else
      return false
    end
  end
end
2
  • What param do you pass into your won? method? Commented Jan 2, 2018 at 15:07
  • @MarekLipka it's an array. board = ["O", "O", " ", "X", "X", "X", " ", " ", " "] in the test is where it's getting passed in. Commented Jan 2, 2018 at 15:09

3 Answers 3

5
def won?(board)
  WIN_COMBINATIONS.any? do |combo|
    board[combo[0]] != " " &&
      board[combo[0]] == board[combo[1]] &&
      board[combo[0]] == board[combo[2]]
  end
end

or, even more succinct with Array#values_at:

def won?(board)
  WIN_COMBINATIONS.any? do |combo|
    [%w|X| * 3, %w|O| * 3].include? board.values_at(*combo)
  end
end
Sign up to request clarification or add additional context in comments.

7 Comments

@mike-heft In your actual code you should use this. This is more idiomatic ruby
...or arr = board.values_at(*combo).uniq; arr.size == 1 && arr.first != ' '.
@CarySwoveland you might want to check the previous version of this answer :)
Ah, yes. I prefer your previous revision. Adding a variable and a second statement to remove the select clause is imo a wash, but mainly, I think the earlier one reads better.
You can make your second version even more succinct: def won?(board) false end :-P
|
4

The reason is that you return from your method on the first iteration.
Inside your iteration you always return after the first step. Just put the return false statement after your iteration and it will work.

1 Comment

Yup that was it. Was just coming back to answer Thank you :D
1

Just three more solutions along with test code checking them against each other:

def won1?(board)
  WIN_COMBINATIONS.any? do |i, j, k|
    board[i] != " " && board[i] == board[j] && board[i] == board[k]
  end
end

def won2?(board)
  WIN_COMBINATIONS.any? do |combo|
    a, b = board.values_at(*combo).minmax; a != " " && a == b
  end
end

def won3?(board)
  WIN_COMBINATIONS.any? do |combo|
    [["X"], ["O"]].member?(board.values_at(*combo).uniq)
  end
end

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

a = ["O", "X", " "]
a.product(*([a] * 8)).each { |board|
  w1 = won1?(board)
  w2 = won2?(board)
  w3 = won3?(board)
  p [w1, w2, w3, board] if w2 != w1 || w3 != w1
}

1 Comment

Another: WIN_COMBINATIONS.any? {|combo| ["X", "O"].one? {|token| combo.all? {|i| board[i] == token}}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.