Paly CS
Paly CS

Reputation: 19

How to make a general method to check for winners in Tic-Tac-Toe

I made a Tic-Tac-Toe game in Ruby. The method below checks for a winner in the vertical columns.

How do I make it so that this method can be applied to boards of different sizes, like 4x4, 6x6?

def vertical_check(array)

  result = nil

  if (array[0][0] == "X" && array[1][0] == "X" && array[2][0] == "X") ||
    (array[0][1] == "X" && array[1][1] == "X" && array[2][1] == "X") ||
    (array[0][2] == "X" && array[1][2] == "X" && array[2][2] == "X")

    result = "X"

  elsif (array[0][0] == "O" && array[1][0] == "O" && array[2][0] == "O") ||
    (array[0][1] == "O" && array[1][1] == "O" && array[2][1] == "O") ||
    (array[0][2] == "O" && array[1][2] == "O" && array[2][2] == "O")

    result = "O"
  else
    result = nil
  end
  return result
end

The following is a failed attempt:

def vertical_check_x(array)

  result = nil

  index = 0
  index2 = 0

  until result != nil || index == array.length

    while array[index][index2] == "X"
      index += 1
    end

    if index == array.length
      result = "X"
    else
      result = nil
      index = array.length
    end

    index2 += 1
  end

  return result
end

def vertical_check_o(array)

  result = nil

  index = 0
  index2 = 0
  until result != nil || index == array.length

    while array[index][index2] == "O"
      index += 1
    end

    if index -1 == array.length
      result = "O"
    else
      result = nil
      index = array.length
    end

    index2 += 1
  end

  return result
end

def vertical_check(array)

  result = vertical_check_x(array)

  if result == nil
    result = vertical_check_o(array)
  end

  return result
end

Upvotes: 1

Views: 590

Answers (1)

rohit89
rohit89

Reputation: 5773

To quickly find a winner in given array, count the number of unique elements, confirm that there is only one unique element and if it is only X or O:

def winner arr
  return arr[0] if arr.uniq.length == 1 && ['X', 'O'].include?(arr[0])
  nil
end

The next problem is selecting the rows, columns and diagonals for an nxn array.

Rows are easy:

rows = arr.map {|row| row}

Columns are as follows - you select elements with the same index for each row:

cols = n.times.collect {|i| arr.map {|row| row[i]}}

Next are diagonals. There are two diagonals, one starts from leftmost corner and the other from the rightmost.

The leftmost diagonal has the sequence as:

(0, 0) -> (1, 1) -> (2, 2) ....

See the pattern?

diag = n.times.collect {|i| arr[i][i]}

The rightmost diagonal has pattern that goes like this (for a 3x3):

(0, 2) -> (1, 1) -> (2, 0)

For a 4x4, it's like this:

(0, 3) -> (1, 2) -> (2, 1) -> (3, 0)

So, the pattern for an nxn is:

(0, n-1-0) -> (1, n-1-1) -> (2, n-1-2) -> ... (i, n-1-i) ... -> (n-1, 0)

So:

diag = n.times.collect {|i| arr[i][n - 1 - i]}

Now, you can just do something like:

w = rows.map {|r| winner r}.compact[0]

for each array to get the winner.

Upvotes: 4

Related Questions