z3rspoilerlib 0.1.2
A library for analyzing large batches of A Link to the Past Randomizer spoiler logs

# Overview

<p>z3rspoilerlib is a python library for analyzing spoiler logs produced by the A Link To The 
Past Randomizer (https://www.alttpr.com). It returns numbers in the form of integers or table-like
dictionaries for further analysis and has some other helpful functions and variables. The current version is a
pre-release version subject to change at any time.</p>

# Table of Contents

1. [Getting Started](#getting-started)
2. [SeedBulk Methods](#seedbulk-methods)
3. [SeedSingle Class](#seedsingle-class)
3. [SeedSingle Attributes](#seedsingle-attributes)
4. [SeedSingle Methods](#seedsingle-methods)
5. [Item Variables](#item-variables)
6. [Location Variables](#location-variables)
7. [Loading Individual Seeds](#loading-individual-seeds)
8. [Todo](#todo)
9. [v30.4 Spoiler Logs](#v304-spoiler-logs)

# Getting Started

The recommended way to install is to use pip. You can use the command `pip install z3rspoilerlib` or 
`pip3 install z3rspoilerlib` depending on which version of pip you're using. To use it in a script, 
put `import z3rspoilerlib` at the top or use a shorthand like `import z3rspoilerlib as zsl`.

Once you've got it installed and imported, you can begin by creating an instance of the `SeedBulk` 
class, which accepts a directory containing spoiler logs as an argument and prepares them to be used later. 
It also accepts the game state(open, standard, or inverted) as a second argument with None as the 
default. For example you can use, `batch = zsl.SeedBulk('spoilers-304-norg', 'open')` to load a 
directory of open mode seeds named "spoilers-304-norg." If you don't pass a directory, the program 
will look in the current directory. It will try to load all .txt files, so make sure you only have 
spoiler logs in the directory you want it to load from.

## SeedBulk Methods

The SeedBulk class has a few handy built in methods you can use to count items and locations which 
return integers and table-like dictionaries. Items and locations should be passed as they appear 
in the spoiler logs. If there are two different spellings for a region, use the spelling of the key 
containing multiple locations, not the spelling used in individual locations(e.g. use "Dark Palace", 
not "Palace of Darkness".) In addition to the regions defined by the spoiler logs, there are some 
custom regions included that can be used as well. These are listed below in the [SeedSingle Attributes](seedsingle-attributes) section.

**count_item_in_loc(_item_, _loc_)**: Counts how many times `item` appears in `loc`(a specific item location, a region, or a custom region) in the batch. Returns an integer.

**count_where(_item_)**: Returns a dictionary of location-number pairs counting how many times `item` appeared in a given location.

**count_what(_loc_)**: Returns a dictionary of item-number pairs counting how many times that item appeared in `loc`. Must be one specific location, not a region.

**count_where_if(_item_a_, _item_b_, _loc_b_)**: Returns a dictionary with location-number pairs that count 
where `item_a` appears given that `item_b` is in `loc_b`(specific location, region, or custom region). 
Returns `None` instead of an empty dictionary.

**count_what_if(_loc_a_, _item_b_, _loc_b_)**: Returns a dictionary with item-number pairs that counts what items appear in `loc_a`(must be one specific location) given that `item_b` is in `loc_b`(specific location, region, or custom region). Returns None instead of an empty dictionary.

# SeedSingle Class

When SeedBulk loads the spoiler logs, it creates a SeedSingle object for each individual log. These objects have their own methods and attributes you can use. To iterate over these instead of using the built in methods, create an instance of the class and use a `for` loop like so: `for i in batch.load_seeds():`. `batch.load_seeds()` is a generator expression that loads these objects into memory one at a time designed such that it will use very little memory when working with large amounts of logs. Inside this loop you can use the SeedSingle methods and attributes. Additionally, SeedBulk has an attribute `spoiler_count` with the number of spoiler logs in the batch.

## SeedSingle Attributes

**seed_dict**: The seed's unaltered spoiler log as a dictionary.

**world**: A dictionary containing information about the world with the following keys: 

* State: the game state
* Crystals: a list of all crystal dungeons
* Pendants: a list of all pendant dungeons
* Red Crystals: crystals 5 & 6
* Green Pendant: the green pendant dungeon 
* TR Medallion
* MM Medallion

**location_by_item**: A dictionary of unique items as keys and their location as values.

**custom_region_dict**: A dictionary that is like the original log, but with custom regions. Current 
custom regions are: 

* Kakariko: Items in Kakariko except locations gated by another item(Sick Kid, Magic Bat) and Race Game
* South Shore: Dam to Ice Rod Cave
* Zora Area: Waterfall chests, Zora Ledge, and Zora
* Sahas Hut
* Village Of Outcasts: Chest Game, Brewery, and C-Shaped House
* TT First Four: The first four chests in Thieves' Town
* Hookshot Cave
* Superbunny Cave
* North Dark World: Bumper Ledge and Graveyard Ledge
* Smith Sequence: Smith Item and Purple Chest
* Pyramid Fairy
* Waterfall Fairy
* Hype Cave
* Mire Shed
* TR Mimic Cave: All items in Turtle Rock plus the item in Mimic Cave
* Sphere One Stanard

## SeedSingle Methods

**get_location_region_by_item()**: Returns a dictionary with unique items as keys and a tuple containing the location and region for that item as the value.

**get_items_by_region(_region_)**: Returns a list of items in the given region. Does not include dungeon items.

**make_flat_loc_dict()**: Returns a flattened version of the seed dictionary with specific locations as keys and items as values. There are no nested key-value pairs as there are in the original spoiler logs.

## Loading Individual Seeds

If you only want to load one seed as a SeedSingle object you can use `zsl.load_single(id, game_state, seed_dir)` where 
`id` is the string at the end of the file name, `game_state` is the state(default is open), and the optional `seed_dir`
argument takes a subdirectory that the seed is in. If `seed_dir` is not passed, the function will look in the current
directory.

## Item Variables

<p>This library has an items submodule with some helpful variables:</p>

* prog_items: A tuple containing all items in the game that can be required for progression.
* nice_items: A tuple containing nice to have but never required (Half Magic and Silver Arrows.) 
* other_items: A tuple containing other unique items (Single Arrow and Bug Net.)
* fetch_items: A tuple containing fetch quest items (Shovel, Mushroom, Powder.)
* unique_items: A tuple containing the elements of the above tuples.
* bottle_items: A tuple containing all possible bottle items.
* small_keys: A tuple containing all small keys.
* big_keys: A tuple containing all big keys.
* compasses: A tuple containing all compasses.
* maps: A tuple containing all maps.

## Location Variables

<p>The locations sub module has a tuple containing all 216 locations in the game, simply named `locations`.

## Todo

* Re-implement current functionality and future components as binary Rust extensions for speed. Python is rather slow 
  here. Pre-building the heaviest parts in Rust to be distributed with the python wheel will allow it to be sped up while maintaining the relative simplicity of python syntax.
* Add a module containing requirements for each location which can be used for package functions and in user scripts.
* Write "solvers" for determining whether a seed is Agahnim-required or pedestal-required, maybe a generic solver
  interface that will allow users to model specific situations and return numbers/probabilities
* Write a SeedBulk method or methods that can accept more generic conditionals as arguments than the current methods to
  simplify user scripts; they won't have to write as much custom code
* Refactor plus additional support for keysanity, maybe glitched modes and other goals as well. Initial focus is on
  Normal, Standard/Open/Inverted, Defeat Ganon settings. 

## v30.4 Spoiler Logs

* Normal Open Randomized Ganon http://www.mediafire.com/file/fy2kcn2483634m6/spoilers-304-norg.zip/file<br/>
* Normal Standard Randomized Ganon http://www.mediafire.com/file/ra7i1uc2acb655h/spoilers-304-nsrg-120318.zip/file<br/>
* Normal Standard Uncle Assured Ganon http://www.mediafire.com/file/8r112cgf59786c7/spoilers-304-nsug-130318.zip/file<br/>