字符串|| Ruby中的比较运算符

时间:2019-03-04 00:20:17

标签: ruby comparison-operators

我是Ruby的新手,正在尝试通过编写一个简单的TicTacToe游戏进行练习。

在评估玩家是否赢得比赛方面,我遇到了一个小问题。

从本质上讲,游戏使用的面板等于:

board = ["#",' ',' ',' ',' ',' ',' ',' ',' ',' ']

每次玩家移动其“标记”(X或O)都会添加到板上,并且具有一些功能来检查该点是否被选中,是否是平局或是否获胜。

所以临时董事会可能看起来像这样:

board = ["#",' ',' ','O',' ','X',' ','O',' ',' ']

在评估某人是否获胜时,我的问题来了。我为此编写了一个函数:(前三个表达式用于检查水平方向的胜利,接下来的三个表达式用于垂直方向的胜利,接下来的两个表达式用于对角线胜利。

def check_for_win(board)
  if [board[1],board[2],board[3]].uniq == [("X" || "O")] || [board[4],board[5],board[6]].uniq == [("X" || "O")] ||
    [board[7],board[8],board[9]].uniq == [("X" || "O")] || [board[1],board[4],board[7]].uniq == [("X" || "O")] ||
    [board[5],board[2],board[8]].uniq == [("X" || "O")] || [board[6],board[9],board[3]].uniq == [("X" || "O")] ||
    [board[1],board[5],board[9]].uniq == [("X" || "O")] || [board[7],board[5],board[3]].uniq == [("X" || "O")] 
    true
  else
    false
  end 
end 

该函数似乎在评估是否有带有“ X”标记的获胜者,但对于“ O”标记,如果不能评估为真。应该注意的是,表达式的左侧仍然求值,例如:

board = ["#",' ',' ','O',' ','O',' ','O',' ',' ']
p [board[7],board[5],board[3]].uniq 
>> ["O"]

我似乎无法理解为什么以及对此的任何指导将不胜感激。

2 个答案:

答案 0 :(得分:4)

'X' || 'O'只是说X或O。由于任何字符串都是真实的,所以它总是返回X。因此,在您说过[('X' || 'O')]的任何地方,您实际上只是说了['X']

因此,您仅检查3的整行是否全部为

我不太了解您如何尝试对此进行测试,但是我觉得您最好先运行两次函数,如果没有找到X作为A,则先交付X,然后交付O。胜者,而不是一次检查两者。

或者,您可以让函数返回'X','O'或nil,然后让它仅运行一次函数。返回的字符串将是谁赢得的,如果没有,则没人会赢得。我也建议为此做一个循环。我觉得它更容易阅读。

这是我解决问题的方法。

ROWS = [
  [1,2,3],
  [4,5,6],
  [7,8,9],

  [1,4,7],
  [2,5,8],
  [3,6,9],

  [1,5,9],
  [7,5,3],
]

def find_winner(board)
  ROWS.each do |row|
    # subtract 1 because the ROWS is 1-indexed (like a phone dial) but arrays are 0-indexed
    row_values = row.map { |v| board[v - 1] }
    return('X') if row_values.all?('X')
    return('O') if row_values.all?('O')
  end

  return(nil)
end


test1 = [
  'X', 'X', 'X',
  'O', 'X', 'O',
  'O', 'O', '',
]
puts "Winner of test1: #{find_winner(test1).inspect}"
"X"

test2 = [
  'X', '',  'X',
  'X', 'O', 'O',
  'X', 'O', 'X',
]
puts "Winner of test2: #{find_winner(test2).inspect}"
"X"

test3 = [
  'O', 'X', 'X',
  'O', 'X', 'O',
  'O', 'O', '',
]
puts "Winner of test3: #{find_winner(test3).inspect}"
"O"

test4 = [
  'O', 'X', 'O',
  'X', 'O', 'X',
  'O', 'O', 'X',
]
puts "Winner of test4: #{find_winner(test4).inspect}"
"O"

test5 = [
  'O', 'X', 'O',
  'O', 'X', 'O',
  'X', 'O', 'X',
]
puts "Winner of test5: #{find_winner(test5).inspect}"
nil

答案 1 :(得分:2)

@Nate回答了您的问题。这是您编写方法的一种方法。

代码

def check_for_win(board)
  check_rows(board)                              ||
  check_rows(board.transpose)                    ||
  check_rows([[0,1,2].map { |i| board[i][i] }])  ||    
  check_rows([[0,1,2].map { |i| board[i][2-i] }])
end

def check_rows(rows)
  rows.find { |row| row.uniq.size == 1 && row.first != :_ }&.first
end
&中的

check_rowssafe navigation operator。如果.first的块返回nil,则会导致find被忽略,并且返回nil

示例

check_for_win [[:O, :_, :O],
               [:O, :X, :_],
               [:X, :X, :X]]
  #=> :X

check_for_win [[:O, :_, :O],
               [:O, :X, :X],
               [:O, :X, :X]]
  #=> :O

check_for_win [[:X, :O, :X],
               [:O, :X, :O],
               [:O, :X, :X]]
  #=> :X

check_for_win [[:X, :O, :O],
               [:X, :O, :_],
               [:O, :X, :X]]
  #=> :O

check_for_win [[:X, :O, :X],
               [:X, :O, :O],
               [:O, :X, :X]]
  #=> nil

check_for_win [[:_, :_, :_],
               [:X, :O, :O],
               [:O, :X, :X]]
  #=> nil