library(tidyverse)
library(knitr)
library(kableExtra)
#install,packages("janitor")
library(janitor)
#install,packages("furniture")
library(furniture)
library(gghighlight)Analysis of Block Smash Churn Levels
Introduction
Block Smash is a popular mobile game that involves players clearing a board of different size and shape blocks within a limited number of moves. In this file we will analyse key aspects of the game and various connections between different elements of game play. The key goal of this research is to find what leads to churns in game play and how we may be able to counteract these issues.
#housekeeping
game <- read_csv("game_churn_assignment 03.11.25.csv")
game_clean <- game %>%
clean_names()
game_clean$used_moves <- washer(game_clean$used_moves, -1, -2, -3, -4, -5)How Frequent is Churning
The first piece of information to assess is the level of churning that Block Smash is experiencing.
ggplot(game_clean) +
geom_bar(mapping = aes(x = churn, fill = churn)) +
labs(title = "Count of Churns",
x = "Churn Status",
y = "Count") +
scale_fill_manual(name = "Churn Status",
values = c("#061b46", "#dc2b23")) +
theme_bw()We can clearly see that the majority of Block Smash players are not churning, however, more insightful information can be gained by a percentage breakdown of the churn rate.
perc_game_clean <- game_clean %>%
count(churn) %>%
mutate(perc = n / sum(n) * 100) #Percentage breakdown
ggplot(perc_game_clean, aes(x = "", y = perc, fill = churn)) +
geom_bar(position = "stack", stat = "identity") + #tells R not to agregate
labs(title = "How Frequent is Churning?",
x = "Responce",
y = "Percentage") +
scale_fill_manual(name = "Churn Status",
values = c("#061b46", "#dc2b23")) +
geom_text(aes(label = paste0(round(perc, 2),"%")), #paste0 adds % sign
position = position_stack(vjust = 0.5), size = 5, colour = "white") +
theme_bw()We can see here that approximately 1/3 of player churn from the game. This is impressive as on average mobile games experience over 90% churn rate before day 30. Click here for more information on the churn rates of mobile games. With this being said, there is always room for improvement.
What Levels Cause the Most Churns
We need to assess at what point in the game the players are deciding to churn to further analyse what is causing churning.
ggplot (data = game_clean) +
geom_histogram (mapping = aes(x = level, fill = ""),show.legend = FALSE) +
labs(title = "What Levels Lead to Churning?",
x = "Level",
y = "Count of Churns") +
scale_fill_manual(values = c("#061b46")) +
theme_bw()We can clearly see that the majority of players have churned from the game prior to level 2000. We can assume that the players who churned after this point left due to prolonged use or boredom. For this reason we will be assessing only the levels up to 2000 for the remainder of this assessment.
#housekeeping
top_game_clean <- game_clean %>%
filter(level <= 2000)We can see from the above histogram that the lower levels which are suppose to be designed to train the player as they progress and engage them may are the ones where players are most likely to drop off. Further Assessment of these levels is required to identify where the issue lies.
most_freq_lv_churn <- top_game_clean %>%
filter(churn == "Yes") %>%
group_by(level) %>%
summarise(num_churns = n()) %>%
arrange(desc(num_churns))
top_10_rows <- head(most_freq_lv_churn, 10)#takes top 10 rows
kable(top_10_rows,
col.names = c("Level", "Number of Churns"),
align = "rr",
format = "html",
caption = "Levels With The Highest Number of Churns",
table.attr = 'data-quarto-disable-processing = "true"') %>%
kable_styling(full_width = FALSE) %>%
row_spec(0, bold = TRUE, color = "white", background = "#091b44", underline = TRUE) %>%
row_spec(1:10, color = "black", background = "#c2efff") #Would not run when using colour in English/Irish spelling| Level | Number of Churns |
|---|---|
| 12 | 142 |
| 15 | 142 |
| 53 | 140 |
| 19 | 133 |
| 11 | 132 |
| 25 | 125 |
| 131 | 115 |
| 13 | 92 |
| 42 | 91 |
| 14 | 90 |
We can see from the above table that the levels with the most churns is 12 and 15. We can also see that all of the highest churns occur within the first 500 levels. These initial levels are typically designed as tutorial levels to teach the player how the game works and slowly introduce new elements. We can assume from the data that these tutorial levels are not progressing fast enough, leading to boredom and churning.
Churn Density Based on Level and Playtime
We ave looked at what levels are leading to churns but other factors of the game play are also significant. Next we will assess how churning is distributed based on levels and the playtime length of each player.
ggplot(top_game_clean, aes(x = level, y = play_time_sec, fill = churn)) +
geom_bin2d(bins = 20) + #creates heat map based on frequency of data within certain bins
labs(title = "Churn Density by Level and Playtime",
x = "Level",
y = "Play Time (sec)") +
scale_fill_manual(name = "Churn Status",
values = c("#091b44", "#dc2b23")) +
theme_bw()We can draw two clear conclusions from this heat map. First of all we can see that the shorter the play time, the more likely a player is to churn. Trying to find ways to encourage players to spend more time on each level is a key element to combating churning. Block Smash could consider testing the variety of game play based on churn levels, or try to introduce a reward system for playing the entire level.
We can also see that the player who spend the longest time on the initial levels are also likely to churn. For these initial levels we want to introduce quick, snappy wins that encourage the player to keep playing instead of spending so much time on the one level. Perhaps introducing hints after a few seconds of inactivity would help with this issue.
Why are players churning?
There are different elements of Block Smash that could be leading to churning including coins used, rolling losses, and scores.
stats_by_churn <- top_game_clean %>%
group_by(churn) %>%
summarise(avg_coins = round(mean(used_coins), 2),
avg_roll_loss = round(mean(rolling_losses), 2),
avg_score = round(mean(scores), 2))
kable(stats_by_churn,
col.names = c("Did they churn?", "Average Coins Spent", "Average Rolling Losses", "Average Score"),
align = "lrrr",
format = "html",
caption = "Factors Affecting Churn Rates",
table.attr = 'data-quarto-disable-processing = "true"') %>%
kable_styling(full_width = FALSE) %>%
row_spec(0, bold = TRUE, color = "white", background = "#091b44", underline = TRUE) %>%
row_spec(1:2, color = "black", background = "#c2efff")| Did they churn? | Average Coins Spent | Average Rolling Losses | Average Score |
|---|---|---|---|
| No | 1.16 | 12.16 | 3183.80 |
| Yes | 1.24 | 7.14 | 2895.57 |
From this table we can conclude that churning players spend slightly more coins on average, however their scores are lower. We could assume that players who churn do not feel as fulfilled because they spend more on the game but do not see the same result reflected in their scores. Block Smash should consider providing rewards for players who invest more money in the game as it leads to profit fro the company.
We can also see that rolling losses doesn’t appear to impact the likelihood of churning.
top_game_clean <- mutate(top_game_clean, scores_level = case_when(scores >= 7500 ~ "High Score",
scores >= 5000 ~ "Above Average Score",
scores >= 2500 ~ "Average Score",
TRUE ~ "Low Score"),
scores_level = factor(scores_level, levels = c("High Score",
"Above Average Score",
"Average Score",
"Low Score")))
ggplot(top_game_clean) +
geom_point(mapping = aes(x = used_coins, y = rolling_losses)) +
facet_grid(scores_level ~ churn,
labeller = label_wrap_gen(width = 9)) + #wraps the labels
labs(title = "Factors Affecting Churning", x = "Coins Used", y = "Number of Rolling Losses") +
theme_bw()Looking at this faceted scatter plot we can see that the people with a high score have a low number of rolling losses regardless of churn. The higher number of rolling losses actually appear to lead to fewer churns.
Time of Play In Relation to Churn
churn_yes <- top_game_clean %>%
filter(churn == "Yes") %>%
count()
hours_play <- top_game_clean %>%
group_by(hour) %>%
filter(churn == "Yes") %>%
summarise(churn = n())
ggplot(hours_play, aes(x = hour, y = churn)) +
geom_line() +
labs(title ="Start Time of Play in Relation to Churn Frequency", x = "Hour (24hr)", y ="Churn Count") +
theme_bw()From this line graph we can see the distribution of churns based on the hours at which players are active on the game. We can clearly see that the most likely time for churning is at 7pm (19hrs). This could indicate that players are using the game to unwind after work but are potentially not feeling engaged or get fed-up with the game. Block Smash could consider introducing a rewards wheel at this time, or introduce mini games that would take less time to play, but still discourage churning.
churn_by_day <- top_game_clean %>%
filter(churn == "Yes") %>%
count(day)
churn_by_day$day = factor(churn_by_day$day, levels = c("Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"))
ggplot(churn_by_day, aes(x = day, y = n, fill = day)) +
geom_col(show.legend = FALSE) +
labs(title = "Number of Churns by Day of Week",
subtitle = "There is little difference between the number of churns on days of the week.",
x = "Day of Week",
y = "Number of Churns") +
gghighlight(day == "Thursday") +
scale_fill_manual(name = "Day",
values = c("#dc2b23")) +
theme_bw()From the above bar chart we can see that there is only a slight difference in churns depending on the day of the week. The day with the most churns is Thursday, so Block Smash could consider creating some type of extra mini games that lead to rewards for a Thursday to engage players and reduce churning.
Conclusion
From our above assessment we can see that there is a potential relationship between the levels and the churn rate. Block Smash may want to run some test on these levels (level 12 and 15) and see where the issues lie. Is there an extra tutorial element that is not landing well with players? Is the level too difficult or too easy? Does it take too much thought to figure out where to put pieces? Block Smash may also want to conduct some qualitative research into the connection between churns and scores to see if it really is the lower scores that are causing players to leave the game.