emc123
emc123

Reputation: 33

Programming a reactive counter with if conditional loop statement in Shiny

I have been trying to create a dice/gambling simulator with Shiny, but I am having two problems (though both may be linked to the one error, I am not sure). I basically create a reactiveValue, set at 10000 (dollars) initially within the server, along with a sample( ) function that only draws from between 1-6 (for a six-faced die) and allows the user to choose the number of dice/tosses. I then set up an observeEvent where an if-loop determines that if the random numbers generated within the sample( ) function are equal to or greater than the number of dice that the user bet would show up, and so long as the reactiveValue remains about 1, then the user can double their "money." If their bet is less than what was generated by sample, then they lose half. If they lose so much that they are below one, then they aren't allowed to bet anymore or at least told that they are broke, but this isn't such an important part to the code.

Right now, I seem to be unable to get the if loop to work, as it throws the error: Warning: Error in if: missing value where TRUE/FALSE needed

 library(shiny)

 ui <- fluidPage(
  pageWithSidebar(
   titlePanel("Feelin' Lucky?"),

       sidebarPanel(
         p("In this simulation, you can select the number of dice you would like to roll,
           and then make a 'bet' on the numbers that will show up with every roll. If there are more faces 
           than the number you guessed, then you still win. If there are less faces, however, 
           you will lose 'money,' displayed at the top of the main panel. Give it a try and
           good luck!"),
        numericInput("dicenum", "Enter the number of dice to roll:", 1),
  numericInput("face", "What face do you think will be rolled?", 1),
  numericInput("bet", "How many of this face do you think will be rolled?", 1), 
  actionButton("go1", "GO!")
),
mainPanel(
  htmlOutput("the.dough"),
  htmlOutput("the.bet"),
  textOutput("results"),
  htmlOutput("results2"),
  htmlOutput("warning")
  )
 )
 )

   server <- function(input, output, session) {

    money <- 10000
    output$the.dough <- renderText(
    paste(money)
     )

   buttonValue <- reactiveValues(go1=FALSE)

   rv <- reactiveValues(money.tot = 10000)

   observeEvent(input$go1,{

isolate({buttonValue$go1=TRUE})
      the.roll <- sample(1:6, size = input$dicenum, replace=TRUE)
  the.face <- as.numeric(input$face) #Dice Face Bet
  amount <- as.numeric(input$bet)


output$warning <- renderText({

  goop <- sum(the.roll==the.face) 

  if ((goop >= amount) & (rv$money.tot>1)) {
    rv$money.tot <- sum(rv$money.tot, rv$money.tot*2-rv$money.tot)

    paste("Well-done! You won the bid! You now have: $", rv$money.tot)
  } else if ((goop < amount) & (rv$money.tot>1)) {
    rv$money.tot <- rv$money.tot-(rv$money.tot/2)
    paste("Darn! It looks like you lost the bid! You now have: $", rv$money.tot)
  } else if (rv$money.tot<1) {
    paste("You are broke! You cannot bid anymore money!")

  } else {
    NULL }
  })

  })
      }

          shinyApp(ui, server)

I have looked up what this means, but I cannot find a case that would exactly explain why it is doing it in my script, especially since the if loop works when written as a base R if loop, i.e. no reactivity or Shiny involved. Example of the working loop:

  rvv <- 10000

  face.guess <- 4
   throw <- sample(1:6, size = 10, replace = TRUE)
    guess.howmany <- 2

   if (sum(throw==face.guess)>=guess.howmany & rvv>1) {
    rvv <- sum(rvv, rvv*2-rvv)

   print("Woohoo!") 
    print(rvv)
  } else if (sum(throw==face.guess)<guess.howmany & rvv>1){
   print("Darn")
    rvv <- rvv-(rvv/2)
  print(rvv)
   } else if (rvv<1) {
  print("You are broke! You can't bid anymore money!") }

Other times, the if loop does seem to partially work, but only to jump to the last option, somehow reducing the starting reactiveValue to below 1 and declaring them broke on the first bid, which should not be possible.

My computer is wonky right now, too, so I apologise if there is syntax issues in the above - it could be partly from not being able to copy/paste properly at the moment.

Any help is much appreciated!

EDIT: Fixed code. I also figured out that when the user gets the bid right, there is a delay, and then it throws the above error. When they guess too high/wrong, it displays the last option (print("You are broke!")), which seems to suggest there is a problem explicitly with how I am invoking the other condition ("goop"). I just do not get what.

Upvotes: 0

Views: 209

Answers (1)

emc123
emc123

Reputation: 33

I figured out a fix for it: I basically had to take the if loop outside of the renderText( ), and instead imbed multiple renders within each step of the if loop. I copied the corrected server portion below. Probably not the most elegant fix, but it works as I wanted:

server <- function(input, output, session) {

   money <- 10000
   output$the.dough <- renderText(
    paste(money)
    )

  buttonValue <- reactiveValues(go1=FALSE)

  rv <- reactiveValues(money.tot = 10000)

  observeEvent(input$go1,{

    isolate({buttonValue$go1=TRUE})

    the.roll <- sample(1:6, size = input$dicenum, replace=TRUE)


    the.face <- as.numeric(input$face) #Dice Face Bet
    amount <- as.numeric(input$bet)
    goop <- sum(the.roll==the.face)

   if (isTRUE(goop >= amount) & isTRUE(rv$money.tot>1) & buttonValue$go1) {
      rv$money.tot <- sum(rv$money.tot, rv$money.tot*2-rv$money.tot)

      output$warning <- renderText({

       paste("Well-done! You won the bid! You now have: $", rv$money.tot)
        })
      } else if (isTRUE(goop < amount) & isTRUE(rv$money.tot>1) & buttonValue$go1) {
    rv$money.tot <- rv$money.tot-(rv$money.tot/2) 
    output$warning <- renderText({
    paste("Darn! It looks like you lost the bid! You now have: $", rv$money.tot)
    })

  } else if (isTRUE(rv$money.tot<1) & buttonValue$go1) {
    output$warning <- renderText({
    paste("You are broke! You cannot bid anymore money!")
    })
  } else {
    NULL }


output$results <- renderText(
  paste("You bid that there would be:", amount, "of the", the.face, "face.")

)
output$results2 <- renderText(
  paste("Actual Result:", as.numeric(sum(the.roll==the.face)), "of the", the.face)
)

  })

  }

Hope this helps anyone who is trying to do anything similar!

Upvotes: 0

Related Questions