0

I'm writing a function that can be used to play "rock, paper, scissors, lizard, spock". I use menu() to ask the user to choose an option, sample() to give the computer an option, and define a win as occurring if the two choices match one of 10 winning pairs. The code works (as in, doesn't throw errors), but produces unexpected output. I can't figure out why this doesn't work, I think it has to do with %in% or perhaps a nuance of list that I don't understand.

choices <- c("rock", "paper", "scissors", "lizard", "spock")

# Scissors [3] beats paper [2], 
# paper [2] beats rock [1], 
# rock [1] beats lizard [4], 
# lizard [4] beats Spock [5],
# Spock [5] beats scissors [3], 
# scissors [3] beats lizard [4], 
# lizard [4] beats paper [2], 
# paper [2] beats Spock [5], 
# Spock [5] beats rock [1], 
# rock [1] beats scissors [3].

wins <- list(c(3, 2), c(2, 1), c(1, 4), c(4, 5), c(5, 3), c(3, 4), c(4, 2), c(2, 5), c(5, 1), c(1, 3))

fun <- function(){
  input <- menu(choices, title="Choose one:")
  if (input == 0){
    message("You have to pick a valid choice to play this. Try again.")
  }
  if (input >= 1 && input <= 5){
    comp_choice <- sample(1:5, 1)
    message(paste0("you chose ", choices[input]))
    message(paste0("computer chose ", choices[comp_choice]))
    print(list(c(input, comp_choice)) %in% wins)
    if (input != comp_choice){
      if (list(c(input, comp_choice)) %in% wins) {
        message("you won")
        } 
      else message("you lost")
    }
    else message("it's a draw")
  }
}

fun()

Example of unexpected output (should be a win):

Selection: 3
you chose scissors
computer chose lizard
[1] FALSE
you lost
FB001
  • 13
  • 4
  • you should add set.seed(0) to the beginning of your code, if you are using random processes such as sampling – Mark Aug 05 '23 at 03:30
  • I wrote an initial comment that was wrong, based on a quick misreading of one of the lines of you function. But you're right that using `%in%` with lists is doing something you don't expect. In fact it's a really sneaky odd thing. Try inserting a print statement, i.e. `print(as.character(list(c(input,comp_choice)))` and running the function a few times. You'll quickly notice some odd stuff happening. It's complicated, but you'll note that the docs for `match` say that lists are converted to character first. – joran Aug 05 '23 at 03:59
  • The problem is to do with some type-related jank in R. If you change the line to be `list(as.numeric(c(input, comp_choice))) %in% wins`, then it works – Mark Aug 05 '23 at 04:00
  • What's going on under the hood is sort of weird, but the bottom line is that, as the documentation suggests, using match on lists is a bad idea, except in very very simple cases. It would be better to encode your pairs as explicit characters, like "34", "12" etc, or use a matrix. – joran Aug 05 '23 at 04:01
  • 1
    Finally found the question I knew existed referencing this [exact thing](https://stackoverflow.com/q/7591632/324364) (ironically asked by me of course). – joran Aug 05 '23 at 04:10

0 Answers0