Ruby language statement with regex

I'm working on my second ruby ​​program and I'm literally stuck with the last thing between me and the finished program. My task is to write a Rock, Paper, Scissors method that returns the winning player. This requires a game argument of the form [["Dave", "S"], ["Dan", "R"]], where "S" and "R" are "Scissors" and "Rock", respectively. It then determines the winner and returns an array containing the winning strategy. Also raises errors if the game is of wrong length or strategy == or not in range.

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

      

This works as I expect, tests strategies against regex and returns a winner. Except for the last case, where the counter always returns nil. If I call player ["r"] under any of the others when it succeeds and it returns the correct player in "/ p / & & / r /". If I change the order it still doesn't work, so I know it is not related to its position. The regex / r / evaluates when needed if I make a separate match call outside of the case statement. So I believe I have narrowed it down to do something with / s / and / r /, but otherwise I'm stumped. Any help with DRYness is also appreciated, thanks for the help!

+3


source to share


4 answers


You don't really need to case

at all. My version of the solution for this task:



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

      

0


source


The problem is with your format /X/ && /X/

. Ruby will not interpret this to require that both regular expressions match. I'm not sure what, but I believe it will treat it the same way when /p/, /r/

, which will be true if or regex matches . When you are testing game = [["Dave","S"], ["Dan","R"]]

, "r"

matches the first argument of case and you are trying to reference playr["p"]

.

Try this instead:



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

      

0


source


Your problem is what is being /p/ && /r/

evaluated before actually being used as a label. Since none of them are false or null, /p/ && /r/

is equal /r/

and in a similar way for your other case labels.

Unless you rewrite this to have one case argument for each case, it case

just doesn't seem like a good fit for what you are doing to me

0


source


Using the instructions in the problem, I solved the problem in a different way.

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

      

I tested all given scenarios and it worked for me.

0


source







All Articles