如何在井字棋盘中找到第一个获胜组合?



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

[...] 它似乎只返回整个多维数组。

您尝试的解决方案存在几个问题:

  1. WIN_COMBINATIONS是一个索引数组。这些索引是数字的,因此它们永远不会'X''O'。您必须检查其相应的值'X'还是'O'

  2. or是用于do_this or fail方案的控制流运算符布尔"or"运算符||。使用or而不是||可能会起作用,但由于其优先级较低,可能会产生意外结果。你几乎总是想要||.

  3. 表达式array.all? { |element| element == 'X' || element == 'O' }检查所有元素是'X'还是'O'。这对['X','O','O']来说是true,对['X',' ','O']来说是false.那是因为你把条件放在块里。你想要的是检查元素是全部'X',还是全部'O'

    array.all?('X') || array.all?('O')
    
  4. 方法的返回值是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

相关内容

最新更新