Little useless-useful R functions β Desk plant simulator
R-bloggers 2026-04-27
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
This time, we will create a Desk plant simulator. And for that we need a set of different functions 
Yes, we will grow a R plant in a simulation game with lots of twerks and hidden gems and ASCII art
And how this set of functions really work?
Storing the daily progress in an RDS. Before running set of functions, you will prepare a location to store the RDS file (environment variables and game play)
.plant_file <- path.expand("~/.r_desk_plant.rds")ASCII art was done by GPT for all the stages and it is so nice 
plant_art <- list( # Stage 0: Seed seed = c( " ", " ", " ", " ", " . ", " (.) ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ), # Stage 1: Sprout sprout = c( " ", " ", " ", " , ", " (') ", " | ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ), # Stage 2: Seedling seedling = c( " ", " ", " \\|/ ", " \\|||/ ", " ||| ", " ||| ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ), # Stage 3: Young plant young = c( " ", " \\~~/ ", " \\\\|// ", " \\|/ ", " ||| ", " ||| ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ),......Then you will have helper and main functions available. Complete code is available on my Github repository.
To run the game you will need to plant a new plant, water it, check the plant status and many others.
PlantNew() # Start a new plant (choose a name!)WaterPlant() # Water your plant (once per day)CheckPlant() # Full status reportPlant() # Quick view (just the art)
Here is an excerpt from the code:
hline <- function(char = "β", n = 40) strrep(char, n)# get current status of a plant / game playget_plant <- function(file = .plant_file) { if (file.exists(file)) { readRDS(file) } }# Save plant in RDS and all game play!save_plant <- function(plant, file = .plant_file) { saveRDS(plant, file)}# get growth infoget_stage <- function(points) { stage_idx <- max(which(growth_stages$min_points <= points)) growth_stages[stage_idx, ]}# get appropriate ASCII art plantget_plant_art <- function(plant) { if (plant$health <= 0) { return(plant_art$dead) } if (plant$health < 30) { return(plant_art$wilted) } stage <- get_stage(plant$points) plant_art[[stage$art_name]]}days_since <- function(date) { as.integer(Sys.Date() - as.Date(date))}# Messages for encouragement - Done with help of chatGPTget_encouragement <- function() { messages <- c( "Your plant appreciates you!", "Keep up the great work!", "You're a natural plant parent!", "Your R sessions make the plant happy!", "Photosynthesis in progress... ", "Growing strong, just like your R skills!", "The plant sends positive vibes!", "Another day, another leaf!", "Your dedication is blooming!", "Keep coding, keep growing!" ) sample(messages, 1)}# General healthget_health_message <- function(health) { if (health >= 90) { return("Thriving! Your plant is radiantly healthy!") } else if (health >= 70) { return("Healthy! Looking good!") } else if (health >= 50) { return("Okay. Could use some attention.") } else if (health >= 30) { return("Struggling. Please water me!") } else if (health > 0) { return("Critical! Water immediately or I'll die!") } else { return("Your plant has died. Start a new one with PlantNew()") }}# ---- main functionsPlantNew <- function(name = NULL, file = .plant_file) { existing <- get_plant(file) if (!is.null(existing) && existing$health > 0) { cat(" You already have a plant named '", existing$name, "'!\n", sep = "") cat(" Health: ", existing$health, "% | Stage: ", get_stage(existing$points)$name, "\n\n", sep = "") cat(" Are you sure you want to replace it? (yes/no): ") response <- tolower(readline()) if (response != "yes") { cat(" Keeping your existing plant. \n\n") } } # Get plant name if (is.null(name)) { suggestions <- c("Fernie Bennes", "Morgan Treeman", "Leaf Seinfeld", "Plantonio Banderas", "Elvis Parsley", "Kramerofern", "Snake Costanza", "Aloe NewmanVera", "Jungle Tribbiani") cat("\n") cat(" NEW PLANT!\n") cat(" Some name suggestions:\n") for (i in seq_along(suggestions)) { cat(sprintf(" %d. %s\n", i, suggestions[i])) } cat("\n Enter a name (or number, or press Enter for random): ") input <- readline() if (input == "") { name <- sample(suggestions, 1) } else if (grepl("^[0-9]+$", input)) { idx <- as.integer(input) if (idx >= 1 && idx <= length(suggestions)) { name <- suggestions[idx] } else { name <- input } } else { name <- input } } # Create new plant plant <- list( name = name, species = "R-Plant (Programmus enthusiasticus)", planted_date = Sys.Date(), last_watered = Sys.Date(), last_visited = Sys.time(), points = 0, health = 100, times_watered = 0, sessions = 0, achievements = character(0) ) save_plant(plant, file) cat("\n") cat(" β", hline("β", 44), "β\n", sep = "") cat(" β NEW PLANT CREATED! β\n") cat(" β", hline("β", 44), "β\n", sep = "") cat("\n") art <- plant_art$seed for (line in art) { cat(" ", line, "\n", sep = "") } cat("\n") cat("Name: ", name, "\n", sep = "") cat("Species: ", plant$species, "\n", sep = "") cat("Planted: ", format(Sys.Date(), "%B %d, %Y"), "\n", sep = "") cat("\n") cat("Tips:\n") cat(" --> Use WaterPlant() to water your plant\n") cat(" --> Use CheckPlant() to see its status\n") cat(" --> Visit often - your R sessions help it grow!\n") cat("\n")}# -- Water planting WaterPlant <- function(file = .plant_file) { plant <- get_plant(file) if (is.null(plant)) { cat("\n No plant found! Start one with PlantNew()\n\n") } if (plant$health <= 0) { cat("\n Your plant has died. Start a new one with PlantNew()\n\n") } # Check if already watered today last_water_date <- as.Date(plant$last_watered) today <- Sys.Date() if (last_water_date == today) { cat("\n") cat(" Already watered today!\n") cat(" Your plant doesn't want to drown. \n") cat(" Come back tomorrow!\n\n") return(invisible(plant)) } # Calculate bonus for consecutive days days_since_water <- days_since(plant$last_watered) water_points <- 15 health_gain <- 20 if (days_since_water == 1) { water_points <- water_points + 5 # Consecutive day bonus plant$achievements <- union(plant$achievements, "daily_waterer") } plant$last_watered <- today plant$points <- plant$points + water_points plant$health <- min(100, plant$health + health_gain) plant$times_watered <- plant$times_watered + 1 plant$last_visited <- Sys.time() # Check for achievements if (plant$times_watered == 10 && !"10_waters" %in% plant$achievements) { plant$achievements <- c(plant$achievements, "10_waters") } if (plant$times_watered == 50 && !"50_waters" %in% plant$achievements) { plant$achievements <- c(plant$achievements, "50_waters") } save_plant(plant, file) # Get stage info old_stage <- get_stage(plant$points - water_points) new_stage <- get_stage(plant$points) leveled_up <- new_stage$stage > old_stage$stage # Display cat("\n") cat(" β", hline("β", 44), "β\n", sep = "") cat(" β WATERING TIME! β\n") cat(" β", hline("β", 44), "β\n", sep = "") cat("\n") cat(" Watering '", plant$name, "'...\n\n", sep = "") art <- get_plant_art(plant) for (line in art) { cat(" ", line, "\n", sep = "") } cat(sprintf(" +%d growth points! (Total: %d)\n", water_points, plant$points)) cat(sprintf(" Health: %d%% %s\n", plant$health, strrep("β", plant$health %/% 10))) if (leveled_up) { cat("\n") cat(" β", hline("β", 44), "β\n", sep = "") cat(" LEVEL UP! Your plant is now: ", new_stage$emoji, " ", new_stage$name, "\n", sep = "") cat(" β", hline("β", 44), "β\n", sep = "") } cat("\n ", get_encouragement(), "\n\n", sep = "")}# -- Check on your desk plantCheckPlant <- function(file = .plant_file) { plant <- get_plant(file) if (is.null(plant)) { cat("\n No plant found! Start one with PlantNew()\n\n") } days_without_water <- days_since(plant$last_watered) if (days_without_water > 1 && plant$health > 0) { # Lose health for each day without water (after first day) health_loss <- (days_without_water - 1) * 10 plant$health <- max(0, plant$health - health_loss) } session_start <- Sys.getenv("R_SESSION_TMPDIR") # Unique per session visit_points <- 2 plant$points <- plant$points + visit_points plant$sessions <- plant$sessions + 1 plant$last_visited <- Sys.time() if (plant$sessions == 100 && !"100_sessions" %in% plant$achievements) { plant$achievements <- c(plant$achievements, "100_sessions") } save_plant(plant, file) # Get stage info stage <- get_stage(plant$points) days_alive <- days_since(plant$planted_date) # Display cat("\n") cat(" β", hline("β", 44), "β\n", sep = "") cat(" β PLANT STATUS REPORT β\n") cat(" β", hline("β", 44), "β\n", sep = "") cat("\n") # Show art art <- get_plant_art(plant) for (line in art) { cat(" ", line, "\n", sep = "") } cat("\n") cat(" ", hline("β", 44), "\n", sep = "") cat(sprintf(" Name: %s\n", plant$name)) cat(sprintf(" Age: %d day%s old\n", days_alive, if(days_alive != 1) "s" else "")) cat(sprintf(" Stage: %s %s\n", stage$emoji, stage$name)) cat(sprintf(" Points: %d / %d (next stage)\n", plant$points, ifelse(stage$stage < 7, growth_stages$min_points[stage$stage + 2], "MAX"))) cat(" ", hline("β", 44), "\n", sep = "") # Health bar health_bar <- paste0( strrep("β", plant$health %/% 10), strrep("β", 10 - plant$health %/% 10) ) cat(sprintf(" Health: [%s] %d%%\n", health_bar, plant$health)) cat(sprintf(" Status: %s\n", get_health_message(plant$health))) cat(" ", hline("β", 44), "\n", sep = "") # Water status days_since_water <- days_since(plant$last_watered) if (days_since_water == 0) { water_status <- " Watered today!" } else if (days_since_water == 1) { water_status <- " Watered yesterday" } else { water_status <- sprintf(" %d days without water!", days_since_water) } cat(sprintf(" Last water: %s\n", water_status)) cat(" ", hline("β", 44), "\n", sep = "") # Stats cat(sprintf(" Waterings: %d total\n", plant$times_watered)) cat(sprintf(" Visits: %d R sessions\n", plant$sessions)) # Achievements if (length(plant$achievements) > 0) { cat(" ", hline("β", 44), "\n", sep = "") cat(" Achievements:\n") achievement_names <- list( "daily_waterer" = "Daily Waterer - Watered on consecutive days", "10_waters" = "Hydration Helper - Watered 10 times", "50_waters" = "Water Master - Watered 50 times", "100_sessions" = "Dedicated Parent - 100 R sessions" ) for (ach in plant$achievements) { if (ach %in% names(achievement_names)) { cat(sprintf(" %s\n", achievement_names[[ach]])) } } } if (days_since_water >= 1 && plant$health > 0) { cat(" Don't forget to WaterPlant()!\n\n") } }# Quick status - just show the plantPlant <- function(file = .plant_file) { plant <- get_plant(file) if (is.null(plant)) { cat("\n No plant! Use PlantNew() to start.\n\n") } # Update health decay silently days_without_water <- days_since(plant$last_watered) if (days_without_water > 1 && plant$health > 0) { health_loss <- (days_without_water - 1) * 10 plant$health <- max(0, plant$health - health_loss) save_plant(plant, file) } stage <- get_stage(plant$points) art <- get_plant_art(plant) cat("\n") for (line in art) { cat(" ", line, "\n", sep = "") } cat("\n") cat(sprintf(" %s %s | Day %d | %d%% health\n", stage$emoji, plant$name, days_since(plant$planted_date), plant$health)) cat("\n")}PlantDelete <- function(file = .plant_file, confirm = TRUE) { plant <- get_plant(file) if (is.null(plant)) { cat("\n No plant to delete.\n\n") return(invisible(FALSE)) } if (confirm) { cat("\n Are you sure you want to delete '", plant$name, "'?\n", sep = "") cat(" This cannot be undone! (yes/no): ") response <- tolower(readline()) if (response != "yes") { cat(" Keeping your plant safe. \n\n") } } file.remove(file) cat("\n Goodbye, ", plant$name, "...\n", sep = "") cat(" Use PlantNew() to start fresh.\n\n")}#optional.onAttach <- function() { plant <- get_plant() if (!is.null(plant) && plant$health > 0) { stage <- get_stage(plant$points) message(sprintf(" Your plant '%s' (%s) is waiting! Use CheckPlant() to visit.", plant$name, stage$name)) }}# Run welcome checklocal({ plant <- get_plant() if (!is.null(plant) && plant$health > 0) { days_without_water <- days_since(plant$last_watered) stage <- get_stage(plant$points) cat(sprintf("\n '%s' says hello! (%s, Day %d)\n", plant$name, stage$name, days_since(plant$planted_date))) if (days_without_water >= 2) { cat(sprintf("It's been %d days without water!\n", days_without_water)) } cat("\n") }})PRO-tips:
- Water daily for bonus points
- Just running CheckPlant() gives small growth points
- Donβt forget to water or your plant will wilt!
- Health below 30% = wilted, Health 0% = dead
As always, the complete code is available on GitHub in Β Useless_R_function repository. The Plant simulator isΒ hereΒ (filename:Β plant_tame.R).
Check the repository for future updates!
Stay healthy and happy R-coding!
Disclaimer: all ASCII art was done by GPT, as well as plant names and ASCII game progress.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

