【问题标题】:How to find first winning combination in Tic-Tac-Toe board?如何在井字棋盘中找到第一个获胜组合?
【发布时间】:2020-02-02 03:45:43
【问题描述】:

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

【问题讨论】:

  • 考虑定义常量X = ['X','X','X'],那么如果WIN_COMBINATIONS.include?(X) 则有'X' 的获胜者。 'O' 类似。

标签: ruby tic-tac-toe


【解决方案1】:

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

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

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

  2. or 是一个控制流运算符,用于do_this or fail 场景。 布尔“或”运算符||。使用or 代替|| 可能 可以工作,但由于precedence 较低,可能会产生意想不到的结果。你几乎总是想要||

  3. 表达式array.all? { |element| element == 'X' || element == 'O' } 检查所有元素是否要么 'X''O'。对于['X','O','O']false 对于['X',' ','O'] 将是true。那是因为您将条件放在块内。你想要的是检查元素是全部'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 如果没有匹配)

【讨论】:

  • 非常感谢,我会牢记这些要点。也很抱歉标题不好。
  • @DiegoVasquez 不客气。不要忘记通过单击灰色复选标记“接受”答案。 (不用着急,你可以等待更多的答案)
【解决方案2】:

这是我解决问题的方法:

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

在初始化方法中,我们创建了一个 3*3 的数组,表示棋盘上的所有位置。这使它变得容易得多,因为它已经按行分组。使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-20
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 1970-01-01
    相关资源
    最近更新 更多