Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import matplotlib.pyplot as plt
- import matplotlib.ticker as ticker
- import numpy as np
- import matplotlib
- print("Custom values have to be added into the program code itself. It should be relatively easy to find (line 59).")
- map_type = 0
- min_width = 5 # minimum width checked
- max_width = 50 # maximum width checked
- total_provinces = 2667 # Used for general scope calculation
- # Forested is an umbrella-term for forested terrains
- # It combines jungle and forest
- forested_base = 60
- forested_increase = 30
- # Harshlands is an umbrella-term for the harshest terrains
- # It combines Mountains and Marshes
- harsh_base = 50
- harsh_increase = 25
- # Steppe is an umbrella-term for all open landscapes.
- # It combines Plains, Hills, and Desert
- steppe_base = 70
- steppe_increase = 35
- urban_base = 80
- urban_increase = 40
- # You can change the weights as you like. Currently map_type = 0 are based on fabricensis's document and are therefore written as a divison.
- # Right now they are set up to be a sum of 1 for general scope, but that should not be necessary.
- # You may get wierd results if you have really large numbers tho (computer rounding errors).
- if map_type == 0: #General
- forested_weight = 703/total_provinces
- harsh_weight = 348/total_provinces
- steppe_weight = 1495/total_provinces
- urban_weight = 121/total_provinces
- elif map_type == 1: #Across the Rhine from Commanders in Conflict (CiC) - Speed5 Mod
- forested_weight = 46
- harsh_weight = 5
- steppe_weight = 63
- urban_weight = 11
- elif map_type == 2: #Sonnenblum from Commanders in Conflict (CiC) - Speed5 Mod
- forested_weight = 0
- harsh_weight = 17
- steppe_weight = 84
- urban_weight = 4
- ## IF YOU WANT TO MAKE YOUR OWN SCENARIO/COMPOSITION OF TERRAINS
- ## YOU CAN MAKE IT HERE:
- ## PUT IN YOUR OWN WEIGHTS, RUN THE PROGRAM AND ENTER 3, IT WILL THEN SHOW YOUR GRAPH FOR YOUR WEIGHTS
- elif map_type == 3: #Custom, put whatever value you want here, too many decimals or too high values are not recommended, here'S an approx. example for barbarossa
- forested_weight = 1.2
- harsh_weight = 0.1
- steppe_weight = 1
- urban_weight = 0.1
- elif map_type == 4: #north africa
- forested_weight = 0
- harsh_weight = 1
- steppe_weight = 3
- urban_weight = 0.05
- # Weights are from fabricensis, remember that certain terrains are combined because they share the same combat width modifiers
- # These could probably be set up a lot smarter:
- terrain_weight_list = [forested_weight, harsh_weight, steppe_weight, urban_weight]
- terrain_list = [forested_base, harsh_base, steppe_base, urban_base]
- terrain_increase_list = [forested_increase, harsh_increase, steppe_increase, urban_increase]
- # weights for the different directions. Not too difficult to add more.
- one_direction_weight = 1.8
- two_direction_weight = 2
- three_direction_weight = 1
- four_direction_weight = 0.2
- direction_weight_list = [one_direction_weight, two_direction_weight, three_direction_weight, four_direction_weight]
- """
- # removing empty weights from the terrain list
- newlist = []
- for i in terrain_weight_list:
- if i != 0:
- newlist.append(i)
- terrain_weight_list = newlist
- """
- def width_modifier(cw): #cw = combat width
- total_weight = 0
- current_modifier = 0 # used for the modifier of the unit later
- for terrain in range(len(terrain_weight_list)): # cycles through every terrain
- # terrain weight variable
- current_terrain_weight = terrain_weight_list[terrain]
- if current_terrain_weight > 0:
- for flanking_directions in range(len(direction_weight_list)): # cycles through 1, 2 or 3 direction attack
- current_width = 0 # current width occupied by our troops in the battle
- battle_width = (terrain_list[terrain] + terrain_increase_list[terrain]*flanking_directions) #combat width of the battle
- divisions_used = 0 # number of divions in combat
- # creates weight variable as flanking direction weight
- current_weight = direction_weight_list[flanking_directions]
- # adds terrain weight to the variable
- current_weight *= current_terrain_weight
- # Calculates how many divisions to be used in the combat
- while current_width+cw <= (battle_width*1.33) and not current_width >= battle_width: #0.33 not 0.30
- current_width += cw
- divisions_used += 1
- # creates modifier penalty used in the final calculation to find modifier/effectiveness, 1 meaning no penalty, 0.9 meaning 10% penalty
- modifier_penalty = 1
- # if it doesnt fit perfect, then calculate all penalties to the total modifier
- if battle_width % cw != 0:
- if current_width > battle_width: # checks for any overstacked combat width
- overstacked_width = current_width - battle_width
- #modifier_penalty += overstacked_width*0.011 #adds the overstacked width to the modifier penalty
- #modifier_penalty += (current_width/battle_width) * ((-1.5*(current_width/battle_width)+2.5)**2) # attempting to replicate fabricensis's calculation
- modifier_penalty *= current_width/battle_width*(1-overstacked_width/battle_width)
- elif current_width < battle_width:
- modifier_penalty *= (current_width/battle_width) #adds the unused width as modifier penalty
- # calculates penalty for any overstacked divisions
- if divisions_used > (5 + 3*flanking_directions):
- overstacked_divisions = divisions_used-(5 + 3*flanking_directions)
- if overstacked_divisions * 0.02 < 0.99: # makes sure to only do the calculation while the total is under 99% (because that is the limit for stacking penalty)
- modifier_penalty *= (1-overstacked_divisions * 0.02) #add the overstacked divisons to the modifier penalty
- else: # set the overstacking penalty to 99% if the actual value is over
- modifier_penalty *= 0.01
- # dont change unless you know what you are doing
- current_modifier += (1-modifier_penalty)*current_weight # adjusts the current modifier to add 1 - modifier penalties, will later divide by total to make average
- total_weight += current_weight
- return current_modifier/total_weight
- # Runs through all widths between 6 and 50 and makes them into y values of a future plot
- y_markers = []
- for y in range(min_width, max_width+1):
- y_markers.append(width_modifier(y)*100)
- ### Plot Customization
- fig, ax = plt.subplots()
- ax.plot(np.arange(min_width,max_width+1), y_markers)
- plt.rcParams['figure.dpi'] = 300
- for y in range(min_width, max_width+1):
- print((y,round(y_markers[y-min_width],2)))
- """<- Means commented out
- # If you want to count with decimals. Only relevant for Mass Assault doctrine or special mods
- # You must comment (put # in front of) the other parts out too (the ones that this code replaces)
- # WARNING: THIS DOES NOT LOOK PRETTY
- for y in np.arange(min_width, max_width+1, 0.1):
- y_markers.append(width_modifier(y)*100)
- x_list = np.arange(6,51,0.1)
- ax.plot(np.round(x_list, 2), y_markers)
- """
- # Grid types and colors
- ax.grid(color="black", which="major", linestyle="solid", linewidth = "1.1")
- ax.grid(color="slategray", which="minor", linestyle="solid", linewidth = "0.2")
- # Ticks
- ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
- ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
- ax.yaxis.set_major_locator(ticker.MultipleLocator(5))
- ax.yaxis.set_minor_locator(ticker.MultipleLocator(1))
- # Limt
- ax.set_xlim(min_width, max_width)
- ax.set_ylim(0, 15)
- plt.xlabel("Combat Width")
- plt.ylabel("Average Effectiveness")
- plt.gca().yaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f %%'))
- plt.savefig('cw_plot.png')
- # Title
- if map_type == 0:
- plt.title("Including Terrain Weights")
- elif map_type == 1:
- plt.title("Across the Rhine (From CiC, Speed5 Mod)")
- elif map_type == 2:
- plt.title("Sonnenblum (From CiC, Speed5 Mod)")
- elif map_type == 3:
- plt.title("Using Custom Terrain Weights")
- else:
- plt.title("Excluding Terrain Weights")
- plt.show()
- def width_modifier_noweight(cw,battle_width,flanking_directions): #cw = combat width
- current_width = 0 # current width occupied by our troops in the battle
- divisions_used = 0 # number of divions in combat
- # Calculates how many divisions to be used in the combat
- while current_width+cw <= (battle_width*1.33) and not current_width >= battle_width: #0.33 not 0.30
- current_width += cw
- divisions_used += 1
- # creates modifier penalty used in the final calculation to find modifier/effectiveness, 1 meaning no penalty, 0.9 meaning 10% penalty
- modifier_penalty = 1
- # if it doesnt fit perfect, then calculate all penalties to the total modifier
- if battle_width % cw != 0:
- if current_width > battle_width: # checks for any overstacked combat width
- overstacked_width = current_width - battle_width
- #modifier_penalty += overstacked_width*0.011 #adds the overstacked width to the modifier penalty
- #modifier_penalty += (current_width/battle_width) * ((-1.5*(current_width/battle_width)+2.5)**2) # attempting to replicate fabricensis's calculation
- modifier_penalty *= current_width/battle_width*(1-overstacked_width/battle_width)
- elif current_width < battle_width:
- modifier_penalty *= (current_width/battle_width) #adds the unused width as modifier penalty
- # calculates penalty for any overstacked divisions
- if divisions_used > (5 + 3*flanking_directions):
- overstacked_divisions = divisions_used-(5 + 3*flanking_directions)
- if overstacked_divisions * 0.02 < 0.99: # makes sure to only do the calculation while the total is under 99% (because that is the limit for stacking penalty)
- modifier_penalty *= (1-overstacked_divisions * 0.02) #add the overstacked divisons to the modifier penalty
- else: # set the overstacking penalty to 99% if the actual value is over
- modifier_penalty *= 0.01
- return 1-modifier_penalty
- direction_weight_list_norm = direction_weight_list[0]+direction_weight_list[1]+direction_weight_list[2]+direction_weight_list[3]
- # generate some example data
- #create a empty matrix in the shape of the spreadsheet
- matrix = np.zeros((21,max_width-min_width+1))
- targetwidths = [50,75,100,125,60,90,120,150,70,105,140,175,80,120,160,200]
- #iterate through the first 16 columns
- for j in range(0,16):
- for i in range(min_width,max_width+1):
- matrix[j][i-min_width]=width_modifier_noweight(i,targetwidths[j],j%4)*100
- #iterate through the next 4 columns
- for j in range(0,4):
- for i in range(min_width,max_width+1):
- for k in range(0,4):
- matrix[j+16][i-min_width]+=matrix[4*j+k][i-min_width]*direction_weight_list[k]
- matrix[j+16][i-min_width]*= 1/direction_weight_list_norm
- #compute the last column
- for i in range(min_width,max_width+1):
- matrix[20][i-min_width]=width_modifier(i)*100
- #slightly change to color distribution
- normalize = matplotlib.colors.Normalize(vmin=-3.5, vmax=10)
- plt.figure(figsize = (20,20))
- # plot the matrix as an image with an appropriate colormap
- plt.imshow(matrix.T, aspect ='auto', cmap="gist_rainbow_r", norm = normalize)
- # add the values
- for (i, j), value in np.ndenumerate(matrix):
- plt.text(i, j, "%.2f"%value, va='center', ha='center')
- plt.axis('off')
- plt.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement