Interactive: Coin flip

Author

Tom Coleman and Michelle Arnetta

Summary
Interactive coin flip for use in the guide on introduction to probability.
#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 340
library(shiny)
library(bslib)

# Hard-coded hex color for the button (a nice teal color)
BUTTON_COLOR <- "#3F6BB6"

ui <- page_fluid(
  title = "Coin flipper",
  
  card(
    card_header("Coin flipper"),
    card_body(
      # Use a row layout for landscape orientation
      layout_columns(
        col_widths = c(4, 4, 4), # Equal width columns
        
        # Left column: Description
        card(
          card_body(
            div(
              style = "display: flex; height: 100%; align-items: center; justify-content: center;",
              p("Click the button to flip a coin.", style = "font-size: 18px;")
            )
          )
        ),
        
        # Middle column: Coin display
        card(
          card_body(
            div(
              style = "text-align: center;",
              div(
                style = "font-size: 40px; line-height: 1.2; width: 150px; height: 150px; 
                       margin: 0 auto; border: 2px solid #ccc; border-radius: 50%;
                       display: flex; align-items: center; justify-content: center;
                       background-color: #f0f0f0;",
                textOutput("coinResult")
              )
            )
          )
        ),
        
        # Right column: Button
        card(
          card_body(
            div(
              style = "display: flex; height: 100%; align-items: center; justify-content: center;",
              actionButton("flipButton", "Flip Coin", class = "btn-lg", 
                          style = paste0("background-color: ", BUTTON_COLOR, "; color: white;"))
            )
          )
        )
      )
    )
  )
)

server <- function(input, output, session) {
  
  # Create a reactive value to store the current coin side
  coinResult <- reactiveVal(sample(c("HEADS", "TAILS"), 1))
  
  # Update the coin result when the flip button is clicked
  observeEvent(input$flipButton, {
    # Flipping animation - this is a simplified version using invalidateLater
    # to simulate the coin flipping
    for(i in 1:5) {
      invalidateLater(i * 100)
    }
    
    # Final result
    coinResult(sample(c("HEADS", "TAILS"), 1))
  })
  
  # Display the current coin result
  output$coinResult <- renderText({
    coinResult()
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Further reading

This interactive element appears in Guide: Introduction to probability. Please click this link to go to the guide.

Version history

v1.0: initial version created 04/25 by Michelle Arnetta (as part of a University of St Andrews VIP project) and tdhc.

This work is licensed under CC BY-NC-SA 4.0.

Mailing List



Feedback

Your feedback is appreciated and useful. Feel free to leave a comment here,
but please be specific with any issues you encounter so we can help to resolve them
(for example, what page it occured on, what you tried, and so on).