2023-04-12 03:59:13 +02:00
|
|
|
import {BiasParams, CarSetupParams} from "../consts/params";
|
|
|
|
|
2023-05-25 18:13:51 +02:00
|
|
|
export const MAX_SETUP_CANDIDATES = 99;
|
2023-04-12 03:59:13 +02:00
|
|
|
export const eps = 1e-6;
|
|
|
|
export const optimalBreakpoint = 0.007; // technically 39/5600 = 0.0069642857142857146 but fine
|
|
|
|
export const greatBreakpoint = 0.04 + eps;
|
|
|
|
export const goodBreakpoint = 0.1 + eps;
|
|
|
|
|
|
|
|
export const errorConst = 1e20;
|
|
|
|
|
|
|
|
export const arrayFloatEqual = (a, b) => {
|
|
|
|
if (a === b) return true;
|
|
|
|
if (a == null || b == null) return false;
|
|
|
|
if (a.length !== b.length) return false;
|
|
|
|
|
|
|
|
for (let i = 0; i < a.length; ++i) {
|
|
|
|
if (Math.abs(a[i] - b[i]) > eps) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const setupToBias = (carSetup) => {
|
2023-04-21 07:28:48 +02:00
|
|
|
try {
|
2023-06-02 06:21:19 +02:00
|
|
|
return BiasParams.map(biasRow => {
|
|
|
|
const r = carSetup.map(
|
|
|
|
(x, idx) => x * biasRow.effect[idx]
|
|
|
|
).reduce((a,b) => a+b) + biasRow.offset;
|
|
|
|
return Math.round(r * 56000) / 56000;
|
|
|
|
}
|
2023-04-21 07:28:48 +02:00
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
return [0.5, 0.5, 0.5, 0.5, 0.5];
|
|
|
|
}
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const biasToSetup = (biasParam) => {
|
2023-04-21 07:28:48 +02:00
|
|
|
try {
|
|
|
|
return CarSetupParams.map(carRow =>
|
|
|
|
biasParam.map(
|
|
|
|
(x, idx) => (x - BiasParams[idx].offset) * carRow.effect[idx]
|
|
|
|
).reduce((a,b) => a+b)
|
|
|
|
)
|
|
|
|
} catch {
|
|
|
|
return [0.5, 0.5, 0.5, 0.5, 0.5];
|
|
|
|
}
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
export const validateFeedbackBreaks = (_result, feedbacks, maxBreaks, validates = [0, 1, 2, 3, 4]) => {
|
|
|
|
let ruleBreaks = 0;
|
|
|
|
for (const idx of validates) {
|
|
|
|
const x = _result[idx];
|
|
|
|
for(const fs of feedbacks[idx]) {
|
|
|
|
const dx = Math.abs(x - fs.value);
|
|
|
|
const f = fs.feedback;
|
|
|
|
// const scale = {bad: 1, good: 2, great: 3, optimal: 4}
|
|
|
|
if (f !== "unknown") {
|
|
|
|
if (
|
|
|
|
(f === 'bad' && (dx < goodBreakpoint))
|
|
|
|
||
|
|
|
|
(f === 'bad+' && (fs.value - x < goodBreakpoint))
|
|
|
|
||
|
|
|
|
(f === 'bad-' && (fs.value - x > - goodBreakpoint))
|
|
|
|
||
|
|
|
|
(f === 'good' && ((dx > goodBreakpoint) || (dx < greatBreakpoint)))
|
|
|
|
||
|
|
|
|
(f === 'great' && ((dx > greatBreakpoint) || (dx < optimalBreakpoint)))
|
|
|
|
||
|
|
|
|
(f === 'optimal' && (dx >= optimalBreakpoint))
|
|
|
|
) {
|
|
|
|
ruleBreaks += 1;
|
|
|
|
if (ruleBreaks > maxBreaks) {
|
|
|
|
return ruleBreaks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ruleBreaks;
|
|
|
|
}
|
|
|
|
|
2023-04-12 03:59:13 +02:00
|
|
|
export const nearestSetup = (biasParam, feedbacks) => {
|
|
|
|
let nearestResult = null;
|
|
|
|
let nearestDiff = errorConst;
|
|
|
|
let lowestRuleBreak = 15;
|
|
|
|
let possibleSetups = 0;
|
|
|
|
let possibleSetupList = [];
|
2023-05-25 11:12:20 +02:00
|
|
|
|
|
|
|
const steps = CarSetupParams.map(x => Math.round((x.max - x.min) / x.step));
|
|
|
|
|
|
|
|
|
|
|
|
let si = [0, 0, 0, 0, 0];
|
|
|
|
let v = [0, 0, 0, 0, 0];
|
|
|
|
|
|
|
|
let bias = BiasParams.map(x => x.offset);
|
|
|
|
|
|
|
|
for(si[0] = 0; si[0] <= steps[0]; si[0]++) {
|
|
|
|
v[0] = si[0] / steps[0];
|
|
|
|
for(let i= 0; i < 5; i++) bias[i] += BiasParams[i].effect[0] * v[0];
|
|
|
|
for(si[1] = 0; si[1] <= steps[1]; si[1]++) {
|
|
|
|
v[1] = si[1] / steps[1];
|
|
|
|
for(let i= 0; i < 5; i++) bias[i] += BiasParams[i].effect[1] * v[1];
|
2023-04-12 03:59:13 +02:00
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
// maybe we can do something here
|
|
|
|
// straights are already determined here. validate 4 only
|
|
|
|
|
|
|
|
const ruleBreaks = validateFeedbackBreaks(bias, feedbacks, lowestRuleBreak, [4]);
|
|
|
|
if (ruleBreaks <= lowestRuleBreak) { // added guards
|
|
|
|
|
|
|
|
for(si[2] = 0; si[2] <= steps[2]; si[2]++) {
|
|
|
|
v[2] = si[2] / steps[2];
|
|
|
|
for(let i= 0; i < 5; i++) bias[i] += BiasParams[i].effect[2] * v[2];
|
|
|
|
for(si[3] = 0; si[3] <= steps[3]; si[3]++) {
|
|
|
|
v[3] = si[3] / steps[3];
|
|
|
|
for(let i= 0; i < 5; i++) bias[i] += BiasParams[i].effect[3] * v[3];
|
|
|
|
|
|
|
|
// maybe we can do something here
|
|
|
|
// toe-out only affects breaking and cornering, so let's validate [0, 3, 4]
|
|
|
|
|
|
|
|
const ruleBreaks = validateFeedbackBreaks(bias, feedbacks, lowestRuleBreak, [0, 3]); // 4 doesn't need to revalidate
|
|
|
|
if (ruleBreaks <= lowestRuleBreak) { // added guards
|
|
|
|
|
|
|
|
for(si[4] = 0; si[4] <= steps[4]; si[4]++) {
|
|
|
|
v[4] = si[4] / steps[4];
|
|
|
|
for(let i= 0; i < 5; i++) {
|
|
|
|
bias[i] += BiasParams[i].effect[4] * v[4];
|
|
|
|
bias[i] = Math.round(bias[i] * 56000) / 56000;
|
2023-05-25 11:12:20 +02:00
|
|
|
}
|
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
{
|
2023-05-25 11:12:20 +02:00
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
const ruleBreaks = validateFeedbackBreaks(bias, feedbacks, lowestRuleBreak);
|
|
|
|
if (ruleBreaks <= lowestRuleBreak) {
|
|
|
|
if (ruleBreaks < lowestRuleBreak) {
|
|
|
|
lowestRuleBreak = ruleBreaks;
|
|
|
|
possibleSetups = 0;
|
|
|
|
nearestDiff = errorConst;
|
|
|
|
nearestResult = null;
|
|
|
|
possibleSetupList = [];
|
|
|
|
}
|
2023-05-25 11:12:20 +02:00
|
|
|
|
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
const arr = [...v];
|
|
|
|
let diff = bias.map((x, idx) => {
|
|
|
|
return (Math.min(Math.abs(x - biasParam[idx]), 0.2) * 100)
|
|
|
|
}).reduce((x, y) => x+y)
|
2023-05-25 11:12:20 +02:00
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
if (diff < errorConst) {
|
|
|
|
if (diff < nearestDiff) {
|
|
|
|
nearestDiff = diff;
|
|
|
|
nearestResult = arr;
|
|
|
|
}
|
|
|
|
possibleSetups++;
|
|
|
|
|
|
|
|
if (
|
|
|
|
possibleSetupList.length < MAX_SETUP_CANDIDATES ||
|
|
|
|
diff < possibleSetupList[MAX_SETUP_CANDIDATES - 1].diff) {
|
|
|
|
possibleSetupList.push({arr, diff});
|
|
|
|
possibleSetupList = possibleSetupList.sort(
|
|
|
|
(x, y) => x.diff - y.diff
|
|
|
|
).slice(0, MAX_SETUP_CANDIDATES)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-05-25 11:12:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-05-25 11:25:28 +02:00
|
|
|
|
|
|
|
for(let i= 0; i < 5; i++) bias[i] -= BiasParams[i].effect[4] * v[4];
|
2023-05-25 11:12:20 +02:00
|
|
|
}
|
2023-04-12 03:59:13 +02:00
|
|
|
|
2023-05-25 11:25:28 +02:00
|
|
|
}
|
|
|
|
for(let i= 0; i < 5; i++) bias[i] -= BiasParams[i].effect[3] * v[3];
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
2023-05-25 11:25:28 +02:00
|
|
|
for(let i= 0; i < 5; i++) bias[i] -= BiasParams[i].effect[2] * v[2];
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
2023-05-25 11:25:28 +02:00
|
|
|
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
2023-05-25 11:25:28 +02:00
|
|
|
|
2023-05-25 11:12:20 +02:00
|
|
|
for(let i= 0; i < 5; i++) bias[i] -= BiasParams[i].effect[1] * v[1];
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
2023-05-25 11:12:20 +02:00
|
|
|
for(let i= 0; i < 5; i++) bias[i] -= BiasParams[i].effect[0] * v[0];
|
2023-04-12 03:59:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
possibleSetupList = possibleSetupList.sort((x, y) => x.diff - y.diff).slice(0, MAX_SETUP_CANDIDATES)
|
|
|
|
return {setup: nearestResult, possibleSetups, lowestRuleBreak, possibleSetupList};
|
|
|
|
}
|
|
|
|
|
2023-04-28 16:20:04 +02:00
|
|
|
export const randomSetup = () => CarSetupParams.map(params => {
|
|
|
|
const s = (params.max - params.min) / params.step;
|
|
|
|
return Math.floor(Math.random() * (s + 1)) / s;
|
|
|
|
})
|
|
|
|
|
|
|
|
|