R/appFunctions.R

Defines functions playCamelUp server generateUI placeGraph makeStackDistGraph makeBoardGraph getFillColor camelScale

Documented in generateUI playCamelUp server

camelScale <- function(useDensity = FALSE){
  if(useDensity){
    colors <- c("darkgreen", "blue", "yellow", "black", "orange")
  } else {
    colors <- c("darkgreen", "blue", "yellow", "white", "orange")
  }
  values <- c("Green", "Blue", "Yellow", "White", "Orange")
  names(colors) <- values

  return(scale_fill_manual(name = "Color",values = colors))
}

getFillColor <- function(color){
  if (color == "White") {
    return ("black")
  }
  if (color == "Green") {
    return("darkgreen")
  }
  return(tolower(color))
}

makeBoardGraph <- function(camelDF){
  plt <-  camelDF %>%
    filter(Space > 0) %>%
    ggplot(aes(x = .data$Space, y = .data$Height, fill = .data$Color))

  if(sum(camelDF$Space) == 0){
    plt <- plt + geom_blank()
  } else {
    plt <- plt + geom_tile(color = "black", size = 1, width = 0.9)
  }
  plt <- plt  +
    geom_vline(xintercept = 16.5) + #finish line
    ggplot2::coord_cartesian(xlim = c(1, 19), ylim = c(0.5,5.49)) +
    ggplot2::scale_x_continuous(breaks = 1:19) +
    ggplot2::scale_y_continuous(labels = c("0.00", "1.00", "2.00", "3.00", "4.00", "5.00"),
                                breaks = 0:5) +
    theme_classic(base_size = 16) +
    camelScale() +
    labs(title = "Game Board",
         x = "Space",
         y = "Height")

  return(plt)
}

makeStackDistGraph <- function(positionDF, color){
  nSims <- nrow(positionDF)/5

  prob_data <-  positionDF %>%
    filter(.data$Color == color) %>%
    group_by(.data$Color, .data$Space, .data$Height) %>%
    summarize(Probability = n()/nSims)

  text_data <- prob_data %>%
    group_by(.data$Color, .data$Space) %>%
    mutate(total_prob = sum(.data$Probability)) %>%
    arrange(-.data$Height) %>%
    slice(1)

  graphColor <- getFillColor(color)

  print(prob_data)
  print(text_data)
  plt <- prob_data %>%
    ggplot(aes(x = .data$Space, y = .data$Height, fill = .data$Probability)) +
    geom_tile(color = "black", size = 1, width = 0.9) +
    scale_fill_gradientn(colours=c("white", graphColor),
                         breaks=c(0,0.5,1),
                         limits=c(0,1)) +
    scale_alpha(range = c(0, 1)) +
    geom_text(data = text_data, mapping = aes(label = round(.data$total_prob, 3), x = .data$Space, y = .data$Height + 0.7), alpha = 1, size = 7) +
    geom_vline(xintercept = 16.5) + #finish line
    ggplot2::coord_cartesian(xlim = c(1, 19), ylim = c(0.5,5.9)) +
    ggplot2::scale_x_continuous(breaks = 1:19) +
    ggplot2::scale_y_continuous(labels = c("0.00", "1.00", "2.00", "3.00", "4.00", "5.00"),
                                breaks = 0:5) +
    theme_classic(base_size = 16) +
    # guides(alpha = FALSE) +
    # camelScale() +
    labs(title = "Distribution of Camel Position",
         x = "Space",
         y = "Height")
  return(plt)
}

placeGraph <- function(rankingDF, color){
  print(names(rankingDF))
  nSims <- nrow(rankingDF)/5
  rankingDF$place <- rep(1:5, nSims)
  plt <- rankingDF %>%
    filter(.data$Color == color) %>%
    group_by(.data$place) %>%
    summarize(prob = n()/nSims) %>%
    mutate(Color = color) %>%
    ggplot(aes(x = .data$place, y = .data$prob, fill = .data$Color)) +
    geom_bar(stat = "identity", width = 0.9) +
    ggplot2::geom_text(ggplot2::aes(label = round(.data$prob, 3)), position=ggplot2::position_dodge(width=0.9), vjust=-0.25, size = 7) +
    theme_classic(base_size = 16) +
    labs(fill = "Camel") +
    camelScale(TRUE) +
    labs(x = "End Ranking",
         y = "Probability",
         title = "Ranking Distribution") +
    ylim(c(0,1)) +
    xlim(0.5, 5.5)
  return(plt)

}

# Run the application

#' Play the game CamelUp
#'
#' @description Run CamelUp in a local web browser. Running locally allows for using the app without an internet connection and running in parallel on the local computer
#' @import ggplot2
#' @import dplyr
#' @import magrittr
#' @return an object representing the CamelUp app as generated by shiny::shinyApp
generateUI <- function(){
  ui <- fluidPage(
    titlePanel("Camel Up"),

    sidebarLayout(
      sidebarPanel(
        radioButtons("decisionButtons", "Move Type",
                     c("Move Camel","Place Leg Bet","Place Tile","Place Overall Bet"),
                     selected = "Move Camel"),
        conditionalPanel(condition = "input.decisionButtons == 'Place Leg Bet'",
                         selectInput('legbetcolor',
                                     "Camel Color:",
                                     c("","Yellow","Orange","Blue","Green","White"))
        ),
        conditionalPanel(condition = "input.decisionButtons == 'Place Tile'",
                         selectInput('tiletype',
                                     "Tile Type",
                                     c("","Plus","Minus")),
                         selectInput('tilespace',
                                     "Space Number:",
                                     c("", 1:16))
        ),
        conditionalPanel(condition = "input.decisionButtons == 'Place Overall Bet'",
                         selectInput('overallbettype',
                                     "Bet Type",
                                     c("","Winner", "Loser")),
                         selectInput('overallbetcolor',
                                     "Camel Color:",
                                     c("","Yellow","Orange","Blue","Green","White"))
        ),

        actionButton('submit',
                     "Go!"),
      ),


      mainPanel(
        tabsetPanel(type = "tabs",
                    tabPanel("View Game",
                             plotOutput("gameBoard"),
                             fluidRow(
                               column(width = 4, tableOutput("positionDF")),
                               column(width = 4, tableOutput("legBetDF")),
                               column(width = 4, tableOutput("purseDF")),
                               column(width = 4, tableOutput("diceDF"))
                             )
                    ),

                    tabPanel("Custom Setup",
                             actionButton("clearCustomBoard", "Clear Board"),
                             fluidRow(
                               column(width = 4, selectInput("customCamelColor", "New Camel Color:", choices = c("Yellow","Orange","Blue","Green","White"))),
                               column(width = 4, numericInput("customCamelSpace", "Space:", min = 1, max = 16, step = 1, value = 1)),
                               column(width = 4, checkboxInput("customCamelDie", "Die Present:")),
                               column(width = 4, selectInput("customBetsLeft", "Number of Leg Bets Remaining:", choices = 0:3))
                             ),
                             actionButton("customAddCamel", "Add Camel"),
                             plotOutput("customBoardGraph")
                    ),
                    tabPanel("Simulate",
                             fluidRow(
                               column(width = 4, actionButton('copyPlayBoard',
                                                              "Copy Board From Game Play")),
                               column(width = 4, actionButton('copyCustomBoard',
                                                              "Copy Board From Custom Board"))
                             ),
                             radioButtons("simDecision", "Move Type",
                                          c("Move Camel","Place Leg Bet","Place Tile","Place Overall Bet"),
                                          selected = "Move Camel"),
                             conditionalPanel(condition = "input.simDecision == 'Place Leg Bet'",
                                              selectInput('simlegbetcolor',
                                                          "Camel Color:",
                                                          c("","Yellow","Orange","Blue","Green","White"))
                             ),
                             conditionalPanel(condition = "input.simDecision == 'Place Tile'",
                                              selectInput('simtiletype',
                                                          "Tile Type",
                                                          c("","Plus","Minus")),
                                              selectInput('simtilespace',
                                                          "Space Number:",
                                                          c("", 1:16))
                             ),
                             conditionalPanel(condition = "input.simDecision == 'Place Overall Bet'",
                                              selectInput('simoverallbettype',
                                                          "Bet Type",
                                                          c("","Winner", "Loser")),
                                              selectInput('simoverallbetcolor',
                                                          "Camel Color:",
                                                          c("","Yellow","Orange","Blue","Green","White"))
                             ),
                             fluidRow(
                               column(width = 4, numericInput("nSims", "Number of Simulations", value = 1000, min = 100, max = 1000000, step = 100)),
                               column(width = 4, actionButton('simulateGame',
                                                              "Simulate!"))
                             ),
                             selectInput("simColor", "Select Camel of Interest", choices = c("Blue", "White", "Orange", "Yellow", "Green")),


                             plotOutput("boardToSim"),
                             plotOutput("stackDist"),
                             # plotOutput("spaceDist"),
                             plotOutput("placeDist")
                    )
        )
      )
    )
  )

  return(ui)

}




# Run the application

#' Play the game CamelUp
#'
#' @description Run CamelUp in a local web browser. Running locally allows for using the app without an internet connection and running in parallel on the local computer
#' @import ggplot2
#' @import dplyr
#' @import magrittr
#' @param input server input
#' @param output server output
#' @return an object representing the CamelUp app as generated by shiny::shinyApp
server <- function(input, output){
  gamePlay <- Game$new(19, 3, FALSE)


  simData <- data.frame() #initialize this
  rankingData <- data.frame()

  customGame <- Game$new(19, 3, FALSE)
  customBoard <- Board$new(19, FALSE)


  # init
  output$gameBoard <- renderPlot(makeBoardGraph(gamePlay$getCamelDF()))
  output$positionDF <- renderTable(gamePlay$getCamelDF() %>% arrange(-.data$Space, -.data$Height))
  output$legBetDF <- renderTable(gamePlay$getLegBetDF())
  output$purseDF <- renderTable(gamePlay$getPurseDF())
  # print(gamePlay$getBoard()$getDiceDF())
  # print(gamePlay$getBoard()$getNDiceRemaining())
  output$diceDF <- renderTable(gamePlay$getDiceRemDF() %>% arrange(.data$Dice_Remaining))
  output$boardToSim <- renderPlot(makeBoardGraph(customBoard$getCamelDF()))
  output$customBoardGraph <- renderPlot(makeBoardGraph(customBoard$getCamelDF()))




  # main panel
  observeEvent(input$submit,{
    if(input$decisionButtons == "Move Camel"){
      gamePlay$takeTurnMove()
    }
    if(input$decisionButtons == "Place Leg Bet"){
      gamePlay$takeTurnLegBet(input$legbetcolor)
    }
    if(input$decisionButtons == "Place Tile"){
      gamePlay$takeTurnPlaceTile(as.numeric(input$tilespace), input$tiletype == "Plus")
    }
    if(input$decisionButtons == "Place Overall Bet"){
      if(input$overallbettype == "Winner"){
        gamePlay$takeTurnPlaceOverallWinner(input$overallbetcolor)
      }
      if(input$overallbettype == "Loser"){
        gamePlay$takeTurnPlaceOverallLoser(input$overallbetcolor)
      }
    }

    output$gameBoard <- renderPlot(makeBoardGraph(gamePlay$getCamelDF()))
    output$purseDF <- renderTable(gamePlay$getPurseDF())

    output$positionDF <- renderTable(gamePlay$getCamelDF() %>% arrange(-.data$Space, -.data$Height))
    output$legBetDF <- renderTable(gamePlay$getLegBetDF())
    output$diceDF <- renderTable(gamePlay$getDiceRemDF() %>% arrange(.data$Dice_Remaining))

  })


  # sim panel
  observeEvent(input$copyPlayBoard, {
    # simBoard <- gamePlay$getBoard()
    output$boardToSim <- renderPlot(makeBoardGraph(gamePlay$getCamelDF()))
  })
  observeEvent(input$copyCustomBoard, {
    simBoard <- customBoard
    output$boardToSim <- renderPlot(makeBoardGraph(simBoard$getCamelDF()))
  })

  observeEvent(input$simulateGame, {
    thisBoard <- Board$new(customBoard)
    if(input$simDecision == "Place Tile"){
      p <- Player$new("Temp") # need player to place tile
      if(input$simtiletype == "Plus"){
        thisBoard$placePlusTile(as.integer(input$simtilespace), p)
      } else {
        thisBoard$placeMinusTile(as.integer(input$simtilespace), p)
      }
    }

    simObj <- Simulator$new(thisBoard)

    simData <- simObj$simulateDecision(input$simDecision %in% c("Move Camel", "Place Leg Bet", "Place Tile"), input$nSims) # bool toEndLeg and nSims
    positionDF <- simData$position
    rankingDF <- simData$ranking
    output$stackDist <- renderPlot(makeStackDistGraph(positionDF, input$simColor))

    output$placeDist <- renderPlot(placeGraph(rankingDF, input$simColor))

  })

  #custom panel
  observeEvent(input$clearCustomBoard, {
    customBoard$clearBoard()
    print(customBoard$getCamelDF())
    output$customBoardGraph <- renderPlot(makeBoardGraph(customBoard$getCamelDF()))
  })

  observeEvent(input$customAddCamel, {
    customBoard$addCustomCamel(input$customCamelColor, as.integer(input$customCamelSpace), input$customCamelDie, as.integer(input$customBetsLeft))
    print(customBoard$getCamelDF())
    output$customBoardGraph <- renderPlot(makeBoardGraph(customBoard$getCamelDF()))
  })
}

# Run the application

#' Play the game CamelUp
#'
#' @description Run CamelUp in a local web browser. Running locally allows for using the app without an internet connection and running in parallel on the local computer
#' @import ggplot2
#' @import dplyr
#' @import magrittr
#' @import shiny
#' @return an object representing the CamelUp app as generated by shiny::shinyApp
#' @export
playCamelUp <- function(){
  shiny::shinyApp(ui = generateUI(), server = server)
}

Try the CamelUp package in your browser

Any scripts or data that you put into this service are public.

CamelUp documentation built on Feb. 22, 2021, 9:08 a.m.