debriefing log parsing

This commit is contained in:
Vasiliy Horbachenko 2018-06-13 02:42:44 +03:00
parent 5f7724d44e
commit 481a5922b4
9 changed files with 107 additions and 49 deletions

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
import pickle
import sys
import theater.caucasus
import ui.window
@ -9,6 +9,14 @@ from game.game import Game
from theater import start_generator
from userdata import persistency
from dcs.lua.parse import loads
with open("/Users/sp/Downloads/won_cap.log", "r") as f:
s = f.read()
print(loads(s))
#sys.exit(0)
game = persistency.restore_game()
if not game:
theater = theater.caucasus.CaucasusTheater()

View File

@ -42,19 +42,20 @@ PRICES = {
Armor.APC_BTR_80: 6,
AirDefence.AAA_ZU_23_on_Ural_375: 4,
AirDefence.SAM_Avenger_M1097: 10,
}
UNIT_BY_TASK = {
FighterSweep: [Su_27, Su_33, Su_25, F_15C, MiG_15bis, MiG_21Bis, MiG_29A, F_A_18C, AV8BNA],
CAS: [Su_25T, A_10A, A_10C, ],
CAP: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
AirDefence: [AirDefence.AAA_ZU_23_on_Ural_375, ],
AirDefence: [AirDefence.AAA_ZU_23_on_Ural_375, AirDefence.SAM_Avenger_M1097 ],
Transport: [IL_76MD, S_3B_Tanker, ],
}
UNIT_BY_COUNTRY = {
"Russia": [Su_25T, Su_27, Su_33, Su_25, MiG_15bis, MiG_21Bis, MiG_29A, AirDefence.AAA_ZU_23_on_Ural_375, Armor.APC_BTR_80, Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, IL_76MD, ],
"USA": [F_15C, A_10C, F_A_18C, AV8BNA, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, S_3B_Tanker],
"USA": [F_15C, A_10C, F_A_18C, AV8BNA, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, S_3B_Tanker, AirDefence.SAM_Avenger_M1097],
}
UnitsDict = typing.Dict[UnitType, int]

View File

@ -56,12 +56,12 @@ class GroundInterceptEvent(Event):
targets = None # type: db.ArmorDict
def __str__(self):
return "Ground intercept from {} at {} ({})".format(self.from_cp, self.to_cp, "*" * self.difficulty)
return "Ground intercept from {} at {}".format(self.from_cp, self.to_cp)
def is_successfull(self, debriefing: Debriefing):
total_targets = sum(self.targets.values())
destroyed_targets = 0
for unit, count in debriefing.destroyed_units[self.defender.name].items():
for unit, count in debriefing.destroyed_units[self.defender_name].items():
if unit in self.targets:
destroyed_targets += count
@ -113,10 +113,10 @@ class InterceptEvent(Event):
transport_unit = None # type: FlyingType
def __str__(self):
return "Intercept from {} at {} ({})".format(self.from_cp, self.to_cp, "*" * self.difficulty)
return "Intercept from {} at {}".format(self.from_cp, self.to_cp)
def is_successfull(self, debriefing: Debriefing):
intercepted = self.transport_unit in debriefing.destroyed_units[self.defender.name].keys()
intercepted = self.transport_unit in debriefing.destroyed_units[self.defender_name].keys()
if self.from_cp.captured:
return intercepted
else:
@ -185,10 +185,10 @@ class CaptureEvent(Event):
STRENGTH_RECOVERY = 0.35
def __str__(self):
return "Attack from {} to {} ({})".format(self.from_cp, self.to_cp, "*" * self.difficulty)
return "Attack from {} to {}".format(self.from_cp, self.to_cp)
def is_successfull(self, debriefing: Debriefing):
attackers_success = len(debriefing.destroyed_units[self.defender.name]) > len(debriefing.destroyed_units[self.attacker.name])
attackers_success = len(debriefing.destroyed_units[self.defender_name]) > len(debriefing.destroyed_units[self.attacker_name])
if self.from_cp.captured:
return attackers_success
else:

View File

@ -21,8 +21,8 @@ ENEMY_INTERCEPT_PROBABILITY_BASE = 10
ENEMY_INTERCEPT_GLOBAL_PROBABILITY_BASE = 1
ENEMY_CAPTURE_PROBABILITY_BASE = 3
PLAYER_INTERCEPT_PROBABILITY_BASE = 30
PLAYER_GROUNDINTERCEPT_PROBABILITY_BASE = 30
PLAYER_INTERCEPT_PROBABILITY_BASE = 100
PLAYER_GROUNDINTERCEPT_PROBABILITY_BASE = 100
PLAYER_GLOBALINTERCEPT_PROBABILITY_BASE = 100
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 50
@ -40,8 +40,8 @@ class Game:
def __init__(self, theater: ConflictTheater):
self.events = []
self.theater = theater
self.player = "USA"
self.enemy = "Russia"
self.player = "Russia"
self.enemy = "USA"
def _roll(self, prob, mult):
return random.randint(0, 100) <= prob * mult
@ -132,16 +132,6 @@ class Game:
theater=self.theater))
break
def _generate_global(self):
for cp in self.theater.player_points():
if cp.is_global:
if self._roll(PLAYER_GLOBALINTERCEPT_PROBABILITY_BASE, cp.base.strength):
enemy_points = list(set(self.theater.enemy_bases()) - set(self.theater.conflicts(False)))
self.events.append(InterceptEvent(attacker_name=self.player,
defender_name=self.enemy,
from_cp=cp,
to_cp=random.choice(enemy_points)))
def _commision_units(self, cp: ControlPoint):
for for_task in [CAP, CAS, FighterSweep, AirDefence]:
limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_LIMITS_SCALE)
@ -207,5 +197,4 @@ class Game:
self._generate_interceptions()
self._generate_globalinterceptions()
self._generate_groundinterceptions()
self._generate_global()

View File

@ -159,7 +159,8 @@ class GroundInterceptOperation(Operation):
radials=ALL_RADIALS
)
super(GroundInterceptOperation, self).__init__(mission, conflict)
self.initialize(mission=mission,
conflict=conflict)
def generate(self):
self.airgen.generate_cas(self.strikegroup, clients=self.attacker_clients, at=self.starting_position)

View File

@ -23,29 +23,33 @@ class EventMenu(Menu):
self.window.clear_right_pane()
row = 0
def label(text):
def label(text, _row=None, _column=None):
nonlocal row
Label(self.frame, text=text).grid()
Label(self.frame, text=text).grid(row=_row and _row or row, column=_column and _column or 0)
if _row is None:
row += 1
def scrable_row(unit_type, unit_count):
nonlocal row
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count)).grid(row=row)
scramble_entry = Entry(self.frame)
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count)).grid(row=row, sticky=W)
scramble_entry = Entry(self.frame, width=10)
scramble_entry.grid(column=1, row=row)
scramble_entry.insert(0, "0")
self.aircraft_scramble_entries[unit_type] = scramble_entry
client_entry = Entry(self.frame)
client_entry = Entry(self.frame, width=10)
client_entry.grid(column=2, row=row)
client_entry.insert(0, "0")
self.aircraft_client_entries[unit_type] = client_entry
row += 1
def scramble_armor_row(unit_type, unit_count):
nonlocal row
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count)).grid(row=row)
scramble_entry = Entry(self.frame)
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count)).grid(row=row, sticky=W)
scramble_entry = Entry(self.frame, width=10)
scramble_entry.insert(0, "0")
scramble_entry.grid(column=1, row=row)
self.armor_scramble_entries[unit_type] = scramble_entry
@ -58,13 +62,23 @@ class EventMenu(Menu):
base = self.event.to_cp.base
label("Aircraft")
label("Amount", row, 1)
label("Client slots", row, 2)
row+=1
for unit_type, count in base.aircraft.items():
scrable_row(unit_type, count)
if not base.total_planes:
label("None")
label("Armor")
for unit_type, count in base.armor.items():
scramble_armor_row(unit_type, count)
if not base.total_armor:
label("None")
Button(self.frame, text="Commit", command=self.start).grid(column=0, row=row)
Button(self.frame, text="Back", command=self.dismiss).grid(column=2, row=row)

View File

@ -21,14 +21,14 @@ class EventResultsMenu(Menu):
self.window.clear_right_pane()
if not self.finished:
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1, True)).grid()
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1, False)).grid(row=1, column=1)
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1)).grid()
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1)).grid(row=1, column=1)
Button(self.frame, text="half losses, succ", command=self.simulate_result(0.5, 0.5, True)).grid(row=2, )
Button(self.frame, text="half losses, fail", command=self.simulate_result(0.5, 0.5, False)).grid(row=2, column=1)
Button(self.frame, text="half losses, succ", command=self.simulate_result(0.5, 0.5)).grid(row=2, )
Button(self.frame, text="half losses, fail", command=self.simulate_result(0.5, 0.5)).grid(row=2, column=1)
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0, True)).grid(row=3, )
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0, False)).grid(row=3, column=1)
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0)).grid(row=3, )
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0)).grid(row=3, column=1)
Label(self.frame, text="Play the mission and save debriefing to {}".format(debriefing_directory_location())).grid(row=0, column=0)
else:
@ -55,6 +55,10 @@ class EventResultsMenu(Menu):
Button(self.frame, text="Okay", command=self.dismiss).grid(columnspan=1, row=row); row += 1
def process_debriefing(self, debriefing: Debriefing):
debriefing.calculate_destroyed_units(mission=self.event.operation.mission,
player_name=self.game.player,
enemy_name=self.game.enemy)
self.game.finish_event(event=self.event, debriefing=debriefing)
self.game.pass_turn()
@ -63,7 +67,7 @@ class EventResultsMenu(Menu):
self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy, {})
self.display()
def simulate_result(self, player_factor: float, enemy_factor: float, result: bool):
def simulate_result(self, player_factor: float, enemy_factor: float):
def action():
debriefing = Debriefing()

View File

@ -34,9 +34,9 @@ class MainMenu(Menu):
def event_button(event):
nonlocal row
Message(self.frame, text="{}{}".format(
event.defender.name == self.game.player and "Enemy attacking: " or "",
event.defender_name == self.game.player and "Enemy attacking: " or "",
event
), aspect=500).grid(column=0, row=row, sticky=NW)
), aspect=800).grid(column=0, row=row, sticky=NW)
Button(self.frame, text=">", command=self.start_event(event)).grid(column=0, row=row, sticky=NE+S)
row += 1
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1

View File

@ -1,26 +1,67 @@
import typing
import json
import threading
import time
import os
from datetime import datetime
from dcs.lua import parse
from dcs.mission import Mission
from dcs.unitgroup import FlyingGroup
from dcs.unit import UnitType
from game import db
DEBRIEFING_LOG_EXTENSION = "log"
class Debriefing:
def __init__(self):
def __init__(self, alive_units):
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[str, int]]
self.alive_units = alive_units # type: typing.Dict[str, typing.Dict[str, int]]
@classmethod
def parse(cls, path: str):
def parse(cls, path: str, mission: Mission):
with open(path, "r") as f:
events = json.load(f)
table_string = f.read()
table = parse.loads(table_string)
units = table.get("debriefing", {}).get("world_state", {})
alive_units = {}
return Debriefing()
for unit in units:
type = unit["type"] # type: str
country_id = int(unit["country"])
if type:
country_dict = alive_units.get(unit[country_id], {})
country_dict[type] = country_dict.get(type, 0) + 1
alive_units[unit[country_id]] = country_dict
return Debriefing(alive_units)
def calculate_destroyed_units(self, mission: Mission, player_name: str, enemy_name: str):
def count_groups(groups: typing.List[UnitType]) -> typing.Dict[UnitType, int]:
result = {}
for group in groups:
for unit in group.units:
result[unit.unit_type] = result.get(unit.unit_type, 0) + 1
return result
def calculate_losses(all_units: typing.Dict[UnitType, int], alive_units: typing.Dict[str, int]) -> typing.Dict[UnitType, int]:
result = {}
for t, count in all_units.items():
result[t] = count - alive_units[db.unit_type_name(t)]
return result
player = mission.country(player_name)
enemy = mission.country(enemy_name)
player_units = count_groups(player.plane_group + player.vehicle_group)
enemy_units = count_groups(enemy.plane_group + enemy.vehicle_group)
self.destroyed_units = {
player.name: calculate_losses(player_units, self.alive_units[player.id]),
enemy.name: calculate_losses(enemy_units, self.alive_units[enemy.id]),
}
def debriefing_directory_location() -> str:
return "build/debriefing"