Advertisement
EditorRUS

UFOEnemy.py

Dec 29th, 2015
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.73 KB | None | 0 0
  1. import random
  2. import copy
  3. from math import ceil
  4.  
  5. data = [ [], [] ]
  6.  
  7. #CONST section
  8. TRIES = 10000
  9. MAIN_MENU = 0
  10. WEAP_MENU = 1
  11. ENEM_MENU = 2
  12.  
  13. WEAPONS = 0
  14. ENEMIES = 1
  15.  
  16. WEAPON_NAME = 0
  17. WEAPON_POWER = 1
  18. BULLETS = 2
  19. DEVIATION = 3
  20.  
  21. ENEMY_NAME = 0
  22. HEALTH = 1
  23. FRONT = 2
  24. SIDE = 3
  25. REAR = 4
  26. UNDER = 5
  27. SUSCEPT = 6
  28.  
  29. STATE = MAIN_MENU
  30.  
  31. # Format strings section
  32. STR_SIMPLE_TRY_AVERAGE = "It would take on average {0} +- {1} shot/s to kill that enemy"
  33. STR_SIMPLE_TRY_MINIMUM = "Minimum amount of {0} shot/s is needed to kill that enemy. {1:2%} of enemies were killed that way"
  34. STR_SIMPLE_TRY_INVINCIBLE_STATUS = "It appears the enemy is almost/completely invincible to that weapon (at least {0} shots were done)"
  35. STR_ADVANCED_TRY_DATA = "{0:>4} +- {1:>4} | {2:>2}"
  36. STR_ADVANCED_TRY_WEAPON_DAM = "({0} DAM)"
  37. STR_ADVANCED_TRY_ENEMY_DATA = "({0} HP) ({1}):"
  38. STR_SHOW_WEAPONS_TAB_ARRANGE = "{0:>3}|{1:>20}|{2:>5}|{3:>5}|{4:>7}|"
  39. STR_SHOW_WEAPONS_TAB_ARRANGE_LEN = 3+20+5+5+7+5
  40. STR_BORDER_OF_DATA_AND_NAMES = "="
  41. STR_SHOW_ENEMIES_SUSCEPT_NAME = "{0:>20}|"
  42. STR_SHOW_ENEMIES_SUSCEPT_LEN  = 3+3+19
  43. STR_SHOW_ENEMIES_ENEMY_DATA = "{0:>3}|{1:>20}|{2:>5}|{3:>5}|{4:>5}|{5:>5}|{6:>5}"
  44. STR_SHOW_ENEMIES_ENEMY_DATA_LEN = 3+20+5+5+5+5+5+6
  45.  
  46. # Service
  47. NOT_NEGATIVE = 2**0
  48. POSITIVE     = 2**1
  49. BOUNDARY      = 2**2
  50.  
  51. def persistent_input(question, the_type, rules=0, boundary=[]):
  52.     val = 0
  53.     while True:
  54.         try:
  55.             val = eval('{0}(input(\'{1}\'))'.format(the_type, question))     # Metacode
  56.         except ValueError:
  57.             continue
  58.         else:
  59.             try:
  60.                 if (rules & NOT_NEGATIVE) and val < 0: continue
  61.                 if (rules & POSITIVE) and val <= 0: continue
  62.                 if (rules & BOUNDRY) and val in range(boundary[0], boundary[1]+1): continue
  63.             except:
  64.                 pass # Not appliable
  65.             return val
  66.  
  67. # Main simulation
  68. def perform(armor, weapon, susp, health, bullets_shot, deviation):
  69.     result_data = []
  70.     # 0 - average shots
  71.     # 1 - deviation
  72.     # 2 - kills
  73.     # 3 - best shots
  74.     # 4 - chance of best shots
  75.    
  76.     higher_mul = 1 + deviation/100
  77.     lower_mul  = max(1 - deviation/100, 0)
  78.    
  79.     minimum = ceil(health / (bullets_shot*(higher_mul*weapon*susp-armor)))
  80.    
  81.     kills = 0
  82.  
  83.     curHP = health
  84.     curAP = armor
  85.     statistical_data = []
  86.     shots = 0
  87.     best_kills = 0
  88.    
  89.     for attempt in range(TRIES):
  90.         for bullet in range(bullets_shot):
  91.             rolled_damage = random.randint(int(weapon*lower_mul), int(weapon*higher_mul))
  92.             rolled_damage = int(rolled_damage * susp)
  93.             curHP -= max(rolled_damage - curAP, 0)
  94.             curAP -= max(0.1 * (rolled_damage - curAP), 0)
  95.             curAP = max(curAP, 0)
  96.         shots += 1
  97.         if shots > 0.01 * TRIES: # If it requires more than 1/100 of TRIES it is probably impossible
  98.             return result_data # Blank data
  99.         if curHP <= 0:
  100.             kills += 1
  101.             if shots <= minimum:
  102.                 best_kills += 1
  103.             curHP = health
  104.             curAP = armor
  105.             statistical_data.append(shots)
  106.             shots = 0
  107.        
  108.  
  109.     standard_deviation = 0
  110.     median = 0
  111.     if len(statistical_data):
  112.         median = 0
  113.         for data in statistical_data:
  114.             median += data
  115.         median = median / len(statistical_data)
  116.  
  117.         standard_deviation = 0
  118.         for data in statistical_data:
  119.             standard_deviation += (data - median)**2
  120.         standard_deviation = standard_deviation / len(statistical_data)
  121.         standard_deviation = standard_deviation**0.5
  122.        
  123.     result_data.append(round(TRIES / kills, 1))
  124.     result_data.append(round(standard_deviation, 1))
  125.     result_data.append(kills)
  126.  
  127.     result_data.append(minimum)
  128.     result_data.append(best_kills / kills)
  129.    
  130.     return result_data
  131.  
  132. # Simulation section
  133. def simple_try():
  134.     armor = persistent_input('Armor: ', 'int', NOT_NEGATIVE)
  135.     weapon = persistent_input('Weapon power: ', 'int', POSITIVE)
  136.     susp  = persistent_input('Susceptibility: ', 'float', NOT_NEGATIVE)
  137.     health = persistent_input('Health: ', 'int', POSITIVE)
  138.     bullets_shot = persistent_input('Projectiles shot at once: ', 'int', POSITIVE)
  139.     expl = persistent_input("Maximum damage deviation from 100% in percents (100% -> 0%-200%): ", 'int', NOT_NEGATIVE)
  140.  
  141.     simple_data = perform(armor, weapon, susp, health, bullets_shot, expl)
  142.     if len(simple_data):
  143.         print(STR_SIMPLE_TRY_AVERAGE.format(simple_data[0], simple_data[1]))
  144.         print(STR_SIMPLE_TRY_MINIMUM.format(simple_data[3], simple_data[4]))
  145.     else:
  146.         print(STR_SIMPLE_TRY_INVINCIBLE_STATUS.format(ceil(0.01 * TRIES)))
  147.     print()
  148.  
  149. def advanced_try():
  150.     # Data
  151.     # [0] = weapons[]
  152.     #       [weapon name, weapon power, bullets_shot, deviation of damage]
  153.     # [1] = enemy list[]
  154.     #       [enemy name, health, front armor, side armor, rear armor, under armor, susceptibility[]]
  155.  
  156.     sim_data = []
  157.  
  158.     # For each weapon a list
  159.     # The list has A lists
  160.     # A = amount of enemies
  161.     # Each list consists of 12 entries
  162.     # 1 + 4X - Average
  163.     # 2 + 4X - Deviation
  164.     # 3 + 4X - Minimum
  165.  
  166.     basic_entry = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # Basic list, 12 entries
  167.     weapon_entry = [] # Data of affecting each weapon on each enemy
  168.     for alpha in range(len(data[ENEMIES])):
  169.         weapon_entry.append(copy.deepcopy(basic_entry))
  170.     for alpha in range(len(data[WEAPONS])):
  171.         sim_data.append(copy.deepcopy(weapon_entry))
  172.  
  173.     for alpha in range(len(data[WEAPONS])):
  174.         for beta in range(len(data[ENEMIES])):
  175.             weapon = data[WEAPONS][alpha]
  176.             enemy  = data[ENEMIES][beta]
  177.  
  178.             HP = enemy[HEALTH]
  179.             FA = enemy[FRONT]
  180.             SA = enemy[SIDE]
  181.             RA = enemy[REAR]
  182.             UA = enemy[UNDER]
  183.             S  = enemy[SUSCEPT][alpha]
  184.  
  185.             P  = weapon[WEAPON_POWER]
  186.             B  = weapon[BULLETS]
  187.             D  = weapon[DEVIATION]
  188.  
  189.             FAData = perform(FA, P, S, HP, B, D)
  190.             SAData = perform(SA, P, S, HP, B, D)
  191.             RAData = perform(RA, P, S, HP, B, D)
  192.             UAData = perform(UA, P, S, HP, B, D)
  193.  
  194.             if len(FAData) > 0:
  195.                 sim_data[alpha][beta][0] = round(FAData[0], 1)
  196.                 sim_data[alpha][beta][1] = round(FAData[1], 1)
  197.                 sim_data[alpha][beta][2] = round(FAData[3], 1)
  198.             if len(SAData) > 0:
  199.                 sim_data[alpha][beta][3] = round(SAData[0], 1)
  200.                 sim_data[alpha][beta][4] = round(SAData[1], 1)
  201.                 sim_data[alpha][beta][5] = round(SAData[3], 1)
  202.             if len(RAData) > 0:
  203.                 sim_data[alpha][beta][6] = round(RAData[0], 1)
  204.                 sim_data[alpha][beta][7] = round(RAData[1], 1)
  205.                 sim_data[alpha][beta][8] = round(RAData[3], 1)
  206.             if len(UAData) > 0:
  207.                 sim_data[alpha][beta][9] = round(UAData[0], 1)
  208.                 sim_data[alpha][beta][10] = round(UAData[1], 1)
  209.                 sim_data[alpha][beta][11] = round(UAData[3], 1)
  210.  
  211.     for alpha in range(len(data[WEAPONS])):
  212.         for beta in range(len(data[ENEMIES])):
  213.             CurWDT = data[WEAPONS][alpha]
  214.             CurEDT = data[ENEMIES][beta]
  215.            
  216.             if CurWDT[WEAPON_NAME] != "":
  217.                 print(CurWDT[WEAPON_NAME], end=' ')
  218.             else:
  219.                 print('Weapon #', alpha, end=' ', sep='')
  220.             print(STR_ADVANCED_TRY_WEAPON_DAM.format(CurWDT[WEAPON_POWER]), end='')
  221.             print('vs ', end='')
  222.             if CurEDT[ENEMY_NAME] != "":
  223.                 print(CurEDT[ENEMY_NAME], end=' ')
  224.             else:
  225.                 print('enemy #', beta, end='', sep='')
  226.             print(STR_ADVANCED_TRY_ENEMY_DATA.format(CurEDT[ENEMY_NAME], CurEDT[SUSCEPT][alpha]))
  227.  
  228.             CurSD = sim_data[alpha][beta]
  229.            
  230.             print('\tFront armor ({0:>9}'.format(str(CurEDT[FRONT])+'AP'+'):| '), end='')
  231.             if CurSD[0] > 0:
  232.                 print(STR_ADVANCED_TRY_DATA.format(CurSD[0], CurSD[1], CurSD[2]))
  233.             else:
  234.                 print('INVINCIBLE')
  235.            
  236.             print('\tSide armor  ({0:>9}'.format(str(CurEDT[SIDE])+'AP'+'):| '), end='')
  237.             if CurSD[3] > 0:
  238.                 print(STR_ADVANCED_TRY_DATA.format(CurSD[3], CurSD[4], CurSD[5]))
  239.             else:
  240.                 print('INVINCIBLE')
  241.  
  242.             print('\tRear armor  ({0:>9}'.format(str(CurEDT[REAR])+'AP'+'):| '), end='')
  243.             if CurSD[6] > 0:
  244.                 print(STR_ADVANCED_TRY_DATA.format(CurSD[6], CurSD[7], CurSD[8]))
  245.             else:
  246.                 print('INVINCIBLE')
  247.  
  248.             print('\tUnder armor ({0:>9}'.format(str(CurEDT[UNDER])+'AP'+'):| '), end='')
  249.             if CurSD[9] > 0:
  250.                 print(STR_ADVANCED_TRY_DATA.format(CurSD[9], CurSD[10], CurSD[11]))
  251.             else:
  252.                 print('INVINCIBLE')
  253.             print()
  254.             print()
  255.  
  256. # Weapon section
  257. def add_weapon():
  258.     weapon_name = persistent_input('Weapon name (leave blank if none): ', 'str')
  259.     damage = persistent_input('Weapon damage: ', 'int', POSITIVE)
  260.     bullets = persistent_input('Projectiles in one shot: ', 'int', POSITIVE)
  261.     deviati = persistent_input('Deviation of damage in percents: ', 'int', NOT_NEGATIVE)
  262.     arrange_data = [weapon_name, damage, bullets, deviati]
  263.     data[WEAPONS].append(arrange_data)
  264.    
  265.     print('{0} enemies are in base.'.format(len(data[ENEMIES])))
  266.     for beta in range(len(data[ENEMIES])):
  267.         print('Susceptability of ', end='')
  268.         if data[ENEMIES][beta][ENEMY_NAME] != "":
  269.             print(data[ENEMIES][beta][ENEMY_NAME], end='')
  270.         else:
  271.             print('enemy #{0}'.format(beta), end='')
  272.         print('; HP = {0}'.format(data[ENEMIES][beta][HEALTH]), end='')
  273.         value = persistent_input(': ', 'float', NOT_NEGATIVE)
  274.         data[ENEMIES][beta][SUSCEPT].append(value)
  275.  
  276. def show_weapons():
  277.     # Arrange a tab
  278.     if len(data[WEAPONS]):
  279.         print(STR_SHOW_WEAPONS_TAB_ARRANGE.format('ID', 'Weapon name', 'Dam', 'Shot', 'Dev'))
  280.         for x in range(STR_SHOW_WEAPONS_TAB_ARRANGE_LEN):
  281.             print(STR_BORDER_OF_DATA_AND_NAMES, end='')
  282.         print()
  283.         indx = 0
  284.         for weapon in data[WEAPONS]:
  285.             print(STR_SHOW_WEAPONS_TAB_ARRANGE.format(indx, weapon[WEAPON_NAME], weapon[WEAPON_POWER], weapon[BULLETS], weapon[DEVIATION]))
  286.             indx += 1
  287.         return True
  288.     return False
  289.        
  290. def rem_weapon():
  291.     global data
  292.     if show_weapons():
  293.         while True:
  294.             ids = persistent_input('Weapon ID (negative to cancel): ', 'int')
  295.             if ids < 0:
  296.                 return False
  297.             if ids > len(data[WEAPONS])-1:
  298.                 continue
  299.             del data[WEAPONS][ids]
  300.             return True
  301.     else:
  302.         print('Nothing to delete')
  303.         return False
  304.  
  305. # Enemy section
  306. def add_enemy():
  307.         name = persistent_input('Enemy name (leave blank if none): ', 'str')
  308.         health = persistent_input('Health: ', 'int', POSITIVE)
  309.         front = persistent_input('Front armor: ', 'int', NOT_NEGATIVE)
  310.         side = persistent_input('Side armor: ', 'int', NOT_NEGATIVE)
  311.         rear = persistent_input('Rear armor: ', 'int', NOT_NEGATIVE)
  312.         under = persistent_input('Under armor: ', 'int', NOT_NEGATIVE)
  313.        
  314.         susp = []
  315.         print('{0} weapons are in base.'.format(len(data[WEAPONS])))
  316.         for delta in range(len(data[WEAPONS])):
  317.             while True:
  318.                 print('Susceptability to ', end='')
  319.                 if data[WEAPONS][delta][WEAPON_NAME] != "":
  320.                     print(data[WEAPONS][delta][WEAPON_NAME], end='')
  321.                 else:
  322.                     print('weapon #{0}'.format(delta), end='')
  323.                 print('; Damage = {0}'.format(data[WEAPONS][delta][WEAPON_POWER]), end='')
  324.                 value = persistent_input(': ', 'float', NOT_NEGATIVE)
  325.                 susp.append(value)
  326.                 break
  327.            
  328.         arrange_data = [name, health, front, side, rear, under, susp]
  329.         data[ENEMIES].append(arrange_data)
  330.  
  331. def show_enemies():
  332.     if len(data[ENEMIES]):
  333.     # [1] = enemy list[]
  334.     #       [enemy name, front armor, side armor, rear armor, under armor, susceptibility]
  335.     #                                                                      []
  336.         print()
  337.         print('{0:>4}'.format('ID|'), end='') # ID column
  338.         print(STR_SHOW_ENEMIES_SUSCEPT_NAME.format('Weapon name'), end='') # Name column
  339.         for enemy in data[ENEMIES]:
  340.             print(STR_SHOW_ENEMIES_SUSCEPT_NAME.format(enemy[ENEMY_NAME]), end='') # Enemy names
  341.         print()
  342.         for m in range(STR_SHOW_ENEMIES_SUSCEPT_LEN+21*len(data[ENEMIES])):
  343.             print(STR_BORDER_OF_DATA_AND_NAMES, end='')
  344.         for alpha in range(len(data[WEAPONS])):
  345.             print()
  346.             print('{0:>3}|'.format(alpha), end='')
  347.             print(STR_SHOW_ENEMIES_SUSCEPT_NAME.format(data[WEAPONS][alpha][WEAPON_NAME]), end='')
  348.             for delta in range(len(data[ENEMIES])):
  349.                 print(STR_SHOW_ENEMIES_SUSCEPT_NAME.format(data[ENEMIES][delta][SUSCEPT][alpha]), end='')
  350.         print()
  351.         print()
  352.         print(STR_SHOW_ENEMIES_ENEMY_DATA.format('ID', 'Enemy name', 'HP', 'FA', 'SA', 'RA', 'UA'))
  353.         for m in range(STR_SHOW_ENEMIES_ENEMY_DATA_LEN):
  354.             print(STR_BORDER_OF_DATA_AND_NAMES, end='')
  355.         print()
  356.         indx = 0
  357.         for enemy in data[ENEMIES]:
  358.             print(STR_SHOW_ENEMIES_ENEMY_DATA.format(indx, enemy[ENEMY_NAME], enemy[HEALTH], enemy[FRONT], enemy[SIDE], enemy[REAR], enemy[UNDER]))
  359.             indx += 1
  360.         return True
  361.     return False
  362.  
  363. def rem_enemy():
  364.     global data
  365.     if show_enemies():
  366.         while True:
  367.             ids = persistent_input('ID (negative to cancel): ', 'int')
  368.             if ids < 0:
  369.                 return False
  370.             if ids > len(data[ENEMIES])-1:
  371.                 continue
  372.             del data[ENEMIES][ids]
  373.             return True
  374.     print('Nothing to delete')
  375.     return False
  376.  
  377. # Debug section
  378. def purge():
  379.     data = [ [], [] ]
  380.  
  381. def debug():
  382.     data0 = ['Heavy Plasma', 115, 1, 100]
  383.     data1 = ['Laser Rifle', 60, 1, 100]
  384.     data2 = [data0, data1]
  385.     data3 = ['Sectoid', 60, 70, 60, 50, 40, [0.8, 0.6]]
  386.     data4 = ['Sectopod', 120, 145, 130, 100, 90, [0.8, 1.5]]
  387.     data5 = [data3, data4]
  388.     c = copy.deepcopy(data2)
  389.     d = copy.deepcopy(data5)
  390.     data[WEAPONS] = c
  391.     data[ENEMIES] = d
  392.  
  393. # Interface section
  394. def main_menu():
  395.     global STATE, TRIES
  396.     choice = 0
  397.     print()
  398.     print('1: Simple evaluation')
  399.     print('2: Multiple evaluations')
  400.     print('3: Change TRIES const (make simulation more accurate or faster)')
  401.     print('0: Exit')
  402.     print()
  403.     choice = persistent_input('>>> ', 'int', BOUNDARY, [0, 3])
  404.     print()
  405.     if choice == 0:
  406.         return True
  407.     if choice == 1:
  408.         simple_try()
  409.     if choice == 2:
  410.         STATE = WEAP_MENU
  411.     if choice == 3:
  412.         print('Current TRIES: ', TRIES)
  413.         while True:
  414.             new_val = persistent_input('New value (negative to cancel): ', 'int')
  415.             if new_val < 0:
  416.                 break
  417.             if new_val == 0:
  418.                 continue
  419.             TRIES = new_val
  420.             break
  421.        
  422. def weapon_menu():
  423.     global STATE
  424.     choice = 0
  425.     print()
  426.     print('1: Add weapon')
  427.     print('2: Show weapons')
  428.     print('3: Remove weapon')
  429.     print('4: Next step')
  430.     print('0: Back to main menu')
  431.     print()
  432.     choice = persistent_input('>>> ', 'int', BOUNDARY, [0, 4])
  433.     print()
  434.     if choice == 0:
  435.         STATE = MAIN_MENU
  436.     if choice == 1:
  437.         add_weapon()
  438.     if choice == 2:
  439.         if not show_weapons():
  440.             print('Nothing to show')
  441.     if choice == 3:
  442.         rem_weapon()
  443.     if choice == 4:
  444.         STATE = ENEM_MENU
  445.  
  446. def enemy_menu():
  447.     global STATE
  448.     choice = 0
  449.     print()
  450.     print('1: Add enemy')
  451.     print('2: Show enemies')
  452.     print('3: Remove enemy')
  453.     print('4: Previous step')
  454.     print('5: Start simulation')
  455.     print('0: Back to main menu')
  456.     print()
  457.     choice = persistent_input('>>> ', 'int', BOUNDARY, [0, 5])
  458.     print()
  459.     if choice == 0:
  460.         STATE = MAIN_MENU
  461.     if choice == 1:
  462.         add_enemy()
  463.     if choice == 2:
  464.         if not show_enemies():
  465.             print('Nothing to show')
  466.     if choice == 3:
  467.         rem_enemy()
  468.     if choice == 4:
  469.         STATE = WEAP_MENU
  470.     if choice == 5:
  471.         advanced_try()
  472.         STATE = MAIN_MENU
  473.  
  474. # Main iterator
  475. while True:
  476.     if STATE == MAIN_MENU:
  477.         if main_menu(): # To exit
  478.             break
  479.     if STATE == WEAP_MENU:
  480.         weapon_menu()
  481.     if STATE == ENEM_MENU:
  482.         enemy_menu()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement