Ruby的新内容,请原谅糟糕的代码。我想遍历多维数组WIN_COMBINATIONS
并检查至少一个数组的所有元素是否等于'X'
或全部等于'O'
。如果是这样,则返回匹配的数组。这是通过won?
函数完成的,但它似乎只返回整个多维数组。任何协助将不胜感激。
class TicTacToe
WIN_COMBINATIONS = [
[0,1,2], # top_row
[3,4,5], # middle_row
[6,7,8], # bottom_row
[0,3,6], # left_column
[1,4,7], # center_column
[2,5,8], # right_column
[0,4,8], # left_diagonal
[6,4,2] # right_diagonal
]
def initialize
@board = Array.new(9, " ")
end
def display_board
puts " #{@board[0]} | #{@board[1]} | #{@board[2]} "
puts "-----------"
puts " #{@board[3]} | #{@board[4]} | #{@board[5]} "
puts "-----------"
puts " #{@board[6]} | #{@board[7]} | #{@board[8]} "
end
def input_to_index(board_position)
user_input = board_position.to_i
user_input - 1
end
def move(board_index, player_token = 'X')
@board[board_index] = player_token
end
def position_taken?(board_position)
if @board[board_position] == ' '
false
else
true
end
end
def valid_move?(board_position)
if board_position >= 0 and board_position <= 8
if @board[board_position] == ' '
true
end
else
false
end
end
def current_player
turn_count % 2 == 0 ? "X" : "O"
end
def turn_count
@board.count{|token| token == "X" || token == "O"}
end
def turn
puts "Select your move (1-9)n"
move = gets.chomp
move_index = input_to_index(move)
if valid_move?(move_index)
token = current_player
move(move_index, token)
display_board
else
puts "Select your move (1-9)n"
move = gets.chomp
end
end
def won?
WIN_COMBINATIONS.each do |combinations|
if combinations.all? {|combination| combination == 'X' or combination == 'O'}
combinations
else
false
end
end
end
def draw?
if full? and !won?
true
elsif won?
false
else
false
end
end
def over?
end
def winner
end
def play
end
end
[...] 它似乎只返回整个多维数组。
您尝试的解决方案存在几个问题:
-
WIN_COMBINATIONS
是一个索引数组。这些索引是数字的,因此它们永远不会'X'
或'O'
。您必须检查其相应的值是'X'
还是'O'
。 -
or
是用于do_this or fail
方案的控制流运算符。布尔"or"运算符||
。使用or
而不是||
可能会起作用,但由于其优先级较低,可能会产生意外结果。你几乎总是想要||
. -
表达式
array.all? { |element| element == 'X' || element == 'O' }
检查所有元素是'X'
还是'O'
。这对['X','O','O']
来说是true
,对['X',' ','O']
来说是false
.那是因为你把条件放在块里。你想要的是检查元素是全部'X'
,还是全部'O'
:array.all?('X') || array.all?('O')
-
方法的返回值是
WIN_COMBINATIONS.each { ... }
的结果,Array#each
总是返回数组本身(即WIN_COMBINATIONS
(,无论块的结果如何。要获取与条件匹配的第一个元素,请使用find
。
让我们将所有这些应用到您的代码中。给定此板:
@board = %w[
X - O
O X -
- - X
]
您可以通过以下方式获得第一个匹配的组合:
WIN_COMBINATIONS.find do |indices|
values = @board.values_at(*indices)
values.all?('X') || values.all?('O')
end
#=> [0, 4, 8]
values_at
返回相应索引的值(*
将indices
数组转换为参数列表,因此values_at(*[0,1,2])
变为values_at(0,1,2)
(。然后,块的第二行检查这些值是全部'X'
,还是全部'O'
。一旦计算结果为true
,循环中断,find
返回匹配元素。(如果没有匹配项,则nil
(
以下是我处理该问题的方法:
class TicTacToe
class OccupiedError < StandardError; end
attr_reader :rows
def initialize
@rows = 3.times.map{ Array(3, nil) }
end
def place!(player, x:, y:)
raise ArgumentError, "player must be :x or :o" unless [:x, :o].include?(player)
raise OccupiedError, "slot is already occupied" unless @rows[y][x].nil?
@rows[y][x] = player
end
# gets an array of columns instead of rows.
def columns
(0..2).map { |n| @rows.map {|row| row[n] } }
end
def diagonals
[
[@rows[0][0], @rows[1][1], @rows[2][2]], # lrt
[@rows[0][2], @rows[1][1], @rows[2][0]] # rtl
]
end
def all_combos
rows + columns + diagonals
end
# checks all the horizontal, vertical and diagonal combinations
def check_for_winner
# checks all combos for three in a row
(all_combos.find{ |a| a.all?(:x) || a.all?(:o) })&.first
end
end
在 initialize 方法中,我们创建一个 3*3 数组,它表示板上的所有位置。这使得它变得容易得多,因为它已经分组成行。空字符串的 intead 使用 nil 表示空正方形,因为 nil 是假的。
当我们想要检查获胜者时,我们将行、列和两个对角线收集到一个数组数组中:
[1] pry(main)> game.rows
=> [[:o, :o, :o], [nil, :x, :x], [:x, nil, nil]]
[2] pry(main)> game.all_combos
=> [[:o, :o, :o],
[nil, :x, :x],
[:x, nil, nil],
[:o, nil, :x],
[:o, :x, nil],
[:o, :x, nil],
[:o, :x, nil],
[:o, :x, :x]]
从那里我们只需要检查它们中的任何一个是否都是:x
或:o
.我们实际上不必列出获胜的组合。在这种情况下,game.check_for_winner
将返回:o
。