Source code for yawning_titan.agents.sinewave_red

import math
import random
from typing import Dict, List, Union

from yawning_titan.envs.generic.core.red_interface import RedInterface


[docs]def calculate_number_moves(attack_strength): """ Calculate the number of moves for the red agent to take. Args: attack_strength: Current red agent attack strength Returns: An int representing the number of moves the red agent can take that turn """ amount = math.floor(attack_strength) random_value = random.randint(0, 10) diff = attack_strength - amount if diff * 10 > random_value: amount += 1 return int(amount)
[docs]class SineWaveRedAgent(RedInterface): """ An agent which is based on the RedInterface provided by the YAWNING TITAN generic environment. This agent is an example of how the generic RedInterface can be extended to include custom red team behaviour - in this case, action selection. The agent uses a sine wave to allow the red agent to attack more randomly and in waves rather than constantly. """
[docs] def __init__(self, network_interface): self.time = 0 self.sine_offset = random.randint(0, 10) self.cosine_offset = random.randint(0, 10) self.sine_multiplier = round(random.uniform(1.5, 2.25), 4) self.cosine_multiplier = round(random.uniform(2.75, 3.5), 4) super().__init__(network_interface)
[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_counter = 0 # advances the agents power time self.time += round(random.uniform(0.2, 0.8), 2) if self.time >= 50: self.time = 0 self.sine_offset = random.randint(0, 10) self.cosine_offset = random.randint(0, 10) red_skill = self.network_interface.game_mode.red.agent_attack.skill.value.value # works out the current strength of the red agent current_strength = ( ( math.sin(self.sine_multiplier * self.time + self.sine_offset) + math.cos(self.cosine_multiplier * self.time + self.cosine_offset) ) + red_skill - 0.5 ) # uses the red agents skill as a baseline if current_strength < red_skill: current_strength = red_skill # calculate the number of attacks that the red agent will get this go number_runs = calculate_number_moves(current_strength) if self.network_interface.game_mode.red.action_set.spread.use.value: current_turn_attack_info[action_counter] = self.natural_spread() 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_counter] = inter zd = True action_counter += 1 if zd is False: counter = 0 name = "" while counter < number_runs and name != "no_possible_targets": # chooses an action action = self.choose_action() current_turn_attack_info[action_counter] = self.action_dict[action]() action_counter += 1 counter += 1 name = current_turn_attack_info[action_counter - 1]["Action"] # If there are no possible targets for an attack then red will attempt to move to a new node if name == "no_possible_targets" and number_runs >= counter: current_turn_attack_info[action_counter] = self.random_move() action_counter += 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