zenno: use a real last spurt phase
This commit is contained in:
+23
-23
@@ -76,36 +76,36 @@ export interface SectionInfo {
|
||||
section: number;
|
||||
phase: Phase;
|
||||
endRate: number;
|
||||
posKeep: boolean;
|
||||
rush: boolean;
|
||||
spotStruggleEnter: boolean;
|
||||
posKeep?: boolean;
|
||||
rush?: boolean;
|
||||
spotStruggleEnter?: boolean;
|
||||
}
|
||||
|
||||
export const SECTIONS: ReadonlyArray<SectionInfo> = [
|
||||
{ section: 1, phase: Phase.EarlyRace, endRate: 1 / 24, posKeep: true, rush: false, spotStruggleEnter: false },
|
||||
{ section: 1, phase: Phase.EarlyRace, endRate: 1 / 24, posKeep: true },
|
||||
{ section: 2, phase: Phase.EarlyRace, endRate: 2 / 24, posKeep: true, rush: true, spotStruggleEnter: true },
|
||||
{ section: 3, phase: Phase.EarlyRace, endRate: 3 / 24, posKeep: true, rush: true, spotStruggleEnter: true },
|
||||
{ section: 4, phase: Phase.EarlyRace, endRate: 4 / 24, posKeep: true, rush: true, spotStruggleEnter: true },
|
||||
{ section: 5, phase: Phase.MidRace, endRate: 5 / 24, posKeep: true, rush: true, spotStruggleEnter: true },
|
||||
{ section: 6, phase: Phase.MidRace, endRate: 6 / 24, posKeep: true, rush: true, spotStruggleEnter: false },
|
||||
{ section: 7, phase: Phase.MidRace, endRate: 7 / 24, posKeep: true, rush: true, spotStruggleEnter: false },
|
||||
{ section: 8, phase: Phase.MidRace, endRate: 8 / 24, posKeep: true, rush: true, spotStruggleEnter: false },
|
||||
{ section: 9, phase: Phase.MidRace, endRate: 9 / 24, posKeep: true, rush: true, spotStruggleEnter: false },
|
||||
{ section: 10, phase: Phase.MidRace, endRate: 10 / 24, posKeep: true, rush: false, spotStruggleEnter: false },
|
||||
{ section: 11, phase: Phase.MidRace, endRate: 11 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 12, phase: Phase.MidRace, endRate: 12 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 13, phase: Phase.MidRace, endRate: 13 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 14, phase: Phase.MidRace, endRate: 14 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 15, phase: Phase.MidRace, endRate: 15 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 16, phase: Phase.MidRace, endRate: 16 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 17, phase: Phase.LateRace, endRate: 17 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 18, phase: Phase.LateRace, endRate: 18 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 19, phase: Phase.LateRace, endRate: 19 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 20, phase: Phase.LateRace, endRate: 20 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 21, phase: Phase.LateRace, endRate: 21 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 22, phase: Phase.LateRace, endRate: 22 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 23, phase: Phase.LateRace, endRate: 23 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 24, phase: Phase.LateRace, endRate: 24 / 24, posKeep: false, rush: false, spotStruggleEnter: false },
|
||||
{ section: 6, phase: Phase.MidRace, endRate: 6 / 24, posKeep: true, rush: true },
|
||||
{ section: 7, phase: Phase.MidRace, endRate: 7 / 24, posKeep: true, rush: true },
|
||||
{ section: 8, phase: Phase.MidRace, endRate: 8 / 24, posKeep: true, rush: true },
|
||||
{ section: 9, phase: Phase.MidRace, endRate: 9 / 24, posKeep: true, rush: true },
|
||||
{ section: 10, phase: Phase.MidRace, endRate: 10 / 24, posKeep: true },
|
||||
{ section: 11, phase: Phase.MidRace, endRate: 11 / 24 },
|
||||
{ section: 12, phase: Phase.MidRace, endRate: 12 / 24 },
|
||||
{ section: 13, phase: Phase.MidRace, endRate: 13 / 24 },
|
||||
{ section: 14, phase: Phase.MidRace, endRate: 14 / 24 },
|
||||
{ section: 15, phase: Phase.MidRace, endRate: 15 / 24 },
|
||||
{ section: 16, phase: Phase.MidRace, endRate: 16 / 24 },
|
||||
{ section: 17, phase: Phase.LateRace, endRate: 17 / 24 },
|
||||
{ section: 18, phase: Phase.LateRace, endRate: 18 / 24 },
|
||||
{ section: 19, phase: Phase.LateRace, endRate: 19 / 24 },
|
||||
{ section: 20, phase: Phase.LateRace, endRate: 20 / 24 },
|
||||
{ section: 21, phase: Phase.LastSpurt, endRate: 21 / 24 },
|
||||
{ section: 22, phase: Phase.LastSpurt, endRate: 22 / 24 },
|
||||
{ section: 23, phase: Phase.LastSpurt, endRate: 23 / 24 },
|
||||
{ section: 24, phase: Phase.LastSpurt, endRate: 24 / 24 },
|
||||
];
|
||||
|
||||
export interface SectionSlopeSegment extends SectionInfo {
|
||||
|
||||
+38
-38
@@ -8,11 +8,11 @@ import { binomPMF } from './prob';
|
||||
* Fundamental stats of umas.
|
||||
*/
|
||||
export enum Stat {
|
||||
Speed,
|
||||
Stamina,
|
||||
Power,
|
||||
Guts,
|
||||
Wit,
|
||||
Speed = 1,
|
||||
Stamina = 2,
|
||||
Power = 3,
|
||||
Guts = 4,
|
||||
Wit = 5,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,14 +118,15 @@ export function distance(raceLen: number): Distance {
|
||||
/**
|
||||
* Get the distances at which each phase of a race ends.
|
||||
* @param raceLen Length of the race in meters
|
||||
* @returns Ends of each phase in meters
|
||||
* @returns Ends of each phase in meters, including separate late and spurt phases
|
||||
*/
|
||||
export function phases(raceLen: number) {
|
||||
const sixth = raceLen / 6;
|
||||
return {
|
||||
[Phase.EarlyRace]: sixth,
|
||||
[Phase.MidRace]: 4 * sixth,
|
||||
[Phase.LateRace]: raceLen,
|
||||
[Phase.LateRace]: 5 * sixth,
|
||||
[Phase.LastSpurt]: raceLen,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,18 +134,18 @@ export function phases(raceLen: number) {
|
||||
* Race surfaces.
|
||||
*/
|
||||
export enum Surface {
|
||||
Turf,
|
||||
Dirt,
|
||||
Turf = 1,
|
||||
Dirt = 2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Race ground condition types.
|
||||
*/
|
||||
export enum GroundConditions {
|
||||
Firm,
|
||||
Good,
|
||||
Soft,
|
||||
Heavy,
|
||||
Firm = 1,
|
||||
Good = 2,
|
||||
Soft = 3,
|
||||
Heavy = 4,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,12 +328,12 @@ export const RUNNING_STYLES = [
|
||||
|
||||
/**
|
||||
* Race phases.
|
||||
* While last spurt phase is also a phase, it is not distinguished here.
|
||||
*/
|
||||
export enum Phase {
|
||||
EarlyRace,
|
||||
MidRace,
|
||||
LateRace,
|
||||
EarlyRace = 0,
|
||||
MidRace = 1,
|
||||
LateRace = 2,
|
||||
LastSpurt = 3,
|
||||
}
|
||||
|
||||
const hpStrategyCoeff = {
|
||||
@@ -407,7 +408,7 @@ export function hpPerSecond(
|
||||
const pdmMod = pdm ? 0.6 : 1;
|
||||
const damMod = dam ? 0.4 : 1;
|
||||
const groundMod = groundHPRateMod[surface][conditions];
|
||||
const gutsMod = phase === Phase.LateRace ? 1 + 200 / (math.sqrt(600 * gutsStat) as number) : 1;
|
||||
const gutsMod = phase >= Phase.LateRace ? 1 + 200 / (math.sqrt(600 * gutsStat) as number) : 1;
|
||||
const sp = currentSpeed - baseSpeed(raceLen) + 12;
|
||||
return (20 / 144) * sp * sp * rushedMod * pdmMod * damMod * groundMod * gutsMod;
|
||||
}
|
||||
@@ -447,11 +448,11 @@ export function baseSpeed(raceLen: number): number {
|
||||
}
|
||||
|
||||
const speedStrategyPhaseCoeff = [
|
||||
[1.0, 0.98, 0.962],
|
||||
[0.978, 0.991, 0.975],
|
||||
[0.938, 0.998, 0.994],
|
||||
[0.931, 1.0, 1.0],
|
||||
[1.063, 0.962, 0.95],
|
||||
[1.0, 0.98, 0.962, 0.962],
|
||||
[0.978, 0.991, 0.975, 0.975],
|
||||
[0.938, 0.998, 0.994, 0.994],
|
||||
[0.931, 1.0, 1.0, 1.0],
|
||||
[1.063, 0.962, 0.95, 0.95],
|
||||
] as const;
|
||||
|
||||
const distanceProficiencyMod: Readonly<Record<AptitudeLevel, number>> = {
|
||||
@@ -471,7 +472,7 @@ const distanceProficiencyMod: Readonly<Record<AptitudeLevel, number>> = {
|
||||
* @param style Horse's running style
|
||||
* @param phase Phase to calculate for
|
||||
*/
|
||||
export function baseTargetSpeed(raceLen: number, style: RunningStyle, phase: Exclude<Phase, Phase.LateRace>): number;
|
||||
export function baseTargetSpeed(raceLen: number, style: RunningStyle, phase: Exclude<Phase, Phase.LateRace | Phase.LastSpurt>): number;
|
||||
/**
|
||||
* Get a horse's base target speed when not spurting during late race.
|
||||
* @param raceLen Length of the race in meters
|
||||
@@ -483,7 +484,7 @@ export function baseTargetSpeed(raceLen: number, style: RunningStyle, phase: Exc
|
||||
export function baseTargetSpeed(
|
||||
raceLen: number,
|
||||
style: RunningStyle,
|
||||
phase: Phase.LateRace,
|
||||
phase: Phase.LateRace | Phase.LastSpurt,
|
||||
speedStat: number,
|
||||
distanceApt: AptitudeLevel,
|
||||
): number;
|
||||
@@ -497,7 +498,7 @@ export function baseTargetSpeed(
|
||||
const base = baseSpeed(raceLen);
|
||||
const baseTarget = base * speedStrategyPhaseCoeff[style][phase];
|
||||
const late =
|
||||
phase === Phase.LateRace ? (math.sqrt(500 * speedStat!) as number) * distanceProficiencyMod[distanceApt!] * 0.002 : 0;
|
||||
phase >= Phase.LateRace ? (math.sqrt(500 * speedStat!) as number) * distanceProficiencyMod[distanceApt!] * 0.002 : 0;
|
||||
return baseTarget + late;
|
||||
}
|
||||
|
||||
@@ -512,7 +513,7 @@ export function sectionSpeed(
|
||||
raceLen: number,
|
||||
witStat: number,
|
||||
style: RunningStyle,
|
||||
phase: Exclude<Phase, Phase.LateRace>,
|
||||
phase: Exclude<Phase, Phase.LateRace | Phase.LastSpurt>,
|
||||
): [number, number];
|
||||
/**
|
||||
* Calculate the range of section speed values for a horse not spurting during late race.
|
||||
@@ -529,7 +530,7 @@ export function sectionSpeed(
|
||||
witStat: number,
|
||||
style: RunningStyle,
|
||||
distance: AptitudeLevel,
|
||||
phase: Phase.LateRace,
|
||||
phase: Phase.LateRace | Phase.LastSpurt,
|
||||
): [number, number];
|
||||
export function sectionSpeed(
|
||||
raceLen: number,
|
||||
@@ -537,7 +538,7 @@ export function sectionSpeed(
|
||||
witStatOrStyle: number | RunningStyle,
|
||||
styleOrPhase: RunningStyle | Phase,
|
||||
distance?: AptitudeLevel,
|
||||
lateRace?: Phase.LateRace,
|
||||
lateRace?: Phase.LateRace | Phase.LastSpurt,
|
||||
): [number, number] {
|
||||
const speedStat = lateRace !== undefined ? speedStatOrWitStat : 0;
|
||||
const witStat = lateRace !== undefined ? witStatOrStyle : speedStatOrWitStat;
|
||||
@@ -546,7 +547,7 @@ export function sectionSpeed(
|
||||
const base = baseSpeed(raceLen);
|
||||
const baseTarget = base * speedStrategyPhaseCoeff[style][phase];
|
||||
const late =
|
||||
phase === Phase.LateRace
|
||||
phase >= Phase.LateRace
|
||||
? (math.sqrt(500 * speedStat) as number) * distanceProficiencyMod[distance ?? AptitudeLevel.A] * 0.002
|
||||
: 0;
|
||||
const u = (witStat / 550000) * math.log10(witStat * 0.1);
|
||||
@@ -620,11 +621,11 @@ export const COURSE_WIDTH = 11.25;
|
||||
export const LANE_WIDTH = COURSE_WIDTH / 18;
|
||||
|
||||
const accelStrategyPhaseCoeff = {
|
||||
[RunningStyle.FrontRunner]: [1.0, 1.0, 0.996],
|
||||
[RunningStyle.PaceChaser]: [0.985, 1.0, 0.996],
|
||||
[RunningStyle.LateSurger]: [0.975, 1.0, 1.0],
|
||||
[RunningStyle.EndCloser]: [0.945, 1.0, 0.997],
|
||||
[RunningStyle.Runaway]: [1.17, 0.94, 0.956],
|
||||
[RunningStyle.FrontRunner]: [1.0, 1.0, 0.996, 0.996],
|
||||
[RunningStyle.PaceChaser]: [0.985, 1.0, 0.996, 0.996],
|
||||
[RunningStyle.LateSurger]: [0.975, 1.0, 1.0, 1.0],
|
||||
[RunningStyle.EndCloser]: [0.945, 1.0, 0.997, 0.997],
|
||||
[RunningStyle.Runaway]: [1.17, 0.94, 0.956, 0.956],
|
||||
} as const;
|
||||
|
||||
const surfaceProficiencyMod: Readonly<Record<AptitudeLevel, number>> = {
|
||||
@@ -681,6 +682,7 @@ const phaseDecel = {
|
||||
[Phase.EarlyRace]: -1.2,
|
||||
[Phase.MidRace]: -0.8,
|
||||
[Phase.LateRace]: -1.0,
|
||||
[Phase.LastSpurt]: -1.0,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
@@ -695,9 +697,7 @@ export function deceleration(phase: Phase, pdm?: boolean, dead?: boolean): numbe
|
||||
return -1.2;
|
||||
}
|
||||
if (pdm) {
|
||||
// This isn't until 1.5anni.
|
||||
// return -0.5;
|
||||
return phaseDecel[phase];
|
||||
return -0.5;
|
||||
}
|
||||
return phaseDecel[phase];
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@
|
||||
const distance = $derived([last(seggs[0]).end.x, last(seggs[1]).end.x] as const);
|
||||
const time = $derived([last(seggs[0]).end.t, last(seggs[1]).end.t] as const);
|
||||
const finishTime = $derived([
|
||||
time[0] + (phases[race.Phase.LateRace] - distance[0]) / spurtSpeed,
|
||||
time[1] + (phases[race.Phase.LateRace] - distance[1]) / spurtSpeed,
|
||||
time[0] + (raceLen - distance[0]) / spurtSpeed,
|
||||
time[1] + (raceLen - distance[1]) / spurtSpeed,
|
||||
] as const);
|
||||
function gainLengths(fast: accel.Instant, slow: accel.Instant): number {
|
||||
const m = fast.v * (slow.t - fast.t) + fast.x - slow.x;
|
||||
|
||||
@@ -103,6 +103,10 @@
|
||||
race.spurtSpeed(stats[race.Stat.Speed], stats[race.Stat.Guts], style, distanceApt, raceLen),
|
||||
race.spurtSpeed(stats[race.Stat.Speed], stats[race.Stat.Guts], style, distanceApt, raceLen),
|
||||
] as [number, number],
|
||||
[race.Phase.LastSpurt]: [
|
||||
race.spurtSpeed(stats[race.Stat.Speed], stats[race.Stat.Guts], style, distanceApt, raceLen),
|
||||
race.spurtSpeed(stats[race.Stat.Speed], stats[race.Stat.Guts], style, distanceApt, raceLen),
|
||||
] as [number, number],
|
||||
});
|
||||
|
||||
// const isFront = $derived(style === race.RunningStyle.FrontRunner || style === race.RunningStyle.Runaway);
|
||||
|
||||
Reference in New Issue
Block a user