Guest User

Optimal Combat Width Calculator Corrected 3

a guest
Mar 5th, 2023
289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.09 KB | Software | 0 0
  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3.  
  4. terrain_weight_question = int(input("0 for no terrain weights, 1 for terrain weights: "))
  5.  
  6. min_width = 6 # minimum width checked
  7. max_width = 50 # maximum width checked
  8.  
  9. total_provinces = 2667
  10.  
  11. # You can change the weights as you like. Currently they are based on fabricensis's document and are therefore written as a divison.
  12. # Right now they are set up to be a sum of 1, but that is not really necessary
  13.  
  14. # IS COMBINED WITH JUNGLE
  15. forest_base = 84
  16. forest_increase = 42
  17. forest_weight = 703/total_provinces
  18.  
  19. hills_base = 80
  20. hills_increase = 40
  21. hills_weight = 401/total_provinces
  22.  
  23. marsh_base = 78
  24. marsh_increase = 26
  25. marsh_weight = 51/total_provinces
  26.  
  27. mountain_base = 75
  28. mountain_increase = 25
  29. mountain_weight = 297/total_provinces
  30.  
  31. # IS COMBINED WITH DESERT
  32. plains_base = 90
  33. plains_increase = 45
  34. plains_weight = 1094/total_provinces
  35.  
  36. urban_base = 96
  37. urban_increase = 32
  38. urban_weight = 121/total_provinces
  39.  
  40. # Weights are from fabricensis, remember that forest and jungle & plains and desert are combined when changing the weights
  41.  
  42.  
  43.  
  44. # These could probably be set up a lot smarter:
  45. terrain_weight_list = [forest_weight, hills_weight, marsh_weight, mountain_weight, plains_weight, urban_weight]
  46. terrain_list = [forest_base, hills_base, marsh_base, mountain_base, plains_base, urban_base]
  47. terrain_increase_list = [forest_increase, hills_increase, marsh_increase, mountain_increase, plains_increase, urban_increase]
  48.  
  49.  
  50. # weights for the different directions. Not too difficult to add more.
  51. one_direction_weight = 1
  52. two_direction_weight = 2
  53. three_direction_weight = 1
  54.  
  55. direction_weight_list = [one_direction_weight, two_direction_weight, three_direction_weight]
  56.  
  57. # removing empty weights from the terrain list
  58. newlist = []
  59. for i in terrain_weight_list:
  60.     if i != 0:
  61.         newlist.append(i)
  62.  
  63. terrain_weight_list = newlist
  64.  
  65. def width_modifier(cw): #cw = combat width
  66.    
  67.     current_modifier = 0 # used for the modifier of the unit later
  68.     test_number = 0 # number of the current test (basically n)
  69.    
  70.    
  71.    
  72.     for terrain in range(len(terrain_weight_list)): # cycles through every terrain
  73.        
  74.         # adds terrain weights if user said so
  75.         if terrain_weight_question == 1:
  76.             current_terrain_weight = terrain_weight_list[terrain]
  77.         else:
  78.             current_terrain_weight = 1
  79.            
  80.            
  81.            
  82.         for flanking_directions in range(3): # cycles through 1, 2 or 3 direction attack
  83.             current_width = 0 # current width occupied by our troops in the battle
  84.             battle_width = (terrain_list[terrain] + terrain_increase_list[terrain]*flanking_directions) #combat width of the battle
  85.             divisions_used = 0 # number of divions in combat
  86.            
  87.            
  88.             # creates weight variable as flanking direction weight
  89.             current_weight = direction_weight_list[flanking_directions]
  90.                
  91.             # adds terrain weight to the variable
  92.             current_weight *= current_terrain_weight
  93.        
  94.        
  95.        
  96.             # Calculates how many divisions to be used in the combat
  97.             while current_width+cw < (battle_width*1.22) and not current_width > battle_width:
  98.                 current_width += cw
  99.                 divisions_used += 1
  100.                
  101.             # creates modifier penalty used in the final calculation to find modifier/effectiveness
  102.             modifier_penalty = 0
  103.            
  104.             # calculates penalty for any overstacked divisions
  105.             if divisions_used > (8 + 4*flanking_directions):
  106.                 overstacked_divisions = divisions_used-(8 + 4*flanking_directions)
  107.                 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)
  108.                     modifier_penalty = overstacked_divisions * 0.02 #add the overstacked divisons to the modifier penalty
  109.                 else: # set the overstacking penalty to 99% if the actual value is over
  110.                     modifier_penalty = 0.99
  111.                
  112.                
  113.            
  114.             # if it doesnt fit perfect, then calculate all penalties to the total modifier
  115.             if battle_width % cw != 0:
  116.                
  117.                 if current_width > battle_width: # checks for any overstacked combat width
  118.                     overstacked_width = current_width - battle_width
  119.                     modifier_penalty += overstacked_width * 0.015 #adds the overstacked width to the modifier penalty
  120.                
  121.                
  122.                 elif current_width < battle_width:
  123.                     modifier_penalty += (battle_width-current_width)*0.01 #adds the unused width as modifier penalty
  124.                
  125.            
  126.             # actual calculation for adding the modifier for this cycle into the average
  127.             current_modifier = (current_modifier*test_number + ((1-modifier_penalty)*current_weight)) / (test_number + current_weight) # adjusts the current modifier average to add 1 - modifier penalties
  128.                
  129.                
  130.             test_number += 1
  131.            
  132.     return current_modifier
  133.  
  134.  
  135. # Runs through all widths between 6 and 50 and makes them into y values of a future plot
  136. y_markers = []
  137. for y in range(min_width, max_width+1):
  138.     y_markers.append(width_modifier(y))    
  139.  
  140.  
  141. # Plot Customization
  142. plt.grid(color="black", linestyle="solid")  
  143. plt.xticks(np.arange(10, 46, 5))
  144. plt.xlim(6, 50)
  145. plt.ylim(0.775, 0.975)
  146. plt.xlabel("Combat Width")
  147. plt.ylabel("Average Modifier/Effectiveness")
  148. if terrain_weight_question == 1:
  149.     plt.title("Width Modifier w/ Terrain Weights")
  150. else:
  151.     plt.title("Width Modifier w/out Terrain Weights")
  152.  
  153.  
  154. # Creates and shows plot
  155. plt.plot(np.arange(6,51), y_markers)
  156. plt.show()
  157.  
  158.  
  159. # Manual width checking
  160. for i in range(3):
  161.     print("Input combat width to check exact value. This will disappear after 3 uses.", 3-i, "uses left")
  162.     test_width = int(input(""))
  163.     print(width_modifier(test_width))
  164.    
Tags: python hoi4
Add Comment
Please, Sign In to add comment