How to find where my (or my enemy's) information units scored?

There are two important parts to retrieving the breach information (and similar information, such selfDestruct, etc).

  1. Breach data is only reported with results of the action phase, which are not stored by default
  2. Breach data is not parsed by game_state, so it will have to be modified to actually retrieve the information.

Retrieving the results of the Action phase

The default AlgoCore does not report action phase data, so you will need to change that. If you look at the block of code from lines 55 to 80 in the algocore.py file, you can see that this is the section that handles turns. If it is the build / deploy phase, self.on_turn(game_state_string), from AlgoStrategy is called, which parses the data. However, if it is the action phase, nothing happens. To change this, I created a function in AlgoStrategy called parse_action_phase, which takes the game_state_string as an arguement (similar to on_turn in this way), and called it in the correct if block in AlgoCore. I then used that function to parse and store information

Retrieving the information from the game_state_string

Now that data from the action phase has been retrieved, it now has to be parsed so that it is readable for your code. I started by parsing information the same way as in the on_turn function, by creating a game_state. To get breach information from the game_state_string (called serialized_string or state_line in game_state.py), first find the__parse_state function (technically, you can do this anywhere, but considering that you are parsing a state, this seems to be the correct place to do so). At any point after the line state = json.loads(state_line), using state["events"]["breach"] will give you the information on breaches.

To be honest, I don’t really know what all of the information reported about breach means. However, these are my best guesses:

  1. The 1st piece of information, the 2-number array, is the location of the breach
  2. The 2nd piece of information (counting the array as 1) is the damage dealt by the unit
  3. The 3rd is the type of information (3 is Ping, 4 is EMP, 5 is Scrambler).
  4. I don’t really know about the 4th, the string of a number (ex. "730"), but it might have to do with the unique identity of a unit?
  5. The 5th piece of information, the number that, as far as I know, is always either a 1 or 2 (but I am not sure about this), is still a mystery to me. Maybe player identity?

I hope that this was helpful, despite how long and badly phrased it was. If it doesn’t make sense, please ask for clarification.

Edit:
A discussion about what all of the numbers mean has happened in this post:
https://forum.c1games.com/t/parsing-replay-files/276/10

Edit:
One thing that I didn’t mention (because I didn’t know) is that GameUnit doesn’t like REMOVE units. If you create a GameState based on a game_state_string from the action phase, and a REMOVE unit is present, your algo will crash. This is because certain qualities (such as speed, damage, range, etc.) are not defined for the REMOVE unit. If a GameUnit of a REMOVE unit is created (GameUnits are created when a GameState is created), you will receive an error. To fix this, you will have to edit unit.py. In the function __serialize_self, add 2 lines after the line
from .game_state import FIREWALL_TYPES, UNIT_TYPE_TO_INDEX, ENCRYPTOR, REMOVE
(Or really any time before any undefined qualities are requested). The lines to add are:

if self.unit_type == REMOVE:
<indent>return;

Thanks to the same thread that I referenced earlier (Parsing Replay Files - #10 by Jumpster - Questions - Terminal Forum) for mentioning that this was an issue

Edit:
Another issue that I have found is that this sometimes crashes despite this fix. The error is (ignoring the giant line of functions leading up to the error):

File "/tmp/algo16180919916539904124/gamelib/game_state.py", line 136, in __create_parsed_units self.game_map[x,y][0].pending_removal = True
IndexError: list index out of range

To fix it, around the line

if unit_type == REMOVE:
<indent>self.game_map[x,y][0].pending_removal = True

Change it to:

if unit_type == REMOVE:
<indent> try:
<indent><indent>self.game_map[x,y][0].pending_removal = True
<indent>except:
<indent><indent>gamelib.debug_write("Error! Program tried to die while parsing REMOVE unit")

Side note: This is a very hacky fix, so if somebody knows how to fix it properly, feel free to say so. I don’t really know why this is happening.

8 Likes