Salmon Run Statistics: Tides and Events (Part 3)
Tags: showdev, python
Published: 2020-12-23 14:52:46

[First](https://dev.to/cassdlcm/salmon-run-statistics-part-1-1l0l) | [Previous](https://dev.to/cassdlcm/salmon-run-statistics-stages-part-2-34cn) | Next

Today we're gonna look at the probability distribution of events and tides.

```
high tide:
none: 15.0058% occurrence; 80.8970% wave cleared
mothership: 0.7407% occurrence; 98.5512% wave cleared
fog: 0.7919% occurrence; 83.2775% wave cleared
rush: 0.9527% occurrence; 75.1159% wave cleared
cohock_charge: 0.0% occurrence
griller: 0.9929% occurrence; 77.6987% wave cleared
goldie_seeking: 0.9623% occurrence; 92.9686% wave cleared

normal tide:
none: 45.5480% occurrence; 81.9957% wave cleared
mothership: 2.4686% occurrence; 95.6328% wave cleared
fog: 2.5295% occurrence; 86.8992% wave cleared
rush: 3.1385% occurrence; 85.3304% wave cleared
cohock_charge: 0.0% occurrence
griller: 2.9823% occurrence; 88.2238% wave cleared
goldie_seeking: 3.0713% occurrence; 83.7560% wave cleared

low tide:
none: 15.0909% occurrence; 87.9722% wave cleared
mothership: 0.7476% occurrence; 97.6866% wave cleared
fog: 0.7793% occurrence; 92.1918% wave cleared
rush: 0.0% occurrence
cohock_charge: 4.1976% occurance; 92.0484% wave cleared
griller: 0.0% occurrence
goldie_seeking: 0.0% occurrence
```

Events
```
none: 75.64554806202921
mothership: 3.9574326151171575
fog: 4.100073531455544
rush: 4.0913558846642696
cohock_charge: 4.1982418148877196
griller: 3.973857167042747
goldie_seeking: 4.033490924803348
```

Tides
```
high: 0.19446164109069133
normal: 0.5973773780856048
low: 0.2081609808237039
```

Judging from this data, I think it generates the event first, and then the tide.
There is an approximately 25% chance of having an event, with the chance of any particular event being approximately 4%.
For events which can occur on any tide, there is an approximately 60% chance of receiving normal tide, and a 20% chance each for high and low.
Cohock charge is the only event that can only occur on low tide, so if that event is rolled it is guaranteed to be low tide.
Grillers, goldie seeking, and rush all are normal or high tides, so it's 75% normal tide and 25% high tide.

Out of the possible combinations, high tide rush has the lowest wave clear percentage, and high tide mothership has the highest.

Today's file is the appropriately named [reports/tides_and_events.py](https://github.com/cassdelacruzmunoz/salmontracker/blob/dev/scripts/tides_and_events.py).

Let's go through this file together.

```Python
data = core.init("All")
```
The usual updating the dataset.

```Python
tideList: List[str] = ["high", "normal", "low"]
eventList: List[str] = [
    "None",
    "mothership",
    "fog",
    "rush",
    "cohock_charge",
    "griller",
    "goldie_seeking",
]
tideDict: Dict[str, dict] = {}
for tideStr in tideList:
    eventDict: Dict[str, Union[str, int]] = {}
    for eventStr in eventList:
        eventDict[eventStr] = {"key": eventStr, "count": 0.0, "clear_count": 0.0}
    tideDict[tideStr] = eventDict
```
This creates a dictionary of dictionaries from the list of tides and list of events, where tides are the outer layer and events are the inner layer, with the inner layer dictionaries having the event name, the occurrence count, and the clear count.

```Python
total: float = 0.0
```
We need to store the total number of waves in the data file in order to calculate the percent of occurrences, so we initialize that variable now with a value of 0.0.
Sure, it is only gonna hold integer values, but this saves on having to cast it to a float later.

```Python
with gzip.open(data) as reader:
    for job in jsonlines.Reader(reader, ujson.loads):
        waveCount: int = 0
        for wave in job["waves"]:
            total += 1.0
            if wave["known_occurrence"] is not None:
                cast(
                    Dict[str, float],
                    tideDict[wave["water_level"]["key"]][
                        wave["known_occurrence"]["key"]
                    ],
                )["count"] += 1.0
                if job["clear_waves"] > waveCount:
                    cast(
                        Dict[str, float],
                        tideDict[wave["water_level"]["key"]][
                            wave["known_occurrence"]["key"]
                        ],
                    )["clear_count"] += 1.0
            else:
                cast(
                    Dict[str, float], tideDict[wave["water_level"]["key"]]["None"]
                )["count"] += 1.0
                if job["clear_waves"] > waveCount:
                    cast(
                        Dict[str, float],
                        tideDict[wave["water_level"]["key"]]["None"],
                    )["clear_count"] += 1.0
            waveCount += 1
```
Now, we crack open the data file and start collecting our results.
The first two lines are to extract the job from the gzip encoded jsonlines file.
We need a variable to count which wave we're on because we need to check if the `"clear_waves"` value in the job is higher than that.
We check if the wave has an event, and if so we store the data in the appropriate event dictionary, otherwise we store it in the `"none"` dictionary.
We then check if the wave was cleared or not.

```Python
for tide in tideDict.values():
    for event in tide.values():
        print(
            cast(str, event["key"])
            + ": "
            + str(100.0 * cast(float, event["count"]) / total)
            + "% occurance; "
            + str(
                100.0
                * cast(float, event["clear_count"])
                / (
                    cast(float, event["count"])
                    if cast(float, event["count"]) > 0.0
                    else 1.0
                )
            )
            + " % wave cleared"
        )
```
These loops print out the results in the format similar to the one shown in this post.
I did edit the results print to look nicer in this post.