step-sequence-generator
Version:
A step sequence generator for figure skating programs
115 lines (114 loc) • 5.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StepTracker = void 0;
const utils_1 = require("./utils");
const custom_errors_1 = require("../../errors/custom-errors");
const random_generator_1 = require("../../utils/random-generator");
const rb_vector_key_percentage_1 = require("../../shared/constants/rb-percentage/rb-vector-key-percentage");
const extractors_1 = require("../roulette/weight-calculator/extractors");
const weight_key_creators_1 = require("../roulette/number-generator/weight-key-creators");
class StepTracker {
constructor(data) {
const { standardStartCoordinates, vectorsTrack, vectorAngles, vectorKeyChanceRatioMapGenerator, roulette, } = data;
this.startCoordinates = standardStartCoordinates;
this.vectorsTrack = vectorsTrack;
this.vectorAngles = vectorAngles;
this.vectorKeyChanceRatioMapGenerator = vectorKeyChanceRatioMapGenerator;
this.roulette = roulette;
}
/**
* @arg data
* @arg {VectorKey | null} data.currentVectorKey ключ вектора движения относительно поля
* @arg {ArcVectorIndexType} data.currentAcrVectorIndex индекс дуги: по часовой или против часовой стрелки
* @arg {DescartesCoordinatesType} data.currentCoordinates текущий координаты
* @arg {number} data.distance расстояние, которое покрывает движение
* */
getNextPosition(data) {
const { currentVectorKey, currentAcrVectorIndex, currentCoordinates, distance } = data;
const triedVectorKeys = new Set();
let availableVectorKeys = this.getAllowedVectorKeys(currentVectorKey);
while (availableVectorKeys.length > 0) {
const vectorKeyChanceRatioMap = this.vectorKeyChanceRatioMapGenerator.getChanceRatioMap({
currentVectorKey,
vectorKeys: availableVectorKeys,
currentAcrVectorIndex,
rbPercentage: rb_vector_key_percentage_1.RB_VECTOR_KEY_PERCENTAGE,
});
const vectorKey = this.getNextMovementVector(availableVectorKeys, vectorKeyChanceRatioMap);
triedVectorKeys.add(vectorKey);
const vectorCursor = this.getNextTrackVector(vectorKey);
const newCoordinates = this.getNewCoordinates({
vectorCursor,
currentCoordinates,
distance,
});
if (newCoordinates)
return {
vector: vectorKey,
coordinates: newCoordinates,
};
availableVectorKeys = this.filterVectorKeys(triedVectorKeys, availableVectorKeys);
}
console.debug('getNextPosition: Новые координаты не найдены');
throw new custom_errors_1.SequenceTrackerError('Unable to find next coordinates within bounds.', 'NO_VALID_COORDINATES');
}
filterVectorKeys(triedVectorKeys, vectorKeys) {
return vectorKeys.filter((vectorKey) => !triedVectorKeys.has(vectorKey));
}
getNewCoordinates(data) {
const { vectorCursor, currentCoordinates, distance } = data;
const newX = this.calcCoordinate({
cursor: vectorCursor.x,
coord: currentCoordinates.x,
distance,
});
const newY = this.calcCoordinate({
cursor: vectorCursor.y,
coord: currentCoordinates.y,
distance,
});
try {
return (0, utils_1.createCoordinates)(newX, newY);
}
catch (error) {
if (error instanceof custom_errors_1.CoordinatesError && error.code === 'OUTSIDE_BOUNDS')
return null;
console.debug('getNewCoordinates; Неизвестная ошибка');
throw error;
}
}
calcCoordinate(data) {
const { cursor, coord, distance } = data;
return distance * cursor + coord;
}
getNextTrackVector(vectorKey) {
return this.vectorsTrack[vectorKey];
}
getNextMovementVector(vectors, chanceRatioMap) {
if (vectors.length === 0)
throw new custom_errors_1.SequenceTrackerError('vectors.length should be more than 0', 'NO_VECTOR_FOR_CHOICE');
const index = this.roulette.spinWheel({
selection: vectors,
chanceRatioMap,
itemKeyExtractor: extractors_1.vectorKeyKeyExtractor,
weightKeyCreator: weight_key_creators_1.vectorWeightKeyCreator,
});
return vectors[index];
}
getAllowedVectorKeys(currentVector, maxTurnAngle = 90) {
return currentVector === null
? Object.keys(this.vectorAngles)
: Object.keys(this.vectorAngles).filter((key) => {
const absoluteAngelDiff = Math.abs(this.vectorAngles[currentVector] - this.vectorAngles[key]);
const normalizeAngleDiff = Math.min(absoluteAngelDiff, 360 - absoluteAngelDiff);
return normalizeAngleDiff <= maxTurnAngle;
});
}
getStartCoordinates() {
return this.startCoordinates[this.getRandom(0, this.startCoordinates.length - 1)];
}
getRandom(min, max) {
return (0, random_generator_1.randomGenerator)(min, max);
}
}
exports.StepTracker = StepTracker;