###Working Functions for BML Traffic Model

##initialization matrix##
#input is r=num rows, c=num cols,p=density of matrix (% of cells with a car in it)
bml.init <- function(r, c, p){
  m<-matrix(0,nrow=r,ncol=c)
  m<-apply(m,c(1,2),function(x) ifelse(sample(c(TRUE,FALSE),1,prob=c(p,1-p)),x<-sample(c(1,2),1),x<-0))
  return(m)
}

#in case need to assign for testing purposes   assign("m",m,pos=1)


##Eastward movement (1s)##
#move.e moves can move cars INTO the border column, but cannot move border cars to "wrap around".
move.e<-function(m){
  for(i in 1:nrow(m)){
    for(j in (ncol(m)-1):1){
      if(m[i,j] == 1 & m[i,j+1] == 0){
        m[i,j]=0
        m[i,j+1]=1
      }
    }
  }
  return(m)
}

#border.e will move cars on the border to the wraparound edge, but only those cars that were originally there
#in the refrence matrix (otherwise we could theoretically have a car be moved twice if it was in the 2nd to
#last column, once by move.e and then again by border.e)
border.e<-function(m,m.ref){
  for(i in 1:nrow(m)){
    if(m.ref[i,ncol(m)]==1 & m[i,1]==0){
      m[i,ncol(m)]=0
      m[i,1]=1
    }
  }
  return(m)
}

move.e.2<-function(m,m.ref){
  for(i in 1:nrow(m)){
    for(j in (ncol(m)-1):1){
      if(m.ref[i,j] == 1 & m[i,j] == 1 & m[i,j+1] == 0){
        m[i,j]=0
        m[i,j+1]=1
      }
    }
  }
  return(m)
}

#order of operations. move.e -> border.e (m is output of move.e) -> move.e.deux
test<-matrix(cbind(c(1,0,0,1,1),c(1,1,0,0,0),c(0,0,0,1,1),c(0,0,1,1,1),c(1,0,0,0,1)),nrow=5,byrow=TRUE)

bml.step.e<-function(m){
  m.ref<-m
  m<-move.e(m)
  m<-border.e(m,m.ref)
  m<-move.e.2(m,m.ref)
  return(m)
}

##Northward movement (2s)##
#move.n can move cars north into the top border (first row), but cannot wrap them around. SECOND VERSION WORKS
move.n<-function(m){
  for(j in 1:ncol(m)){
    for(i in 2:nrow(m)){
      if(m[i,j] == 2 & m[i-1,j] == 0){
        m[i,j]=0
        m[i-1,j]=2
      }
    }
  }
  return(m)
}

#border.n wraps around those cars on the border only from the refrence matrix (should be called after move.n)
border.n<-function(m,m.ref){
  for(j in 1:ncol(m)){
    if(m.ref[1,j]==2 & m[nrow(m),j]==0){
      m[1,j]=0
      m[nrow(m),j]=2
    }
  }
  return(m)
}

move.n.2<-function(m,m.ref){
  for(j in 1:ncol(m)){
    for(i in 2:nrow(m)){
      if(m.ref[i,j] == 2 & m[i,j] == 2 & m[i-1,j] == 0){
        m[i,j]=0
        m[i-1,j]=2
      }
    }
  }
  return(m)
}

#Sundays version of the NORTHWARD movement function.
#order of operations. move.n -> border.n (m is output of move.n) -> move.n.deux
#m.ref is defined at very beginiing of the bml.step.n fucntion, see bml.step.e for refrence.

test.n<-matrix(cbind(c(2,2,0,0,2),c(2,0,0,2,2),c(2,2,0,0,0),c(2,2,2,0,0),c(2,0,0,0,2)),nrow=5,byrow=FALSE)

bml.step.n<-function(m){
  m.ref<-m
  m<-move.n(m)
  m<-border.n(m,m.ref)
  m<-move.n.2(m,m.ref)
  return(m)
}

##One complete Movement Step (1s and 2s)## 
bml.step<-function(m){
  m.grid<-m
  m<-bml.step.e(m)
  m<-bml.step.n(m)
  grid.new<-identical(m.grid,m)
  return(list(m,grid.new))
}

#Write the simulation function. The simulation function takes as its inputs the parameters of the initial
#system state (eg; size and proportion of cells with cars in them). It then outputs the initial grid, the
#final grid, and the number of steps needed to reach gridlock. It iterates through 5000 steps; if gridlock
#is reached before that, it will indicate how many steps were taken. If not, it will return 5000.

bml.sim <- function(r, c, p){
  m.initial<-bml.init(r,c,p)
  m.1<-bml.step(m.initial)
  m<-m.1[[1]]
  gridlock<-m.1[[2]]
  iterations<-5000
  for(i in 2:iterations){
    m.1<-bml.step(m)
    m<-m.1[[1]]
    gridlock<-m.1[[2]]
    if(gridlock == TRUE) break
  }
  if(i == 5000){
    i = "System gridlock free after 5000 iterations"
  }
  else if(i != 5000){
    i = paste(paste("System reached gridlock after", i, sep=" "),"iterations",sep=" ")
  }
  return(list(m.initial,m,i))
}