library(shiny)Warning: package 'shiny' was built under R version 4.4.3
# Safely evaluate expressions like "1/2", "8/4", etc.
try_eval <- function(expr_str) {
tryCatch({
result <- eval(parse(text = expr_str))
if (is.numeric(result)) result else NA
}, error = function(e) NA)
}
ui <- fluidPage(
titlePanel("Prime Checker and Factorial Calculator"),
# JS: Allow Enter key to submit the form
tags$script(HTML("
$(document).on('keypress', function (e) {
if (e.which == 13 && $('#user_input').is(':focus')) {
setTimeout(function() {
$('#check').click();
}, 50);
}
});
")),
# Responsive CSS styling with top padding
tags$style(HTML("
body {
font-family: 'Segoe UI', 'Helvetica Neue', sans-serif;
font-size: 16px;
text-align: center;
padding-top: 5vh;
}
.centered {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 20px;
}
#user_input {
font-size: 17px;
padding: 6px;
width: 200px;
text-align: center;
}
#check {
font-size: 17px;
height: 38px;
margin-left: 10px;
}
#prime_text, #bigfact {
font-size: 17px;
text-align: center;
}
#bigfact {
max-height: 100px;
max-width: 600px;
overflow-x: auto;
overflow-y: auto;
white-space: nowrap;
border: 1px solid #ddd;
padding: 10px;
background-color: #f9f9f9;
font-weight: normal;
margin: 10px auto 0 auto;
}
")),
# Main layout with centered input row
div(class = "centered",
tags$div(
style = "display: flex; align-items: center; gap: 10px;",
tags$label("Enter a number:", `for` = "user_input"),
tags$input(
id = "user_input",
type = "text",
value = ""
),
actionButton("check", "Submit")
),
br(), br(),
textOutput("prime_text"),
uiOutput("factorial_text")
)
)
server <- function(input, output, session) {
# Clear output when input is cleared
observe({
if (input$user_input == "") {
output$prime_text <- renderText("")
output$factorial_text <- renderUI(NULL)
}
})
observeEvent(input$check, {
input_raw <- input$user_input
if (input_raw == "") {
output$prime_text <- renderText("")
output$factorial_text <- renderUI(NULL)
return()
}
# Evaluate safely (supports fractions like 8/4)
num <- try_eval(input_raw)
if (is.na(num)) {
output$prime_text <- renderText("That's not a number! Try again.")
output$factorial_text <- renderUI(NULL)
return()
}
# Prime checker logic
is_prime <- function(n) {
if (n <= 1) return(FALSE)
if (n == 2 || n == 3) return(TRUE)
if (n %% 2 == 0) return(FALSE)
for (i in 3:floor(sqrt(n))) {
if (n %% i == 0) return(FALSE)
}
return(TRUE)
}
# Handle decimals or negatives
if (num != floor(num) || num < 0) {
output$prime_text <- renderText("❌ That's NOT a prime number!")
output$factorial_text <- renderUI("Undefined. Factorial is UNDEFINED.")
} else {
# Prime result
prime_result <- if (is_prime(num)) {
"✔️ That's a prime number!"
} else {
"❌ That's NOT a prime number!"
}
output$prime_text <- renderText(prime_result)
# Factorial or fallback
fact <- factorial(num)
if (is.infinite(fact)) {
approx_val <- exp(lgamma(num + 1))
if (is.infinite(approx_val)) {
output$factorial_text <- renderUI("Factorial too large to approximate.")
} else {
approx_fact <- format(approx_val, scientific = TRUE)
output$factorial_text <- renderUI({
paste0("Number exceeds computational limits. Factorial result is approximate:\n", approx_fact)
})
}
} else {
fact_str <- format(fact, scientific = FALSE)
fact_exp <- format(fact, scientific = TRUE)
if (num > 20 || nchar(fact_str) > 24) {
output$factorial_text <- renderUI({
tagList(
paste0("Factorial (short): ", fact_exp, "\n\n"),
div(id = "bigfact", fact_str)
)
})
} else {
output$factorial_text <- renderUI({
paste0("Factorial: ", fact_str)
})
}
}
}
})
}
# Launch the app
shinyApp(ui = ui, server = server)Shiny applications not supported in static R Markdown documents