#0. define ship, distribution matrix X, and probability matrix.
#dominator
ship <- c(1500, 250/0.6, 2500/0.6, 200, 78, 5, 78*2, 0.6)
#damage
d <- 50
h <- 50
#constants
omega <- 0.05
kappa <- 0.15
a_0 <- ship[4]
n <- ship[6]
#X
x <- matrix(c(0,1/30,1/30,1/30,0,1/30,1/15,1/15,1/15,1/30,1/30,1/15,1/15,1/15,1/30,1/30,1/15,1/15,1/15,1/30,0,1/30,1/30,1/30,0),5,5)
#draw a random cell from a custom cumulative distribution function
custrandom <- function(dist){
return(which(dist > runif(1,0,1))[1])
}
range <- 1000
#basic calculations
#this computes a weighted average but can be defined using linear algebra due to what we're working with
poolarmor <- function(matrix, index){
pooledarmor <- 0
for(i in 1:5) pooledarmor <- pooledarmor + 15* (x[i,] %*% matrix[,index+i-3])
return(pooledarmor[[1]])
}
#compute armor damage reduction factor
chi <- function(matrix, index) return(max(kappa,h/(h+max(a_0*omega,poolarmor(matrix,index)))))
#deal damage, the linear algebra way
#for some ungodly reason R insists on transposing the vector
#i refers to row of armor cell, j to column, r to counterfactual vector (star)
damage <- function(damagematrix,i,j,r) return((d * x[i,] %*% damagematrix[(j-2):(j+2),r])[[1]])
create_b_star <- function(armormatrix){
B_star_vector <- vector(mode="double",length=(n+8))
for (i in 1:n) {
B_star_vector[4+i] <- chi(A,4+i)
}
B_star <- diag(B_star_vector)
return(B_star)
}
star_matrix <- function(matrixA,matrixB,r) {
A_star <- matrix(0,nrow=length(matrixA[,1]),ncol=length(matrixA[1,]))
for (i in 5:(length(matrixA[1,])-5)){
for (j in 1:(length(matrixA[,1]))){
A_star[i,j] <- max(0, matrixA[i,j] - damage(matrixB, i, j
, r))
}
}
return(A_star)
}
star_matrix_wonky_hull_dmg <- function(matrixA,matrixB,r) {
A_star <- matrix(0,nrow=length(matrixA[,1]),ncol=length(matrixA[1,]))
hulldamage <- 0
for (j in 5:(length(matrixB[1,])-2)){
for (i in 1:(length(matrixA[,1]))){
hulldamage <- hulldamage + max(0, damage(matrixB, i, j, r) - matrixA[i,j])
A_star[i,j] <- max(0, matrixA[i,j] - damage(matrixB, i, j, r))
}
}
A_star[1,1] <- hulldamage
#dumb hack
return(A_star)
}
#sd
serror <- 50
#spread
spread <- 10
#how much is the visual arc of the ship in rad?
shipangle <- ship[5]/(2* pi *range)
#how much is the visual arc of a single cell of armor in rad?
cellangle <- shipangle/ship[6]
#distribution
anglerangevector <- 0
anglerangevector <- vector(mode="double", length = ship[6]+1)
anglerangevector[1] <- -shipangle/2
for (i in 1:(length(anglerangevector)-1)) anglerangevector[i+1] <- anglerangevector[i]+cellangle
#now convert it to pixels
anglerangevector <- anglerangevector*2*pi*range
# this function generates the shot distribution (a bhattacharjee distribution for the
#non-trivial case)
hit_distribution <- function(upperbounds, standard_deviation, spread){
vector <- vector(mode="double", length = length(upperbounds)+1)
if (standard_deviation == 0){
if (spread == 0){
vector[1] <- 0
for (j in 2:(length(upperbounds))) {
#if both spread and standard deviation are 0 then all shots hit 1 cell. this should be so even if
#the ship has an even number of cells to prevent ships with even no. cells appearing tougher which is not
#the case in the real game most likely
if ((upperbounds[j] >= 0) & (upperbounds[j-1] < 0)) vector[j] <- 1
}
#return part of a box
} else {
vector[1] <- min(1,max(0,(upperbounds[1]+spread))/(2*spread))
for (j in 2:(length(upperbounds))) vector[j] <- min(1,max(0,(upperbounds[j]+spread))/(2*spread)) - min(1,max(0,(upperbounds[j-1]+spread))/(2*spread))
vector[length(upperbounds)+1] <- 1-min(1,max(0,(upperbounds[length(upperbounds)]+spread))/(2*spread))
}
} else {
if (spread != 0){
vector[1] <- hit_probability_coord_lessthan_x(upperbounds[1], standard_deviation, spread)
for (j in 2:(length(upperbounds))) vector[j] <- (hit_probability_coord_lessthan_x(upperbounds[j], standard_deviation, spread)-hit_probability_coord_lessthan_x(upperbounds[j-1], standard_deviation, spread))
vector[length(upperbounds)+1] <- (1-hit_probability_coord_lessthan_x(upperbounds[length(upperbounds)], standard_deviation, spread))
} else {
#if spread is 0 but standard deviation is not 0 we have a normal distribution
vector[1] <- pnorm(upperbounds[1],0,standard_deviation)
for (j in 2:(length(upperbounds))) vector[j] <- pnorm(upperbounds[j],0,standard_deviation) - pnorm(upperbounds[j-1], mean=0, sd=standard_deviation)
vector[length(upperbounds)+1] <- 1-pnorm(upperbounds[length(upperbounds)], mean=0, sd=standard_deviation)
}
}
return(vector)
}
G <- function(y) return(y*pnorm(y) + dnorm(y))
#a is the SD of the normal distribution and b is the parameter of the uniform distribution
hit_probability_coord_lessthan_x <- function(z, a, b) return(a/2/b*(G(z/a+b/a)-G(z/a-b/a)))
p <- hit_distribution(anglerangevector,serror,spread)
A <- matrix(ship[4]/15,5,ship[6]+4)
#pad A
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(c(0,0,0,0,0),A)
A <- cbind(c(0,0,0,0,0),A)
B_star <- create_b_star(A)
p_cum <- vector(mode = "double", length=length(p))
p_cum[1] <- p[1]
for (i in 2:length(p)) p_cum[i] <- sum(p[1:i])
augprob <- c(0,0,0,p,0,0,0)
#now the complex model
A <- matrix(ship[4]/15,5,ship[6]+4)
#pad A
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(c(0,0,0,0,0),A)
A <- cbind(c(0,0,0,0,0),A)
B_star <- create_b_star(A)
C <- B_star
hulldamage <- 0
hullhp <- ship[1]
shot <- 0
matrixlist <- list()
for(r in 1:n) matrixlist[[r]] <-star_matrix_wonky_hull_dmg(A,B_star,r+4)
modelresults <- data.frame(hullhp=double(),shot=integer(),series=integer())
while (hullhp > 0){
shot <- shot+1
#compute hull damage according to C at previous step
for(r in 1:n) hulldamage <- hulldamage + matrixlist[[r]][1,1]*p[r+1]
hullhp <- hullhp - hulldamage
#then, create the counterfactuals that a shot hits armor matrix A based on
#unadjusted damage reduction calculation
B_star <- create_b_star(A)
# for(r in 1:n) matrixlist[[r]] <-star_matrix_wonky_hull_dmg(A,B_star,r+2)
for(r in 1:n) matrixlist[[r]] <-star_matrix_wonky_hull_dmg(A,B_star,r+4)
#2 rows of zeroes and 2 rows of padding
hulldamage <- 0
for(index in 1:n){
rightside <- 0
pooledprob <- 0
#compute probability weighted average of counterfactuals
for (grr in -4:4) {
if((index+grr+4) >0){ if(index+grr+4 <= n){
rightside <- rightside + (chi(matrixlist[[index+grr+4]],index+4))*augprob[index+4+grr]
pooledprob <- pooledprob + augprob[index+4+grr]
}
}
}
C[index+4,index+4] <- (C[index+4,index+4]*(1-pooledprob) + rightside)
#possible corrections?
# C[index+4,index+4] <- max(kappa,C[index+4,index+4])
# C[index+4,index+4] <- min(C[index+4,index+4],h/(h+omega*a_0))
print(C[index+4,index+4])
}
#now, compute the matrix C (next armor damage reduction)
for(r in 1:n) matrixlist[[r]] <-star_matrix_wonky_hull_dmg(A,C,r+4)
#then, update A accordning to C.
A <- A*(p[1]+p[length(p)])
for(r in 1:n) A <- A + matrixlist[[r]]*p[r+1]
A[1,1] <- 0
for(i in 1:length(A[1,]))for(j in 1:length(A[,1])) A[j,i] <- max(A[j,i],0)
# B_star <- create_b_star(A)
modelresults <-rbind(modelresults, c(hullhp, shot, i))
}
shotlimit <- shot
colnames(modelresults) <- c("hullhp","shot","series")
modelresults$series <- 1000
#now the simple model
A <- matrix(ship[4]/15,5,ship[6]+4)
#pad A
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(c(0,0,0,0,0),A)
A <- cbind(c(0,0,0,0,0),A)
B_star <- create_b_star(A)
hullhp <- ship[1]
shot <- 0
matrixlist <- list()
simplemodelresults <- data.frame(hullhp=double(),shot=integer(),series=integer())
while (hullhp > 0){
shot <- shot+1
#2 rows of zeroes and 2 rows of padding
for(r in 1:n) matrixlist[[r]] <-star_matrix_wonky_hull_dmg(A,B_star,r+4)
hulldamage <- 0
#probability list has list item 1 as missing
for(r in 1:n) hulldamage <- hulldamage + matrixlist[[r]][1,1]*p[r+1]
hullhp <- hullhp - hulldamage
A[1,1] <- 0
A <- A*(p[1]+p[length(p)])
for(r in 1:n) A <- A + matrixlist[[r]]*p[r+1]
for(i in 1:length(A[1,]))for(j in 1:length(A[,1])) A[j,i] <- max(A[j,i],0)
B_star <- create_b_star(A)
simplemodelresults <-rbind(simplemodelresults, c(hullhp, shot, i))
}
colnames(simplemodelresults) <- c("hullhp","shot","series")
simplemodelresults$series <- 750
generatetestdata <-1
if(generatetestdata == 1){
#generate simulated data using 100 models
testresults <- data.frame(hullhp=double(),shot=integer(),series=integer())
hullhp <- ship[1]
for (i in 1:100){
A <- matrix(ship[4]/15,5,ship[6]+4)
#pad A
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(A,c(0,0,0,0,0))
A <- cbind(c(0,0,0,0,0),A)
A <- cbind(c(0,0,0,0,0),A)
B_star <- create_b_star(A)
hullhp <- ship[1]
shot <- 0
while (shot <= shotlimit){
shot <- shot+1
A<-star_matrix_wonky_hull_dmg(A,B_star,custrandom(p_cum)+3)
hullhp <- hullhp - A[1,1]
A[1,1]<-0
B_star <- create_b_star(A)
testresults <-rbind(testresults, c(hullhp, shot, i))
}
}
colnames(testresults) <- c("hullhp","shot","series")
}
library(ggplot2)
testresiduals <- testresults
testresiduals <- rbind(testresiduals, cbind(aggregate(hullhp ~ shot, testresiduals, FUN=median), series=500))
testresiduals <- rbind(testresiduals, modelresults)
testresiduals <- rbind(testresiduals, simplemodelresults)
testresiduals$hullhp <- testresiduals$hullhp/ship[1]
for (i in 1:shotlimit) {
testresiduals[which(testresiduals$shot==i),1] <- testresiduals[which(testresiduals$shot==i),1] - modelresults[which(modelresults$shot==i),][[1]]/ship[[1]]
}
ggplot(testresiduals,aes(x=shot,y=hullhp*100,group=series,col=series,linewidth=floor(series/500)))+
geom_line()+
scale_colour_viridis_c()+
scale_linewidth_continuous(range=c(0.1,2))+
labs(x="Shot",y="Hull hp residual %")+
theme(legend.position="none")