diff --git a/app.py b/app.py index eb3013e..2d7b07c 100644 --- a/app.py +++ b/app.py @@ -2,14 +2,6 @@ import streamlit as st import database as db -class Moon: - def __init__(self, name, tier, inside_max_power, outside_max_power): - self.name = name - self.tier = tier - self.inside_max_power = inside_max_power - self.outside_max_power = outside_max_power - - class Creature: def __init__(self, name, nickname, power, max_spawns, hits_to_kill): self.name = name @@ -26,85 +18,22 @@ class Run: self.outside_power = moon.outside_max_power -def find_spawn_list(remaining_power: int, creatures: list[Creature]) -> list[str] | None: - """ - Given a run, return all possible spawns for location. - - :param creatures: - :param remaining_power: The remaining power in the current location. - :return: A list of all creatures that may still spawn or None. - """ - if remaining_power == 0: - return None - - spawnable = sorted( - [creature.name for creature in creatures if creature.power <= remaining_power] - ) - if spawnable: - return spawnable - else: - return None - - def main(): st.set_page_config("Lethal Company Scouter", "🛰️") - moons = [ - # Tier 1 - Moon("Experimentation", 1, 4, 8), - Moon("Assurance", 1, 6, 8), - Moon("Vow", 1, 7, 6), - # Tier 2 - Moon("Offense", 2, 12, 12), - Moon("March", 2, 14, 12), - # Tier 3 - Moon("Rend", 3, 10, 6), - Moon("Dine", 3, 15, 6), - Moon("Titan", 3, 18, 7), - ] - - outside_creatures = [ - Creature("Baboon Hawk", None, 1, 15, 6), - Creature("Circuit Bees", None, 1, 6, None), - Creature("Eyeless Dog", None, 2, 8, 12), - Creature("Forest Keeper", "Giant", 3, 3, None), - Creature("Earth Leviathan", "Worm", 2, 3, None), - # Hybrid - Creature("Outside Ghost Girl ", None, 2, 1, None), - Creature("Outside Masked", None, 1, 10, 4), - ] - - inside_creatures = [ - Creature("Bracken", "Freddy Fazbear", 3, 1, 6), - Creature("Bunker Spider", None, 3, 1, 6), - Creature("Coil Head", None, 1, 5, None), - Creature("Hoarding Bug", "Yippee Bug", 1, 8, 3), - Creature("Hygrodere", "Goo", 1, 2, None), - Creature("Jester", None, 3, 1, None), - Creature("Nutcracker", None, 1, 10, 5), - Creature("Snare Flea", "Head. Bug.", 1, 4, 3), - Creature("Spore Lizard", None, 1, 2, None), - Creature("Thumper", None, 2, 4, 4), - # Hybrid - Creature("Inside Ghost Girl", None, 2, 1, None), - Creature("Inside Masked", None, 1, 10, 4), - ] - - st.markdown("# :red[Lethal Company] Scouter") - st.markdown(":rainbow[What does the scouter say about this moon's power level?]") - - moon_strings = db.get_moon_list() - - moon = st.selectbox( + moon_name = st.selectbox( "Moon", - moon_strings, + db.get_moon_list(), placeholder="Moon! Pick a moon!", help="Pick your current moon.", ) + moon_id = db.get_moon_id_by_name(moon_name) + run = Run(db.get_moon_by_id(moon_id)) - run = Run(next(m for m in moons if m.name is moon)) + st.markdown(f"## {run.moon.name} ({run.moon.tier})") - st.markdown(f"## {run.moon.name} (Tier {run.moon.tier})") + st.info(f"Risk: {run.moon.risk_level} | Min scrap: {run.moon.min_scrap} " + f"| Max scrap: {run.moon.max_scrap} | Default layout: {run.moon.default_layout}") # Begin column layout left_column, right_column = st.columns(2) @@ -112,81 +41,9 @@ def main(): with left_column: st.markdown("### Outside") - with st.form("outside"): - for creature in outside_creatures: - moon_max = min( - creature.max_spawns, run.moon.outside_max_power // creature.power - ) - if moon_max > 0: - st.slider( - creature.name, - 0, - moon_max, - key=creature.name, - help=creature.nickname, - ) - else: - st.slider( - creature.name, - 0, - 1, - key=creature.name, - help=creature.nickname, - disabled=True, - ) - - run.outside_power = run.outside_power - st.session_state[creature.name] - - outside_submit = st.form_submit_button("Calculate") - if outside_submit: - st.info(f"Maximum power: {run.moon.outside_max_power}") - if run.outside_power >= 0: - st.warning(f"🌳 Outside power remaining: {run.outside_power}") - st.write(find_spawn_list(run.outside_power, outside_creatures)) - else: - st.error( - f"Power level exceeds maximum possible for {run.moon.name}." - ) - with right_column: st.markdown("### Inside") - with st.form("inside"): - for creature in inside_creatures: - moon_max = min( - creature.max_spawns, run.moon.inside_max_power // creature.power - ) - if moon_max > 0: - st.slider( - creature.name, - 0, - moon_max, - key=creature.name, - help=creature.nickname, - ) - else: - st.slider( - creature.name, - 0, - 1, - key=creature.name, - help=creature.nickname, - disabled=True, - ) - - run.inside_power = run.inside_power - st.session_state[creature.name] - - inside_submit = st.form_submit_button("Calculate") - if inside_submit: - st.info(f"Maximum power: {run.moon.inside_max_power}") - if run.inside_power >= 0: - st.warning(f"🏭 Inside power remaining: {run.inside_power}") - st.write(find_spawn_list(run.inside_power, inside_creatures)) - else: - st.error( - f"Power level exceeds maximum possible for {run.moon.name}." - ) - if __name__ == "__main__": main() diff --git a/database/database.py b/database/database.py index 2cb1c82..6be6b59 100644 --- a/database/database.py +++ b/database/database.py @@ -2,22 +2,111 @@ import os import sqlite3 +class Moon: + def __init__(self, moon_id, name, risk_level, cost, default_layout, map_size_multiplier, min_scrap, max_scrap, + outside_max_power, inside_max_power, tier): + self.id = moon_id + self.name = name + self.risk_level = risk_level + self.cost = cost + self.default_layout = default_layout, + self.map_size_multiplier = map_size_multiplier + self.min_scrap = min_scrap + self.max_scrap = max_scrap + self.outside_max_power = outside_max_power + self.inside_max_power = inside_max_power + self.tier = tier + + def get_connection() -> sqlite3.Connection: + """Opens a connection to the SQLite3 database at the default path + or a path provided by an environment variable if one exists. + + :return: A connection to the database as a sqlite3.Connection object + """ if os.getenv("DATABASE_FILE"): return sqlite3.connect(os.getenv("DATABASE_FILE")) else: return sqlite3.connect("./scouter.db") +def get_moon_id_by_name(moon_name: str) -> int | None: + """Queries the database for a moon ID that matches the given name. + + :param moon_name: Moon name as a string + :return: The moon's ID as an int or None if no moon is found + """ + with get_connection() as connection: + cursor = connection.cursor() + moon_id = cursor.execute( + "select moon_id " + "from moon " + "where moon_name = ? " + "limit 1;", + (moon_name,) + ).fetchone() + + if moon_id: + return moon_id[0] + else: + return None + + def get_moon_list() -> list[str] | None: + """Provides a list of all moon names from the database. + + :return: All moon names as a list of strings or None if no moons are found + """ with get_connection() as connection: cursor = connection.cursor() moons = cursor.execute( "select moon_name from moon order by moon_id" - ) + ).fetchall() if moons: moons = [moon[0] for moon in moons] return moons else: return None + + +def get_moon_by_id(moon_id: int) -> Moon | None: + """Queries the database to create a moon object. + + :param moon_id: Moon ID as int + :return: A moon object or None if no moon is found + """ + with get_connection() as connection: + connection.text_factory = str + cursor = connection.cursor() + + query = """ + select m.moon_id, + m.moon_name, + rl.risk_level_name, + m.cost, + l.layout_name, + m.map_size_multiplier, + m.min_scrap, + m.max_scrap, + m.outside_max_power, + m.inside_max_power, + mt.tier_name +from moon as m + join main.risk_level rl on rl.risk_level_id = m.risk_level_id + join main.layout l on l.layout_id = m.default_layout_id + join main.moon_tier mt on mt.moon_tier_id = m.moon_tier_id +where m.moon_id = ? +limit 1;""" + + moon = cursor.execute( + query, + (moon_id,) + ).fetchone() + + if moon: + return Moon(*moon) + else: + return None + +print(get_moon_by_id(3).default_layout) \ No newline at end of file