Source code for yawning_titan.envs.generic.core.red_interface
from typing import Dict, List, Union
from yawning_titan.envs.generic.core.network_interface import NetworkInterface
from yawning_titan.envs.generic.core.red_action_set import RedActionSet
"""
An interface to the parent red agent that selects what actions it wants to use base on the settings and then uses a
dictionary to call these actions.
"""
[docs]class RedInterface(RedActionSet):
"""The interface used by the Red Agents to act within the environment."""
[docs] def __init__(self, network_interface: NetworkInterface):
"""
Initialise the red interface.
Args:
network_interface: Object from the NetworkInterface class
"""
self.network_interface = network_interface
self.non_attacking_actions = ["do_nothing", "random_move"]
self.action_dict = {}
action_set = []
probabilities_set = []
action_number = 0
# Goes through the actions that the red agent can perform
if self.network_interface.game_mode.red.action_set.spread.use.value:
# If the action is enabled in the settings files then add to list of possible actions
self.action_dict[action_number] = self.spread
action_set.append(action_number)
# also gets the weight for the action (likelihood action is performed) from the settings file
probabilities_set.append(
self.network_interface.game_mode.red.action_set.spread.likelihood.value
)
action_number += 1
if self.network_interface.game_mode.red.action_set.random_infect.use.value:
self.action_dict[action_number] = self.intrude
action_set.append(action_number)
probabilities_set.append(
self.network_interface.game_mode.red.action_set.random_infect.likelihood.value
)
action_number += 1
if self.network_interface.game_mode.red.action_set.basic_attack.use.value:
self.action_dict[action_number] = self.basic_attack
action_set.append(action_number)
probabilities_set.append(
self.network_interface.game_mode.red.action_set.basic_attack.likelihood.value
)
action_number += 1
if self.network_interface.game_mode.red.action_set.do_nothing.use.value:
self.action_dict[action_number] = self.do_nothing
action_set.append(action_number)
probabilities_set.append(
self.network_interface.game_mode.red.action_set.do_nothing.likelihood.value
)
action_number += 1
if self.network_interface.game_mode.red.action_set.move.use.value:
self.action_dict[action_number] = self.random_move
action_set.append(action_number)
probabilities_set.append(
self.network_interface.game_mode.red.action_set.move.likelihood.value
)
action_number += 1
# normalises the weights so they work with numpy choices
probabilities_set_normal = [
float(i) / sum(probabilities_set) for i in probabilities_set
]
super().__init__(network_interface, action_set, probabilities_set_normal)
[docs] def perform_action(self) -> Dict[int, Dict[str, List[Union[bool, str, None]]]]:
"""
Chooses and then performs an action.
This is called for every one of the red agents turns
Returns:
A tuple containing the name of the action, the success status, the target, the attacking node and any natural spreading attacks
"""
current_turn_attack_info = {}
action_count = 0
if self.network_interface.game_mode.red.natural_spreading.capable.value:
current_turn_attack_info[action_count] = self.natural_spread()
action_count += 1
zd = False
# tries to use a zero day attack if it is enabled (not in the main dictionary as it tries it every turn)
if self.network_interface.game_mode.red.action_set.zero_day.use.value:
inter = self.zero_day_attack()
if True in inter["Successes"]:
current_turn_attack_info[action_count] = inter
zd = True
action_count += 1
if zd is False:
# chooses an action
action = self.choose_action()
# performs the action
current_turn_attack_info[action_count] = self.action_dict[action]()
action_count += 1
# If there are no possible targets for an attack then red will attempt to move to a new node
if (
current_turn_attack_info[action_count - 1]["Action"]
== "no_possible_targets"
):
current_turn_attack_info[action_count] = self.random_move()
action_count += 1
# increments the day for the zero day
if self.network_interface.game_mode.red.action_set.zero_day.use.value:
self.increment_day()
all_attacking = [
node
for l_nodes in list(
map(
lambda y: y["Attacking_Nodes"],
filter(
lambda x: x["Action"] not in self.non_attacking_actions,
current_turn_attack_info.values(),
),
)
)
for node in l_nodes
]
all_target = [
node
for l_nodes in list(
map(
lambda y: y["Target_Nodes"],
filter(
lambda x: x["Action"] not in self.non_attacking_actions,
current_turn_attack_info.values(),
),
)
)
for node in l_nodes
]
all_success = [
node
for l_nodes in list(
map(
lambda y: y["Successes"],
filter(
lambda x: x["Action"] not in self.non_attacking_actions,
current_turn_attack_info.values(),
),
)
)
for node in l_nodes
]
self.network_interface.update_stored_attacks(
all_attacking, all_target, all_success
)
return current_turn_attack_info