library(tidyverse)
library(gganimate)

NUMPLAYERS = 45
ROUNDS = 5000
INITWEALTH = 45

#initialize the bank
#columns wealths of the NUMPLAYERS players
#rows show wealths of each of the ROUNDS ticks of the clocks
bank = matrix(0, nrow = ROUNDS, ncol = NUMPLAYERS)
bank[1,] =  c(rep(INITWEALTH, NUMPLAYERS))

#function to give a dollar to someone other than oneself
get_recipient = function(player) {
  sample(setdiff(1:NUMPLAYERS, player), 1)}

#execute trades and update the ledger 
for (i in 2:ROUNDS) {
  #every player with wealth chooses another person to receive a buck
  recipients = sapply(which(bank[i - 1,] > 0), get_recipient)

  #table of the dollars owed each person
  count_table = table(recipients)
  
  #get the indices of the people owed money
  indices = as.integer(names(count_table))
  
  #everyone gives up a dollar, unless they are at zero
  bank[i,] = ifelse(bank[i - 1,] > 0, bank[i - 1,] - 1, bank[i - 1,])
  
  #selected people receive dollars
  bank[i, indices] = bank[i, indices] + count_table
}

####################Animate it
#Make a suitable long data frame
df = as.data.frame(bank)
names(df) = 1:NUMPLAYERS
df = df %>%
  mutate(frame = 1:ROUNDS) %>%
  gather(person, wealth, 1:NUMPLAYERS) %>%
  mutate(person = as.numeric(person)) %>%
  arrange(frame) %>%
  group_by(frame) %>%
  mutate(rank = rank(wealth, ties.method = "random")) %>%
  ungroup() %>%
  gather(histtype,playerid,c(person,rank)) %>%
  mutate(histtype = sprintf("Ordered by %s", histtype))

p <- ggplot(df, aes(x = playerid, y = wealth, frame = frame, fill=histtype)) +
  theme_minimal() +
  theme(panel.grid.major.x = element_blank(),
        panel.grid.minor = element_blank()) +
  geom_rect(aes( xmin = playerid - .4, xmax = playerid +.4, ymin = 0, ymax = wealth)) +
  scale_x_continuous(breaks = 1:NUMPLAYERS) +
  coord_cartesian(xlim = c(0, NUMPLAYERS), y = c(0, 5 * INITWEALTH)) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  labs(x='players',y='dollars') +
  facet_wrap( ~ histtype,ncol=1) +
  theme(legend.position = "none")
p

#set options for the animation package. Need ImageMagick installed on your computer
animation::ani.options(nmax = ROUNDS,
                       convert = 'C:\\Program Files\\ImageMagick-7.0.6-Q16')
#save the movie
gganimate(p, "dollar_stacked.mp4", interval = .01)