Skip to content

Commit 0bfb3b3

Browse files
committed
Improve snapper encounter rate computation
1 parent adebb7f commit 0bfb3b3

File tree

2 files changed

+85
-30
lines changed

2 files changed

+85
-30
lines changed

src/familiar/freeFightFamiliar.ts

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { Familiar, familiarWeight, inebrietyLimit, Location, myInebriety } from "kolmafia";
1+
import { Familiar, familiarWeight, inebrietyLimit, Location, Monster, myInebriety } from "kolmafia";
22
import {
33
$familiar,
44
$item,
55
$location,
6-
$monsters,
76
$phylum,
8-
$skill,
97
clamp,
108
findLeprechaunMultiplier,
119
get,
@@ -19,6 +17,7 @@ import getDropFamiliars from "./dropFamiliars";
1917
import getExperienceFamiliars from "./experienceFamiliars";
2018
import { GeneralFamiliar, timeToMeatify } from "./lib";
2119
import { meatFamiliar } from "./meatFamiliar";
20+
import { barfEncounterRate } from "../lib";
2221

2322
type MenuOptions = {
2423
canChooseMacro?: boolean;
@@ -86,33 +85,12 @@ export function menu(options: MenuOptions = {}): GeneralFamiliar[] {
8685
Snapper.have() &&
8786
Snapper.getTrackedPhylum() === $phylum`dude`
8887
) {
89-
/*
90-
# E stands for olfacted Garbage Tourist, A is angry toursit, F is horrible tourist family
91-
import itertools
92-
def rate(q):
93-
m = ["E"] * 5 + ["A"] * 2 + ["F"] * 2
94-
options = list(itertools.product(m, m))
95-
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")]
96-
return len(dude) / 81
97-
*/
98-
99-
const dudes = $monsters`angry tourist, horrible tourist family`.filter((m) =>
100-
$location`Barf Mountain`.combatQueue.includes(`${m}`),
101-
).length;
102-
103-
// if you don't have olfaction, just assume a simple rate calculation
104-
const noOlfactRate = 4 / (1 + 4 + (have($skill`Gallapagosian Mating Call`) ? 1 : 0));
105-
106-
// when you have olfaction, you
107-
// using the above python script, dude rate for number of dudes in queue is:
108-
const olfactRate =
109-
[
110-
0.44, // 0 dudes = 44% chance
111-
0.32, // 1 dude = 32% chance
112-
0.19, // 2 dudes = 19% chance
113-
][dudes] ?? 0;
114-
115-
const dudeRate = have($skill`Transcendent Olfaction`) ? olfactRate : noOlfactRate;
88+
const encounterRate = barfEncounterRate({ snapper: true, snapperPhylum: $phylum`dude` });
89+
const dudeRate = [...encounterRate.entries()].reduce(
90+
(acc: number, entry: [Monster, number]) =>
91+
entry[0].phylum === $phylum`dude` ? entry[1] + acc : acc,
92+
0,
93+
);
11694

11795
familiarMenu.push({
11896
familiar: $familiar`Red-Nosed Snapper`,

src/lib.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
mySoulsauce,
3535
myTurncount,
3636
numericModifier,
37+
Phylum,
3738
print,
3839
printHtml,
3940
restoreHp,
@@ -60,6 +61,8 @@ import {
6061
$item,
6162
$location,
6263
$monster,
64+
$monsters,
65+
$phylum,
6366
$skill,
6467
$slot,
6568
ActionSource,
@@ -80,6 +83,7 @@ import {
8083
PropertiesManager,
8184
property,
8285
set,
86+
Snapper,
8387
SongBoom,
8488
sum,
8589
uneffect,
@@ -683,3 +687,76 @@ export function printEventLog(): void {
683687
);
684688
}
685689
}
690+
691+
const rateCache = new Map<string, Map<Monster, number>>();
692+
693+
export function barfEncounterRate(options: {
694+
snapper?: boolean;
695+
snapperPhylum?: Phylum;
696+
olfact?: Monster;
697+
longCon?: Monster;
698+
motif?: Monster;
699+
turtle?: Monster;
700+
humanity?: boolean;
701+
}): Map<Monster, number> {
702+
const olfact = options.olfact ?? get("olfactedMonster");
703+
const longCon = options.longCon ?? get("longConMonster");
704+
const motif = options.motif ?? get("motifMonster");
705+
const turtle = options.turtle ?? get("_gallapagosMonster");
706+
const snapper = options.snapper ?? myFamiliar() === $familiar`Red-Nosed Snapper`;
707+
const snapperPhylum = options.snapperPhylum ?? Snapper.getTrackedPhylum();
708+
const humanity = options.humanity ?? have($effect`Ew, The Humanity`);
709+
710+
const zoneMonsters = $monsters`garbage tourist, angry tourist, horrible tourist family`;
711+
const encounterQueue = zoneMonsters.filter((m) =>
712+
$location`Barf Mountain`.combatQueue.includes(`${m}`),
713+
);
714+
715+
const cacheKey = [
716+
olfact,
717+
longCon,
718+
motif,
719+
turtle,
720+
snapper,
721+
snapperPhylum,
722+
humanity,
723+
...encounterQueue,
724+
]
725+
.map((v) => `${v}`)
726+
.join(":");
727+
728+
const cachedValue = rateCache.get(cacheKey);
729+
if (cachedValue) {
730+
return cachedValue;
731+
}
732+
733+
const copies = (target: Monster | null, n: number): Monster[] =>
734+
n === 0 ? [] : [...zoneMonsters.filter((m) => m === target), ...copies(target, n - 1)];
735+
736+
const monsterQueue = [
737+
...zoneMonsters,
738+
...copies(olfact, 3),
739+
...copies(longCon, 3),
740+
...copies(motif, 2),
741+
...copies(turtle, 1),
742+
...zoneMonsters
743+
.filter((m) => snapper && m.phylum === snapperPhylum)
744+
.flatMap((m) => copies(m, 2)),
745+
...zoneMonsters
746+
.filter((m) => humanity && m.phylum === $phylum`dude`)
747+
.flatMap((m) => copies(m, 2)),
748+
];
749+
750+
const encounters = monsterQueue.flatMap((m) =>
751+
monsterQueue.map((n) =>
752+
// olfaction, longcon, and motif caus that monster to ignore queue rejection
753+
olfact === m || longCon === m || motif === m || !encounterQueue.includes(m) ? m : n,
754+
),
755+
);
756+
757+
const encounterRate = new Map<Monster, number>(
758+
zoneMonsters.map((m) => [m, encounters.filter((n) => n === m).length / encounters.length]),
759+
);
760+
rateCache.set(cacheKey, encounterRate);
761+
return encounterRate;
762+
}

0 commit comments

Comments
 (0)