Skip to content

Commit 1b82ae8

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

File tree

2 files changed

+89
-30
lines changed

2 files changed

+89
-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: 81 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,80 @@ 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+
monkeyPoint?: Monster;
701+
humanity?: boolean;
702+
}): Map<Monster, number> {
703+
const olfact = options.olfact ?? get("olfactedMonster");
704+
const longCon = options.longCon ?? get("longConMonster");
705+
const motif = options.motif ?? get("motifMonster");
706+
const turtle = options.turtle ?? get("_gallapagosMonster");
707+
const monkeyPoint = options.monkeyPoint ?? get("monkeyPointMonster");
708+
const snapper = options.snapper ?? myFamiliar() === $familiar`Red-Nosed Snapper`;
709+
const snapperPhylum = options.snapperPhylum ?? Snapper.getTrackedPhylum();
710+
const humanity = options.humanity ?? have($effect`Ew, The Humanity`);
711+
712+
const zoneMonsters = $monsters`garbage tourist, angry tourist, horrible tourist family`;
713+
const encounterQueue = zoneMonsters.filter((m) =>
714+
$location`Barf Mountain`.combatQueue.includes(`${m}`),
715+
);
716+
717+
const cacheKey = [
718+
olfact,
719+
longCon,
720+
motif,
721+
turtle,
722+
monkeyPoint,
723+
snapper,
724+
snapperPhylum,
725+
humanity,
726+
...encounterQueue,
727+
]
728+
.map((v) => `${v}`)
729+
.join(":");
730+
731+
const cachedValue = rateCache.get(cacheKey);
732+
if (cachedValue) {
733+
return cachedValue;
734+
}
735+
736+
const copies = (target: Monster | null, n: number): Monster[] =>
737+
n === 0 ? [] : [...zoneMonsters.filter((m) => m === target), ...copies(target, n - 1)];
738+
739+
const monsterQueue = [
740+
...zoneMonsters,
741+
...copies(olfact, 3),
742+
...copies(longCon, 3),
743+
...copies(motif, 2),
744+
...copies(turtle, 1),
745+
...copies(monkeyPoint, 2),
746+
...zoneMonsters
747+
.filter((m) => snapper && m.phylum === snapperPhylum)
748+
.flatMap((m) => copies(m, 2)),
749+
...zoneMonsters
750+
.filter((m) => humanity && m.phylum === $phylum`dude`)
751+
.flatMap((m) => copies(m, 2)),
752+
];
753+
754+
const encounters = monsterQueue.flatMap((m) =>
755+
monsterQueue.map((n) =>
756+
// olfaction, longcon, and motif caus that monster to ignore queue rejection
757+
olfact === m || longCon === m || motif === m || !encounterQueue.includes(m) ? m : n,
758+
),
759+
);
760+
761+
const encounterRate = new Map<Monster, number>(
762+
zoneMonsters.map((m) => [m, encounters.filter((n) => n === m).length / encounters.length]),
763+
);
764+
rateCache.set(cacheKey, encounterRate);
765+
return encounterRate;
766+
}

0 commit comments

Comments
 (0)