Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import collections
- import random
- import math
- import statistics
- class Utils:
- def log(message):
- print(message)
- class Simulator():
- def level_10_quest1(self, player_state):
- basement = Basement()
- while basement.progress < 1:
- basement.resolve_turn(player_state)
- return player_state
- def level_10_quest3(self, player_state):
- topfloor = TopFloor()
- while topfloor.progress < 1:
- topfloor.resolve_turn(player_state)
- return player_state
- def run_simulator(self, iterations = 100000):
- turns1 = []
- turns3 = []
- for a in range(iterations):
- player_state = self.level_10_quest1(PlayerState())
- turns1.append(player_state.total_turns_spent)
- if player_state.stench_jellies:
- pass
- elif player_state.get_amulet():
- Utils.log("In {} instances at {}% +NC, with an amulet, it took an average of {} turns to complete the basement, with a median of {} and a deviation of {}."
- .format(iterations, PlayerState().player_nc, statistics.mean(turns1), statistics.median(turns1), statistics.pstdev(turns1)))
- else:
- Utils.log("In {} instances at {}% +NC, with no amulet, it took an average of {} turns to complete the basement, with a median of {} and a deviation of {}."
- .format(iterations, PlayerState().player_nc, statistics.mean(turns1), statistics.median(turns1), statistics.pstdev(turns1)))
- for a in range(iterations):
- player_state = self.level_10_quest3(PlayerState())
- turns3.append(player_state.total_turns_spent)
- if player_state.stench_jellies:
- pass
- elif player_state.get_mohawk_wig():
- Utils.log("In {} instances at {}% +NC, with a mohawk wig, it took an average of {} turns to complete the top floor, with a median of {} and a deviation of {}."
- .format(iterations, PlayerState().player_nc, statistics.mean(turns3), statistics.median(turns3), statistics.pstdev(turns3)))
- else:
- Utils.log("In {} instances at {}% +NC, with no mohawk wig, it took an average of {} turns to complete the top floor, with a median of {} and a deviation of {}."
- .format(iterations, PlayerState().player_nc, statistics.mean(turns3), statistics.median(turns3), statistics.pstdev(turns3)))
- class PlayerState():
- def __init__(self):
- self.player_nc = 25 # CHANGE NC HERE
- self.player_item = 700 # CHANGE +ITEM% HERE
- self.total_turns_spent = 0
- self.wishes = 3
- self.banishes = [
- Banish("Spring Bumper", 30, 999, True, True),
- Banish("Throw Latte", 30, 4, True, True),
- Banish("Reflex hammer", 30, 3, False, True),
- Banish("KGB dart", 20, 3, False, True),
- Banish("Batter Up!", 9999, 999, False, False),
- ]
- self.olfacted_mob = None
- self.latted_mob = None
- self.mated_mob = None
- self.stench_jellies = 0
- self.food_quality = 25
- self.massive_dumbbell = 0
- self.bass_record = 0
- self.model_rocketship = 0
- self.mohawk_wig = 1
- self.amulet = 1
- self.grops_encounters = 0
- self.smoke_bombs = 0
- def nc_mod(self):
- return mod_cap(self.player_nc)
- def item_mod(self):
- return 1 + (self.player_item/100)
- def get_total_turns_spent(self):
- return self.total_turns_spent
- def get_wishes(self):
- return self.wishes
- def get_massive_dumbbell(self):
- return self.massive_dumbbell
- def get_bass_record(self):
- return self.bass_record
- def get_model_rocketship(self):
- return self.model_rocketship
- def get_amulet(self):
- return self.amulet
- def get_mohawk_wig(self):
- return self.mohawk_wig
- def get_extra_copies(self, encounter_name):
- return (
- 0 +
- (3 if self.olfacted_mob == encounter_name else 0) +
- (2 if self.latted_mob == encounter_name else 0) +
- (1 if self.mated_mob == encounter_name else 0)
- )
- def need_sniffs(self, encounter):
- if encounter.get_use_all_sniffs():
- self.olfacted_mob = encounter.name
- self.latted_mob = encounter.name
- self.mated_mob = encounter.name
- else:
- if encounter.use_olfact:
- self.olfacted_mob = encounter.name
- if encounter.use_latte:
- self.latted_mob = encounter.name
- if encounter.use_mating:
- self.mated_mob = encounter.name
- def check_banish(self, encounter):
- avail_banish = None
- for banish in self.banishes:
- if banish.get_banished_mob() == encounter.name:
- return False
- if (not avail_banish) and (banish.check(self)):
- avail_banish = banish
- return avail_banish
- def use_banish(self, location, encounter):
- banish = self.check_banish(encounter)
- if banish:
- banish.use(self, location, encounter)
- return True
- return False
- def mod_cap(virgin_mod):
- if virgin_mod < 0:
- return 0
- if virgin_mod > 25:
- return 20 + math.floor(virgin_mod/5)
- return virgin_mod
- class Banish():
- def __init__(self, name = "", length = 30, avail_uses = 3, cooldown = False, free = True):
- self.name = name
- self.length = length
- self.avail_uses = avail_uses
- self.cooldown = cooldown
- self.free = free
- self.banished_mob = None
- self.expiry = -1
- def get_avail_uses(self):
- return self.avail_uses
- def get_expiry(self):
- return self.expiry
- def get_banished_mob(self):
- if self.get_expiry() < player_state.get_total_turns_spent():
- return None
- return self.banished_mob
- def check(self, player_state):
- return (self.get_avail_uses()) and (self.get_expiry() < player_state.get_total_turns_spent())
- def use(self, location, player_state, encounter):
- self.banished_mob = encounter.name
- self.avail_uses -= 1
- self.expiry = player_state.get_total_turns_spent() + self.length
- location.banishes_used += 1
- class Encounter():
- def __init__(self, name = "", banish = False, itembase = 0):
- self.name = name
- self.wish = False
- self.should_banish = banish
- self.use_all_sniffs = False
- self.use_olfact = False
- self.use_latte = False
- self.use_mating = False
- def __str__(self):
- return "Encounter({})".format(self.name)
- def get_use_all_sniffs(self):
- return self.use_all_sniffs
- def check(self, location, player_state):
- return True
- def add_nc_queue(self, location, nc = None):
- if nc is None:
- nc = self.name
- location.nc_history.append(nc)
- def add_com_queue(self, location, combat = None):
- if combat is None:
- combat = self.name
- location.combat_history.append(combat)
- def run(self, location, player_state):
- if self.should_banish:
- player_state.use_banish(location, encounter)
- return True
- location.turns_spent += 1
- location.pity_timer += 1
- player_state.total_turns_spent += 1
- class Location():
- def __init__(self, native_nc, superlikelies, non_combats, combats):
- self.native_nc = native_nc
- self.superlikelies = superlikelies
- self.non_combats = non_combats
- self.combats = combats
- self.nc_history = collections.deque([], 5)
- self.combat_history = collections.deque([], 5)
- self.banishes_used = 0
- self.turns_spent = 0
- def select_encounter(self, player_state):
- encounter = self.check_superlikely(player_state)
- if encounter is None:
- encounter = self.select_nc(player_state)
- if encounter is None:
- encounter = self.select_combat(player_state)
- return encounter
- def check_superlikely(self, player_state):
- for superlikely in self.superlikelies:
- if superlikely.check(self, player_state):
- return superlikely
- return None
- def weighted_random(self, weights):
- total = sum(weight for item, weight in weights.items())
- r = random.randint(1, total)
- for (item, weight) in weights.items():
- r -= weight
- if r <= 0:
- return item
- def get_nc_weights(self, player_state):
- nc_weights = {}
- for name in [x.name for x in self.non_combats if x.check(self, player_state)]:
- if not name in nc_weights.keys():
- copies = 1 #+ player_state.get_extra_copies(name)
- nc_weights[name] = copies if (name in self.nc_history) else (4 * copies)
- else:
- nc_weights[name] += 1 if (name in self.nc_history) else 4
- return nc_weights
- def nc_queue(self, nc):
- if (nc.name in self.nc_history) and (random.randrange(4)):
- return None
- return nc
- def select_nc(self, player_state):
- if self.native_nc == 0:
- return None
- actual_nc = self.native_nc + player_state.player_nc
- avail_ncs = [x for x in self.non_combats if x.check(self, player_state)]
- if (len(avail_ncs)) and ((random.randrange(100) < actual_nc) or (self.pity_timer == 10)):
- encounter = None
- while encounter is None:
- encounter = self.nc_queue(random.choice(avail_ncs))
- return encounter
- return None
- def get_combat_weights(self, player_state):
- combat_weights = {}
- for name in [x.name for x in self.combats if x.check(self, player_state)]:
- if not name in combat_weights.keys():
- copies = 1 + player_state.get_extra_copies(name)
- combat_weights[name] = copies if (name in self.combat_history and not player_state.olfacted_mob == name) else (4 * copies)
- else:
- combat_weights[name] += 1 if (name in self.combat_history and not player_state.olfacted_mob == name) else 4
- return combat_weights
- def select_combat(self, player_state):
- encounter_name = self.weighted_random(self.get_combat_weights(player_state))
- return [x for x in self.combats if x.name == encounter_name][0]
- def resolve_turn(self, player_state):
- encounter = None
- loops = 0
- while (encounter is None) and (loops < 100):
- encounter = self.select_encounter(player_state)
- loops += 1
- if encounter is not None:
- encounter.run(self, player_state)
- class Basement(Location):
- class Furry(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_massive_dumbbell():
- location.progress = 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- return True
- elif player_state.get_amulet():
- location.progress = 1
- else:
- player_state.massive_dumbbell += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1 #nothing added to queue because taking the superlikely is optimal.
- class Source(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_massive_dumbbell():
- location.progress = 1
- self.add_nc_queue(location)
- elif player_state.get_amulet():
- location.progress = 1 #nothing added to queue because taking the superlikely (in case).
- else:
- player_state.massive_dumbbell += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1 #nothing added to queue because taking the superlikely is optimal.
- class Gym(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_massive_dumbbell():
- location.pity_timer = 0
- return False
- elif player_state.get_amulet():
- location.progress = 1
- else:
- player_state.massive_dumbbell += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- def __init__(self):
- Location.__init__(
- self,
- 5,
- [],
- [ Basement.Furry("Furry"),
- Basement.Source("Source"),
- Basement.Gym("Gym")
- ],
- [
- Encounter("Alphabet Giant"),
- Encounter("Fitness Giant"),
- Encounter("Furry Giant"),
- Encounter("Neckbeard Giant")
- ]
- )
- self.progress = 0
- self.pity_timer = 0
- def get_progress(self):
- return self.progress
- class TopFloor(Location):
- class Steam(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_bass_record():
- location.progress = 1
- elif player_state.get_model_rocketship():
- location.pity_timer = 0
- return True;
- else:
- player_state.model_rocketship += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- class Goth(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_bass_record():
- location.progress = 1
- elif player_state.get_model_rocketship():
- location.pity_timer = 0
- return True;
- else:
- player_state.model_rocketship += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- class Punk(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_mohawk_wig():
- location.progress = 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- elif not player_state.get_bass_record():
- player_state.bass_record += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- else:
- location.pity_timer = 0
- return True;
- class Raver(Encounter):
- def __init__(self, name = ""):
- self.name = name
- def run(self, location, player_state):
- if player_state.get_mohawk_wig():
- location.progress = 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- elif not player_state.get_bass_record():
- player_state.bass_record += 1
- location.turns_spent += 1
- location.pity_timer = 0
- player_state.total_turns_spent += 1
- self.add_nc_queue(location)
- else:
- pass
- def __init__(self):
- Location.__init__(
- self,
- 5,
- [],
- [ TopFloor.Steam("Steam"),
- TopFloor.Goth("Goth"),
- TopFloor.Punk("Punk"),
- TopFloor.Raver("Raver")
- ],
- [
- Encounter("Goth Giant"),
- Encounter("Punk Rock Giant"),
- Encounter("Raver Giant"),
- Encounter("Steampunk Giant")
- ]
- )
- self.progress = 0
- self.pity_timer = 0
- def get_progress(self):
- return self.progress
- if __name__ == "__main__":
- Simulator().run_simulator()
Advertisement
Add Comment
Please, Sign In to add comment