Skip to content

Commit

Permalink
Improve snapper encounter rate computation
Browse files Browse the repository at this point in the history
  • Loading branch information
pstalcup committed Sep 21, 2023
1 parent adebb7f commit 1b82ae8
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 30 deletions.
38 changes: 8 additions & 30 deletions src/familiar/freeFightFamiliar.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Familiar, familiarWeight, inebrietyLimit, Location, myInebriety } from "kolmafia";
import { Familiar, familiarWeight, inebrietyLimit, Location, Monster, myInebriety } from "kolmafia";
import {
$familiar,
$item,
$location,
$monsters,
$phylum,
$skill,
clamp,
findLeprechaunMultiplier,
get,
Expand All @@ -19,6 +17,7 @@ import getDropFamiliars from "./dropFamiliars";
import getExperienceFamiliars from "./experienceFamiliars";
import { GeneralFamiliar, timeToMeatify } from "./lib";
import { meatFamiliar } from "./meatFamiliar";
import { barfEncounterRate } from "../lib";

type MenuOptions = {
canChooseMacro?: boolean;
Expand Down Expand Up @@ -86,33 +85,12 @@ export function menu(options: MenuOptions = {}): GeneralFamiliar[] {
Snapper.have() &&
Snapper.getTrackedPhylum() === $phylum`dude`
) {
/*
# E stands for olfacted Garbage Tourist, A is angry toursit, F is horrible tourist family
import itertools
def rate(q):
m = ["E"] * 5 + ["A"] * 2 + ["F"] * 2
options = list(itertools.product(m, m))
dude = [m for m in options if (m[0] in ["A", "F"] and m[0] not in q) or (m[1] in ["A", "F"] and m[0] in q and m[0] != "E")]
return len(dude) / 81
*/

const dudes = $monsters`angry tourist, horrible tourist family`.filter((m) =>
$location`Barf Mountain`.combatQueue.includes(`${m}`),
).length;

// if you don't have olfaction, just assume a simple rate calculation
const noOlfactRate = 4 / (1 + 4 + (have($skill`Gallapagosian Mating Call`) ? 1 : 0));

// when you have olfaction, you
// using the above python script, dude rate for number of dudes in queue is:
const olfactRate =
[
0.44, // 0 dudes = 44% chance
0.32, // 1 dude = 32% chance
0.19, // 2 dudes = 19% chance
][dudes] ?? 0;

const dudeRate = have($skill`Transcendent Olfaction`) ? olfactRate : noOlfactRate;
const encounterRate = barfEncounterRate({ snapper: true, snapperPhylum: $phylum`dude` });
const dudeRate = [...encounterRate.entries()].reduce(
(acc: number, entry: [Monster, number]) =>
entry[0].phylum === $phylum`dude` ? entry[1] + acc : acc,
0,
);

familiarMenu.push({
familiar: $familiar`Red-Nosed Snapper`,
Expand Down
81 changes: 81 additions & 0 deletions src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
mySoulsauce,
myTurncount,
numericModifier,
Phylum,
print,
printHtml,
restoreHp,
Expand All @@ -60,6 +61,8 @@ import {
$item,
$location,
$monster,
$monsters,
$phylum,
$skill,
$slot,
ActionSource,
Expand All @@ -80,6 +83,7 @@ import {
PropertiesManager,
property,
set,
Snapper,
SongBoom,
sum,
uneffect,
Expand Down Expand Up @@ -683,3 +687,80 @@ export function printEventLog(): void {
);
}
}

const rateCache = new Map<string, Map<Monster, number>>();

export function barfEncounterRate(options: {
snapper?: boolean;
snapperPhylum?: Phylum;
olfact?: Monster;
longCon?: Monster;
motif?: Monster;
turtle?: Monster;
monkeyPoint?: Monster;
humanity?: boolean;
}): Map<Monster, number> {
const olfact = options.olfact ?? get("olfactedMonster");
const longCon = options.longCon ?? get("longConMonster");
const motif = options.motif ?? get("motifMonster");
const turtle = options.turtle ?? get("_gallapagosMonster");
const monkeyPoint = options.monkeyPoint ?? get("monkeyPointMonster");
const snapper = options.snapper ?? myFamiliar() === $familiar`Red-Nosed Snapper`;
const snapperPhylum = options.snapperPhylum ?? Snapper.getTrackedPhylum();
const humanity = options.humanity ?? have($effect`Ew, The Humanity`);

const zoneMonsters = $monsters`garbage tourist, angry tourist, horrible tourist family`;
const encounterQueue = zoneMonsters.filter((m) =>
$location`Barf Mountain`.combatQueue.includes(`${m}`),
);

const cacheKey = [
olfact,
longCon,
motif,
turtle,
monkeyPoint,
snapper,
snapperPhylum,
humanity,
...encounterQueue,
]
.map((v) => `${v}`)
.join(":");

const cachedValue = rateCache.get(cacheKey);
if (cachedValue) {
return cachedValue;
}

const copies = (target: Monster | null, n: number): Monster[] =>
n === 0 ? [] : [...zoneMonsters.filter((m) => m === target), ...copies(target, n - 1)];

const monsterQueue = [
...zoneMonsters,
...copies(olfact, 3),
...copies(longCon, 3),
...copies(motif, 2),
...copies(turtle, 1),
...copies(monkeyPoint, 2),
...zoneMonsters
.filter((m) => snapper && m.phylum === snapperPhylum)
.flatMap((m) => copies(m, 2)),
...zoneMonsters
.filter((m) => humanity && m.phylum === $phylum`dude`)
.flatMap((m) => copies(m, 2)),
];

const encounters = monsterQueue.flatMap((m) =>
monsterQueue.map((n) =>
// olfaction, longcon, and motif caus that monster to ignore queue rejection
olfact === m || longCon === m || motif === m || !encounterQueue.includes(m) ? m : n,
),
);

const encounterRate = new Map<Monster, number>(
zoneMonsters.map((m) => [m, encounters.filter((n) => n === m).length / encounters.length]),
);
rateCache.set(cacheKey, encounterRate);
return encounterRate;
}

0 comments on commit 1b82ae8

Please sign in to comment.