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