refactor: calculating stock speed limit

This commit is contained in:
2025-05-31 14:21:43 +02:00
parent 39f2688611
commit 32fbf51943
6 changed files with 63 additions and 210 deletions
+5 -15
View File
@@ -2,10 +2,7 @@
<div class="stock-specs">
<div v-if="store.chosenStorageStockName || chosenRealComposition">
<b v-if="store.chosenStorageStockName">
<span
class="text--accent"
:title="store.chosenStorageStockName.length > 41 ? store.chosenStorageStockName : ''"
>
<span class="text--accent" :title="store.chosenStorageStockName.length > 41 ? store.chosenStorageStockName : ''">
<BookmarkCheck :size="19" />
{{ store.chosenStorageStockName.slice(0, 40) }}
{{ store.chosenStorageStockName.length > 41 ? '...' : '' }}
@@ -16,11 +13,7 @@
<b class="real-stock-info" v-if="chosenRealComposition">
<span class="text--accent">
<img
class="real-stock-icon"
:src="getIconURL(chosenRealComposition.type)"
:alt="chosenRealComposition.type"
/>
<img class="real-stock-icon" :src="getIconURL(chosenRealComposition.type)" :alt="chosenRealComposition.type" />
{{ chosenRealComposition.number }} {{ chosenRealComposition.name }}
</span>
</b>
@@ -30,14 +23,11 @@
{{ $t('stocklist.mass') }}
<span class="text--accent">{{ (store.totalWeight / 1000).toFixed(1) }}t</span>
({{ $t('stocklist.mass-accepted') }}:
<span class="text--accent">{{
store.acceptableWeight ? `${~~(store.acceptableWeight / 1000)}t` : '-'
}}</span
<span class="text--accent">{{ store.acceptableWeight ? `${~~(store.acceptableWeight / 1000)}t` : '-' }}</span
>) - {{ $t('stocklist.length') }}:
<span class="text--accent">{{ store.totalLength }}m</span>
- {{ $t('stocklist.vmax') }}
<span tabindex="0" :data-tooltip="$t('stocklist.disclaimer')">(?)</span>:
<span class="text--accent">{{ store.maxStockSpeed }} km/h</span>
- {{ $t('stocklist.vmax') }} <span tabindex="0" :data-tooltip="$t('stocklist.disclaimer')">(?)</span>:
<span class="text--accent">{{ isFinite(store.maxStockSpeed) ? store.maxStockSpeed : '--' }} km/h</span>
</span>
</div>
</template>
-153
View File
@@ -1,153 +0,0 @@
{
"EU07": {
"passenger": {
"650000": 125
},
"cargo": {
"2000000": 70
},
"none": 110
},
"4E": {
"passenger": {
"650000": 125
},
"cargo": {
"2000000": 70
},
"none": 110
},
"EU07E": {
"passenger": {
"650000": 125
},
"cargo": {
"2000000": 70
},
"none": 110
},
"EP07": {
"passenger": {
"650000": 125
},
"cargo": null,
"none": 110
},
"EP08": {
"passenger": {
"650000": 140
},
"cargo": null,
"none": 110
},
"EP09": {
"passenger": {
"650000": 160
},
"cargo": null,
"none": 160
},
"ET22": {
"passenger": {
"650000": 125
},
"cargo": {
"1200000": 100,
"3100000": 70
},
"none": 125
},
"201E": {
"passenger": {
"650000": 125
},
"cargo": {
"1200000": 100,
"3100000": 70
},
"none": 125
},
"ET41": {
"passenger": {
"700000": 125
},
"cargo": {
"4000000": 70
},
"none": 110
},
"SM42": {
"passenger": {
"95000": 90,
"200000": 80,
"300000": 70,
"450000": 60,
"750000": 50,
"1130000": 40,
"1720000": 30,
"2400000": 20
},
"cargo": {
"95000": 90,
"200000": 80,
"300000": 70,
"450000": 60,
"750000": 50,
"1130000": 40,
"1720000": 30,
"2400000": 20
},
"none": 90
},
"M62": {
"passenger": {
"500000": 100,
"800000": 80,
"1200000": 60,
"2000000": 40,
"3000000": 20
},
"cargo": {
"500000": 100,
"800000": 80,
"1200000": 60,
"2000000": 40,
"3000000": 20
},
"none": 100
},
"ST44": {
"passenger": {
"500000": 100,
"800000": 80,
"1200000": 60,
"2000000": 40,
"3000000": 20
},
"cargo": {
"500000": 100,
"800000": 80,
"1200000": 60,
"2000000": 40,
"3000000": 20
},
"none": 100
},
"CTLR4C": {
"passenger": {
"500000": 100,
"800000": 80,
"1200000": 60,
"2000000": 40,
"3000000": 20
},
"cargo": {
"500000": 100,
"800000": 80,
"1200000": 60,
"2000000": 40,
"3000000": 20
},
"none": 100
}
}
+1 -3
View File
@@ -25,13 +25,11 @@ import {
totalWeight,
} from './utils/vehicleUtils';
import i18n from './i18n-setup';
import http from './http';
import realCompositionsJSON from './data/realCompositions.json';
export const useStore = defineStore({
id: 'store',
export const useStore = defineStore('store', {
state: () => ({
chosenCar: null as ICarWagon | null,
chosenLoco: null as ILocomotive | null,
+14 -1
View File
@@ -28,12 +28,14 @@ export interface ILocomotive {
constructionType: string;
cabinType: string;
maxSpeed: number;
maxSpeedLoco: number;
weight: number;
length: number;
coldStart: boolean;
doubleManned: boolean;
sponsorOnlyTimestamp: number;
teamOnly: boolean;
massSpeeds: VehicleGroupMassSpeeds | null;
}
export interface ICarWagon {
@@ -42,11 +44,13 @@ export interface ICarWagon {
constructionType: string;
loadable: boolean;
maxSpeed: number;
maxSpeedLoaded: number;
weight: number;
length: number;
cargoTypes: ICargo[];
sponsorOnlyTimestamp: number;
teamOnly: boolean;
massSpeeds: VehicleGroupMassSpeeds | null;
}
export interface IStock {
@@ -83,10 +87,13 @@ export interface IVehicleGroup {
id: number;
name: string;
speed: number;
speedLoaded?: number;
speedLoco?: number;
length: number;
weight: number;
cargoTypes: IVehicleCargoType[] | null;
locoProps: IVehicleLocoProps | null;
massSpeeds: VehicleGroupMassSpeeds | null;
}
export interface IVehicleCargoType {
@@ -99,9 +106,15 @@ export interface IVehicleLocoProps {
doubleManned: boolean;
}
export interface VehicleGroupMassSpeeds {
passenger: Record<string, number> | null;
cargo: Record<string, number> | null;
none: number | null;
}
export interface StorageStockEntry {
id: string;
createdAt: number;
updatedAt?: number;
stockString: string;
}
}
+35 -17
View File
@@ -1,29 +1,47 @@
import speedLimits from '../constants/speedLimits.json';
import massLimits from '../constants/massLimits.json';
import { IStock } from '../types/common.types';
export type SpeedLimitLocoType = keyof typeof speedLimits;
export type MassLimitLocoType = keyof typeof massLimits;
export function calculateSpeedLimit(
locoType: SpeedLimitLocoType,
stockTotalWeight: number,
stockCount: number,
isTrainPassenger: boolean
) {
if (speedLimits[locoType] === undefined) return 0;
export function calculateSpeedLimit(stockList: IStock[], isPassenger: boolean, stockMass: number) {
// Check the whole consist speed limit
const stockMaxSpeed = stockList.reduce((acc, vehicle, i) => {
let vehicleSpeed = vehicle.vehicleRef.maxSpeed;
if (stockCount == 1) return speedLimits[locoType]['none'];
if (
vehicle.vehicleRef.group == 'wagon-freight' &&
vehicle.cargo !== undefined &&
vehicle.vehicleRef.maxSpeedLoaded
) {
vehicleSpeed = vehicle.vehicleRef.maxSpeedLoaded;
}
const stockType = isTrainPassenger ? 'passenger' : 'cargo';
const speedTable = speedLimits[locoType][stockType];
return Math.min(vehicleSpeed, acc);
}, Infinity);
if (!speedTable) return undefined;
// Check the head vehicle speed limit
const headVehicle = stockList[0];
let speedLimit = 0;
for (const mass in speedTable)
if (stockTotalWeight > Number(mass)) speedLimit = (speedTable as any)[mass];
// Omit speed check for head vehicle if there's no data for it
if (!headVehicle || !headVehicle.vehicleRef.massSpeeds) return stockMaxSpeed;
return speedLimit;
const massSpeeds =
headVehicle.vehicleRef.massSpeeds[
stockList.length == 1 ? 'none' : isPassenger ? 'passenger' : 'cargo'
];
// Omit speed check if there's no data on mass speeds
if (!massSpeeds) return stockMaxSpeed;
// Number type for locomotives alone
if (typeof massSpeeds === 'number') return massSpeeds;
// Record type for passenger or cargo, find the closest range
const massKey = Object.keys(massSpeeds).findLast((massKey) => stockMass >= Number(massKey));
const massMaxSpeed = massKey ? massSpeeds[massKey] : Infinity;
return Math.min(massMaxSpeed, stockMaxSpeed);
}
export function calculateMassLimit(locoType: MassLimitLocoType, isTrainPassenger: boolean) {
+8 -21
View File
@@ -35,11 +35,14 @@ export function locoDataList(vehiclesData: IVehicleData[] | undefined) {
teamOnly: data.restrictions?.teamOnly ?? false,
maxSpeed: data.group.speed,
maxSpeedLoco: data.group.speedLoco ?? data.group.speed,
length: data.group.length,
weight: data.group.weight,
coldStart: data.group.locoProps?.coldStart ?? false,
doubleManned: data.group.locoProps?.doubleManned ?? false,
massSpeeds: data.group.massSpeeds,
});
return acc;
@@ -63,8 +66,12 @@ export function carDataList(vehiclesData: IVehicleData[] | undefined) {
teamOnly: data.restrictions?.teamOnly ?? false,
maxSpeed: data.group.speed,
maxSpeedLoaded: data.group.speedLoaded ?? data.group.speed,
length: data.group.length,
weight: data.group.weight,
massSpeeds: data.group.massSpeeds,
});
return acc;
@@ -83,27 +90,7 @@ export function totalLength(stockList: IStock[]) {
}
export function maxStockSpeed(stockList: IStock[]) {
const stockSpeedLimit = stockList.reduce(
(acc, stock) => (stock.vehicleRef.maxSpeed < acc || acc == 0 ? stock.vehicleRef.maxSpeed : acc),
0
);
const headingLoco =
stockList[0] && isTractionUnit(stockList[0].vehicleRef) ? stockList[0] : undefined;
if (!headingLoco) return stockSpeedLimit;
const locoType = headingLoco.vehicleRef.type.split('-')[0];
if (/^(EN|2EN|SN)/.test(locoType)) return stockSpeedLimit;
const speedLimitByMass = calculateSpeedLimit(
locoType as SpeedLimitLocoType,
totalWeight(stockList),
stockList.length,
isTrainPassenger(stockList)
);
return speedLimitByMass ? Math.min(stockSpeedLimit, speedLimitByMass) : stockSpeedLimit;
return calculateSpeedLimit(stockList, isTrainPassenger(stockList), totalWeight(stockList));
}
export function acceptableWeight(stockList: IStock[]) {