我正在尝试制作 "Game of Set" 但不知道如何正确检查集合

I am trying to make "Game of Set" but don't know how to correctly check the set

嗨,我刚开始学习编码,ruby 是我的第一语言。我正在尝试制作一款名为“Game of Set”的游戏,可以在 here or wikipedia

中查看规则

我能够获取用户卡片并将它们输入不同的数组。然而,我花了很多时间试图弄清楚如何验证集合。我试图按索引比较数组,但结果不是我想要的。 示例:

first = ['two', 'purple', 'stripe', 'diamond']
second = ['one', 'purple', 'solid', 'diamond']
third = ['three', 'purple', 'empty', 'diamond']

这应该是正确的,因为都是紫色的,都是钻石的,不同的数字和不同的过滤器。

first = ['one', 'green', 'stripe', 'squiggle']
second = ['one', 'purple', 'solid', 'diamond']
third = ['two', 'green', 'empty', 'oval']

这是错误的,因为两个数字相同,一个不相同,颜色也类似。

这就是我要实现的set游戏here

请帮忙谢谢!

在这个游戏中,一个__set被定义为:

Several games can be played with these cards, all involving the concept of a set. A set consists of three cards satisfying all of these conditions:

  • They all have the same number or have three different numbers.
  • They all have the same shape or have three different shapes.
  • They all have the same shading or have three different shadings.
  • They all have the same color or have three different colors.

-- Wikipedia

可以用 one-liner:

来检查
first = ['two', 'purple', 'stripe', 'diamond']
second = ['one', 'purple', 'solid', 'diamond']
third = ['three', 'purple', 'empty', 'diamond']
first.zip(second, third).all? { |array| [1,3].include?(array.uniq.length) }
#=> true

first = ['one', 'green', 'stripe', 'squiggle']
second = ['one', 'purple', 'solid', 'diamond']
third = ['two', 'green', 'empty', 'oval']
first.zip(second, third).all? { |array| [1,3].include?(array.uniq.length) }
#=> false

具体是如何工作的?

first
  .zip(second, third) #=> [["two", "one", "three"], ["purple", "purple", "purple"], ["stripe", "solid", "empty"], ["diamond", "diamond", "diamond"]]
  .all? { |array| 
     # do all nested arrays comply with the set conditions and
     # contain only the same element or three different ones?
    [1,3].include?(array.uniq.length) 
  }

我们得到

first =  ['two',   'purple', 'stripe', 'diamond']
second = ['one',   'purple', 'solid',  'diamond']
third =  ['three', 'purple', 'empty',  'diamond']

arr = [first, second, third]
  #=> [["two",   "purple", "stripe", "diamond"],
  #    ["one",   "purple", "solid",  "diamond"],
  #    ["three", "purple", "empty",  "diamond"]]

我们希望检查 arr 的每个“列”是否包含每个“行”的相同字符串或每行中的不同字符串。

Ruby 没有数组“列”和“行”的概念,只有元素。 arr有三个元素,即数组firstsecondthird。但是,我们可以将方法 Array#transpose1 发送到对象 arr 以获得我们可以使用的东西:

a = arr.transpose
  #=> [["two", "one", "three"],
  #    ["purple", "purple", "purple"],
  #    ["stripe", "solid", "empty"],
  #    ["diamond", "diamond", "diamond"]]

我们现在只需要看看 a 的四个元素是否都通过了测试。

首先,我们想知道是否

b = a[1]
  #=> ["purple", "purple", "purple"]

满足要求属性。一种方便的方法是使用方法 Array#uniq:

计算数组 b 的唯一元素
c = b.uniq
  #=> ["purple"]
如果c中的元素个数等于1b中的元素个数b.size #=> 3,则

b满足要求.由于c.size #=> 1c满足要求。

注意 b.sizearr.size 相同。


我们可以将其放在一个方法中:

def valid?(arr)
  nbr_elements = arr.size
  a = arr.transpose
  a.all? do |b|
    sz = b.uniq.size
    sz == 1 || sz == nbr_elements
  end
end

Enumerable#all?2


我们来试试吧。

valid?(arr)
  #=> true

为了说明 valid? 执行的计算,我将在用 puts 语句对方法加盐后再次 运行 它。

def valid?(arr)
  nbr_elements = arr.size
  puts "nbr_elements = #{nbr_elements}"
  a = arr.transpose
  a.all? do |b|
    sz = b.uniq.size
    puts "b = #{b}"
    puts "  sz = #{sz}"      
    puts "  #{sz == 1} || #{sz == nbr_elements} => #{sz == 1 || sz == nbr_elements}"
    sz == 1 || sz == nbr_elements
  end
end
valid?(arr)
  #=> true
nbr_elements = 3
b = ["two", "one", "three"]
  sz = 3
  false || true => true
b = ["purple", "purple", "purple"]
  sz = 1
  true || false => true
b = ["stripe", "solid", "empty"]
  sz = 3
  false || true => true
b = ["diamond", "diamond", "diamond"]
  sz = 1
  true || false => true

我们也试试第二个例子。

arr = [["one", "green",  "stripe", "squiggle"],
       ["one", "purple", "solid",  "diamond" ],
       ["two", "green",  "empty",  "oval"    ]]
valid?(arr)
  #=> false
nbr_elements = 3
b = ["one", "one", "two"]
  sz = 2
  false || false => false

实际上我们可能不会有语句 a = arr.transpose 而是 chain arr.transpose to all?:

def valid?(arr)
  nbr_elements = arr.size
  arr.transpose.all? do |b|
    sz = b.uniq.size
    sz.zero? || sz == nbr_elements
  end
end

1 当一个数组的所有元素都是元素个数相同的数组时,方法transposeArray#zip可以互换使用more-or-less。 @spickerman 在他的回答中使用了 zip

2 Enumerable 是一个包含实例方法的模块。任何 包含 模块的 class(现在不用担心细节)都使用了 Enumerable 的所有方法,或多或少就像它们一样已在 class.

中定义