Thinking about what Liral said, that brute force is sometimes faster, I decided to apply brute force since I think the best I can do without a few more analysis courses is present a piecewise solution (since the continuous replacement functions for the piecewise I figured out were pretty non-trivial).
So here is the brute-force solution in hopefully human-readable code using our previous functions, slightly augmented.
#create a vector containing angles from -180 to 180
aucvector <- seq(-180,180)
#standard things
#dominator, hullhp, shieldregen, shieldmax, startingarmor, widthinpixels, armorcells, shieldwidth, shieldefficacy, shieldupkeep
ship <- c(14000, 500, 10000, 1500, 220, 12, 440, 1.0, 200)
#engagementrange
range <- 1000
#fudge factor
errorsd <- 0.05
#the fudge factor should be a function of range (more error in position at greater range), but not a function of weapon firing angle, and be expressed in terms of pixels
error <- errorsd*range
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
#we add the special cases to this function
hit_probability_coord_lessthan_x <- function(z, a, b){
if(a > 0 & b > 0) return(a/2/b*(G(z/a+b/a)-G(z/a-b/a)))
if(a > 0 & b == 0) return(pnorm(z,0,a))
if(a == 0 & b > 0) return(min(1,b-abs(z)))
if(a == 0 & b == 0) {
if(z < 0) return(0) else return(1)
}
}
#compute maximum and minimum mean coordinates
#weapons: damage, facing (deg), tracking range (deg), spread
weapon1 <- c(10,-30,60,10)
weapon2 <- c(10,60,30,5)
weapon3 <- c(20,0,60,0)
weapon4 <- c(20,90,60,0)
weapon5 <- c(5,0,180,0)
#data frame of weapons
weapons <- data.frame()
for (i in 1:5) weapons <- rbind(weapons,get(paste("weapon",i,sep="")))
colnames(weapons) <- c("damage","facing","trackingrange","spread")
weapons
#now compute maximum and minimum mean by computing facing+trackingrange/2-spread/2 and facing-trackingrange/2+spread/2
weapons <- cbind(weapons, maxmean=(weapons$facing+weapons$trackingrange/2-weapons$spread/2))
weapons <- cbind(weapons, minmean=(weapons$facing-weapons$trackingrange/2+weapons$spread/2))
#function to transform hit coordinates so mean is aligned with 0, meaning we can use our hit dist fucntion
transform_hit_coord <- function(angle, weapon) return(max(weapon$minmean, min(weapon$maxmean,angle)))
#necessary transformations
segment_to_deg <- function(seg) return(seg/range*360/pi)
deg_to_segment <- function(deg) return(deg*range/360*pi)
#now we have all that we need, so compute the expected auc for degree facings
transformed_angle <- function(angle, weapon) return(angle-transform_hit_coord(angle,weapon))
sumauc <- function(angle) {
summed_auc <- 0
shipwidth <- segment_to_deg(ship[5])/2
derror <- segment_to_deg(error)
for (i in 1:length(weapons[,1])){
summed_auc <- summed_auc + hit_probability_coord_lessthan_x(deg_to_segment(transformed_angle(angle,weapons[i,])+shipwidth),error,deg_to_segment(weapons[i,4]))-
hit_probability_coord_lessthan_x(deg_to_segment(transformed_angle(angle,weapons[i,])-shipwidth),error,deg_to_segment(weapons[i,4]))
}
return(summed_auc)
}
applied <- sapply(aucvector,FUN=sumauc)
plot(sapply(aucvector,FUN=sumauc),xlab="angle",ylab="dps")
abline(v=median(which(applied == max(applied))))
(vertical line = choice of rotation)
The main idea is transform coordinates of the enemy ship to the coordinates of the dist median (ie. enemy ship angle from angle wrt our ship to angle from dist median such that angle of dist median = 0), which you find by considering it is equal to target's center when in tracking range, max turret turn angle - spread/2 when above tracking range, and min turret turn angle + spread/2 when below tracking range, since the mean of the uniform dist is also the mean of the convolved dist. Then you select the median rotation of those which correspond to max dps values.
In this case we had 5 guns, with the following parameters
#weapons: damage, facing (deg), tracking range (deg), spread
weapon1 <- c(10,-30,60,10)
weapon2 <- c(10,60,30,5)
weapon3 <- c(20,0,60,0)
weapon4 <- c(20,90,60,0)
weapon5 <- c(5,0,180,0)
To continue from here, you then save the angle of choice and use the normal hit distribution function, but passing the cells' boundary angles through the transform function for each weapon to get the final hit distribution over the enemy ship from our guns at that angle.
Another plot: this ship has 11 guns that can track over 90 degree intervals and are spaced at 36 degree intervals. (note: the x axis is fixed here, was not centered in last).
#weapons: damage, facing (deg), tracking range (deg), spread
weapon1 <- c(10,-180,90,0)
weapon2 <- c(10,-144,90,0)
weapon3 <- c(10,-108,90,0)
weapon4 <- c(10,-72,90,0)
weapon5 <- c(10,-36,90,0)
weapon6 <- c(10,0,90,0)
weapon7 <- c(10,180,90,0)
weapon8 <- c(10,144,90,0)
weapon9 <- c(10,108,90,0)
weapon10 <- c(10,72,90,0)
weapon11 <- c(10,36,90,0)
This shows that taking the naive median of the max points is actually not satisfactory. Instead we should prefer to choose specifically the middle one (or lower middle, if two exist). Should also apply a little rounding. There is also a problem that the angle is not considered properly, in that angles over 180 do not map to -180+(angle-180) etc. That requires some rewriting paying attention to the cyclical nature of angles but does not change the basic idea. Here is one way to do it.
aucvector <- seq(-360,360)
angles <- seq(-180,180)
applied <- sapply(aucvector,FUN=sumauc)
for (i in 1:360) applied[i] <- applied[i]+applied[i+360]
applied <- applied[1:361]
applied <- c(tail(applied,181),head(applied,180))
plot(applied,x=angles,xlab="angle",ylab="dps")
abline(v=angles[which(round(applied,3) == round(max(applied),3))[ceiling(length(which(round(applied,3) == round(max(applied),3)))/2)]])
For a final test some completely random weapons
weapon1 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon2 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon3 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon4 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon5 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon6 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon7 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon8 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon9 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
weapon10 <- c(runif(1,0,10),runif(1,-180,180),runif(1,0,360),runif(1,0,30))
Edit: fixed wraparound, also I'm adding the fixed script as an attachment to this.
[attachment deleted by admin]