3

Typically a Shiny server would spawn separate instances for individual users, so that multiple people can individually use the same app at the same time. This answer shows how to make a simple multi-user chat room using Shiny, and this answer explains how multiple users can connect to the same session via direct IP. I got the chat example to work, two users both see the messages immediately as they're being sent, and as such can chat to one another.

I'm wondering if it is at all possible to use Shiny for an (experiment) scenario where two users, interacting with one another, would see different GUI elements on their respective screens, and different output, depending on who's turn it is to "play". For example, if user1 is the "starting player", he would see three buttons and click one of them, a relevant image would pop up for user2 (not for user1), user2 clicks a button (that he thinks matches the image), and then a relevant image pops up for user1, and user1 clicks a "correct"/"incorrect" button to send feedback; they should not see who clicks which button, nor the image the other one sees (if actually hiding GUI elements is tricky, graying out/disabling them intermittently is also fine, as long as they don't see what the other does).

Or more graphically:

round 1
user1                   user2
director                guesser

what they see, step by step:
1. [three buttons]      [ (blank) ]
2. [clicks one]         [ ]
3  [ ]                  [sees an image & 3 buttons]
4. [ ]                  [clicks a button]
5. [sees image,2 butns] [ ]
6. [clicks button]      [ ]
7. [ ]                  [sees the message "correct" or "incorrect"]

round 2
user1                   user2
guesser                 director
1. [ ]                  [three buttons]
...
...

And for the next round they switch roles, and so on, for multiple rounds.

I've seen similar experimental scenarios implemented using Javascript (jsPsych, nodegame) and Python (psychopy, oTree), but I'm looking to understand if it's possible to do it in Shiny, and if so, how.

user3554004
  • 1,044
  • 9
  • 24
  • Have a look at this example https://shiny.rstudio.com/gallery/chat-room.html – Pork Chop Jun 05 '19 at 15:10
  • @PorkChop thanks, though that is almost identical to the example I linked to above; the question is whether it is possible to make two users see different things (as opposed to the chat window, which looks the same for everybody, because that's how chat works). – user3554004 Jun 05 '19 at 15:17
  • yes It is possible, based on the user you can use `show` and `hide` from `shinyjs` or shiny native `showTab` – Pork Chop Jun 05 '19 at 15:29

1 Answers1

4

I had the same challenge a couples of years ago when i implemented "Risk" (the board game) as a shiny app.

A quick outline how i approached it back then:

If you use the session parameter in the server function, you can create a local/secret reactiveValue() within that session / for that user.

Next you can set reactiveValues() outside the server function for "global infos" that are accessible across sessions.

The latter approach is probably the more surprising one as we are usually "forced" to define reactive behaviour within the server function. But it works, see the example below.

Reproducible example:

library(shiny)

ui <- fluidPage({
  uiOutput("moreControls")
})

global <- reactiveValues(info  = "public info: I can be seen by everyone", amountUser = 0, userIdToPlay = 1)

server <- function(input, output, session) {
  local <- reactiveValues(secret = paste0("My secret number is ", sample(6, 1)))
  
  observe({
    isolate(global$amountUser <-  global$amountUser + 1)
    isolate(local$userId <- global$amountUser)
  })
  
  observeEvent(input$finish,{
    global$userIdToPlay <- 3 - global$userIdToPlay # assumes two players (for MVE)
  })
  
  output$moreControls <- renderUI({
    global$userIdToPlay
    isolate({
      if(local$userId == global$userIdToPlay){
        return(
          tagList(
            h2("my time to play"),
            selectInput("a", "b", letters),
            actionButton("finish", "finish")
          )
        )
      }else{
        return(
          h2("not my time to play")
        )
      }
    })
  })
  
}
shinyApp(ui, server)
Tonio Liebrand
  • 17,189
  • 4
  • 39
  • 59
  • Cool; I can see why it should work (clever approach!), but for some reason this example doesn't - when I run it in RStudio, it starts (in Rstudio's preview window), but when I try to open it in a browser, it keeps waiting/loading for forwever. Other shiny apps run just fine on my machine and brower (e.g. the chat app linked above). Since there's no error, I can't tell what's the issue either, trying to look into it... – user3554004 Jun 08 '19 at 16:51
  • 1
    interesting observation, i made an edit. Now it works in my browser (Chrome). Btw. you can test playing rstudio viewer vs browser ;) – Tonio Liebrand Jun 08 '19 at 18:59
  • Yep, now it works, seems isolating the userID did the trick. That is awesome, now I'll need to figure out the message sending and other things, but that certainly is a very good place to start! – user3554004 Jun 08 '19 at 19:03
  • cant you use the chat room that @Pork Chorp linked for message sending or you require "secret / bilateral" messages? Ah and an upvote is appreciated ;) – Tonio Liebrand Jun 11 '19 at 11:05
  • Yes, in terms of messages, something like the one of these chat-apps should do, I just haven't had the time to get to it yet. – user3554004 Jun 11 '19 at 13:13