使用正则表达式匹配的 Ruby case 语句

3
我正在处理我的第二个Ruby程序,但遇到了困难,这是我和完成程序之间的最后一道坎儿。我的任务是编写一个石头、剪刀、布游戏方法,返回获胜的玩家。为此,它需要以[["Dave","S"],["Dan","R"]]的格式作为游戏参数,其中"S"和"R"分别代表"剪刀"和"石头"。然后,它将确定获胜者并返回包含获胜策略的数组。如果游戏长度不正确或策略超出范围,则还会引发错误。
class WrongNumberOfPlayersError < StandardError ; end
class NoSuchStrategyError < StandardError ; end


def rps_game_winner(game)

raise WrongNumberOfPlayersError unless game.length == 2

  #Hash of whose Keys are the strategies and values are the players
  playr = {(game[0].slice(1).downcase) => game[0],
    (game[1].slice(1).downcase) => game[1]} #This fits on the above line in IRB

  #Collect Strategies in array for comparison
  stgys = playr.keys

  #raise NoSuchStrategyError unless players give strategies in range, no duplicates
  raise NoSuchStrategyError unless (stgys.select { |s| s.match /[prs]/ }.size == 2) 

  #determine Winner
  case stgys.to_s
   when /p/ && /r/
     playr["p"]
   when /p/ && /s/
     playr["s"]
   when /s/ && /r/
     playr["r"]
  end
end

这个功能符合我的期望,对策略进行正则表达式匹配并返回胜者。除了最后一种情况,当遇到时总是返回nil。如果在其他情况下调用player [“r”],它将成功,并在“/ p / && / r /”中返回正确的玩家。如果我改变顺序,它仍然不起作用,所以我知道它与位置无关。如果我在case语句之外进行单独的匹配调用,正则表达式/ r /会在应该的时候计算。因此,我相信我已经把问题缩小到/s/和/r/之间的某些关系,但我还是束手无策。此外,任何关于DRYness的帮助都将不胜感激,谢谢您的帮助!


似乎是来自SaaS课程的作业 :) - the_joric
你知道的,我开始得有点晚,希望能够追赶上来,但是在这个问题上我花了几个小时努力思考代码后,我意识到阿曼多可能并没有开玩笑,这确实是一门高级课程 :) - two_OMind
4个回答

0
问题出在你的 /X/ && /X/ 格式上。Ruby不会将其解释为需要匹配两个正则表达式。我不确定哪个是哪个,但我相信它会像when /p/, /r/一样处理,即如果任何一个正则表达式匹配,则为真。当你测试game = [["Dave","S"], ["Dan","R"]]时,"r"匹配第一个case语句,然后你尝试引用playr["p"]

请改用以下代码:

case stgys.to_S
  when "pr", "rp"
    playr["p"]
  when "ps", "sp"
    playr["s"]
  when "sr", "rs"
    playr["r"]
end

谢谢您的回复!不幸的是,当我输入这个代码时它并不能正常工作,因为.to_s返回的是self的表示而不是字符串元素,换句话说是"["p", "r"]"。最终,我放弃了我的DRY理念,在哈希键的调用中添加了.sort,并使用可能产生的三个字符串作为我的'when'参数。 - two_OMind

0

实际上,你根本不需要使用case。 我对这个任务的解决方案如下:

def rps_game_winner(game)
  raise WrongNumberOfPlayersError unless game.length == 2
  raise NoSuchStrategyError if game.any? {|n| !(n[1] =~ /^[spr]$/i)}
  loose_hash = {'s' => 'r', 'p' => 's', 'r' => 'p'}
  strategy1 = game[0][1].downcase
  strategy2 = game[1][1].downcase
  loose_hash[strategy1] == strategy2 ? game[1] : game[0]
end

非常感谢,作为一个新手Ruby程序员,我不熟悉你在这里使用的?:条件语句,作为一个初学者,我喜欢使用哈希表,但真的不知道如何充分利用它。当我看到你的方法时,你的loose_hash让我感觉很有意义,但我自己想不到。感谢你帮助我成为更好的程序员。 - two_OMind

0
你的问题在于 /p/ && /r/ 在实际用作标签之前就被计算了。由于它们都不是 false 或 nil,/p/ && /r/ 等于 /r/,其他情况标签也是如此。
除非你将每个情况重写为单个 case 语句,否则我认为 case 并不适合你所做的事情。

0

在问题的指导下,我用不同的方法解决了这个问题。

def rps_game_winner(game)
  raise WrongNumberOfPlayersError unless game.length == 2
  raise NoSuchStrategyError unless game[0].length == 2 and game[1].length == 2
  raise NoSuchStrategyError unless game[0][1] =~ /^[RPS]$/ and game[1][1] =~ /^[RPS]$/
  return game[0] unless (game[0][1] == "P" and game[1][1] == "S") or
                        (game[0][1] == "S" and game[1][1] == "R") or
                        (game[0][1] == "R" and game[1][1] == "P")
  return game[1]
end

def rps_tournament_winner(tournament)
  return rps_game_winner(tournament) unless tournament[0][1] !~ /^[RPS]$/
  return rps_tournament_winner([rps_tournament_winner(tournament[0]), rps_tournament_winner(tournament[1])])
end

我已经测试了所有给定的场景,并且它对我起作用了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接