R/mfl_scoring.R

Defines functions mfl_allrules .fn_parsedivide .fn_parsemultiply ff_scoring.mfl_conn

Documented in ff_scoring.mfl_conn mfl_allrules

## ff_scoring (MFL) ##

#' Get a dataframe of scoring settings, referencing the "all rules" library endpoint.
#'
#' @param conn a conn object created by `ff_connect()`
#'
#' @examples
#' \donttest{
#' try({ # try only shown here because sometimes CRAN checks are weird
#'   ssb_conn <- ff_connect(platform = "mfl", league_id = 54040, season = 2020)
#'   ff_scoring(ssb_conn)
#' }) # end try
#' }
#'
#' @seealso <http://www03.myfantasyleague.com/2020/scoring_rules#rules>
#'
#' @describeIn ff_scoring MFL: returns scoring settings in a flat table, one row per position per rule.
#'
#' @export
ff_scoring.mfl_conn <- function(conn) {
  df <- mfl_getendpoint(conn, "rules") %>%
    purrr::pluck("content", "rules", "positionRules")

  if (is.null(df$positions)) {
    df <- df %>%
      tibble::tibble() %>%
      tidyr::unnest_wider(1)
  }

  if (!is.null(df$positions)) {
    df <- df %>% tibble::as_tibble()
  }


  df <- df %>%
    dplyr::mutate(
      # convert each nested list of rules to tibble by bind_rows
      # so that it can be unnested nicely
      # see ffscrapr#344 for history
      rule = purrr::map(.data$rule, dplyr::bind_rows)
    ) %>%
    tidyr::unnest("rule") %>%
    tidyr::unnest(c("points", "event", "range")) %>%
    tidyr::separate_rows("positions", sep = "\\|") %>%
    dplyr::left_join(mfl_allrules(conn), by = c("event" = "abbrev")) %>%
    dplyr::mutate_at(c("is_player", "is_team", "is_coach"), ~ as.logical(as.numeric(.x))) %>%
    dplyr::mutate(
      points_type = ifelse(stringr::str_detect(.data$points, "\\*|\\/"), "each", "once"),
      points = purrr::map_if(.data$points, grepl("\\/", .data$points), .fn_parsedivide),
      points = purrr::map_if(.data$points, grepl("\\*", .data$points), .fn_parsemultiply),
      points = as.double(.data$points)
    ) %>%
    dplyr::select(
      "pos" = "positions",
      "points",
      "range",
      "event",
      "points_type",
      "short_desc",
      "long_desc"
    )

  return(df)
}

#' Parse the scoring rule chars into numeric.
#'
#' This may not be "precisely" what MFL does, but I'd rather give workable and consistent datatypes.
#'
#' ie MFL sometimes uses the "divide" notation for a threshold/bins type thing.
#' @noRd
#' @keywords internal
.fn_parsemultiply <- function(points) {
  as.numeric(gsub("\\*", "", points))
}

#' @noRd
#' @keywords internal
.fn_parsedivide <- function(points) {
  x <- strsplit(points, "/") %>%
    unlist() %>%
    as.numeric()

  return(x[[1]] / x[[2]])
}

#' MFL rules library - memoised via zzz.R
#'
#' @keywords internal
mfl_allrules <- function(conn) {
  conn$league_id <- NULL

  df <- conn %>%
    mfl_getendpoint("allRules") %>%
    purrr::pluck("content", "allRules", "rule") %>%
    tibble::tibble() %>%
    tidyr::unnest_wider(1) %>%
    dplyr::mutate_if(is.list,
                     ~replace(.x, lengths(.x) == 0, NA_character_) %>%
                       unlist() %>%
                       unname()) %>%
    dplyr::mutate_all(as.character) %>%
    dplyr::select(
      "abbrev" = "abbreviation",
      "short_desc" = "shortDescription",
      "long_desc" = "detailedDescription",
      "is_player" = "isPlayer",
      "is_team" = "isTeam",
      "is_coach" = "isCoach"
    )

  return(df)
}

Try the ffscrapr package in your browser

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

ffscrapr documentation built on Feb. 16, 2023, 10:55 p.m.