Files
itgmania212121/src/StepParityDatastructs.h
T
Michael Votawandteejusb 4e7432a5a0 Several "structural" changes, and some memory optimizations:
- Replaced use of bare '-1' values with StepParity::INVALID_COLUMN
- Removed StepParityGraph object, moved its responsibilities to StepParityGenerator
- Removed some unnecessary data from State object, added 'combinedColumns' and 'whatNoteTheFootIsHitting'
- Created stateCache to allow reuse of state objects
- Fixed a very small bug with TechCounts (missing 'previousPreviousHeel != INVALID_COLUMN')
2025-02-11 19:39:03 -08:00

290 lines
8.6 KiB
C++

#ifndef STEP_PARITY_DATASTRUCTS_H
#define STEP_PARITY_DATASTRUCTS_H
#include "GameConstantsAndTypes.h"
#include "NoteData.h"
#include <queue>
#include <unordered_map>
namespace StepParity {
const int INVALID_COLUMN = -1;
const float CLM_SECOND_INVALID = -1;
enum Foot
{
NONE = 0,
LEFT_HEEL,
LEFT_TOE,
RIGHT_HEEL,
RIGHT_TOE,
NUM_Foot
};
const std::vector<StepParity::Foot> FEET = {LEFT_HEEL, LEFT_TOE, RIGHT_HEEL, RIGHT_TOE};
// A map for getting the other part of the foot, when you don't actually care
// what part it is.
// OTHER_PART_OF_FOOT[LEFT_HEEL] == LEFT_TOE
const std::vector<StepParity::Foot> OTHER_PART_OF_FOOT = {NONE, LEFT_TOE, LEFT_HEEL, RIGHT_TOE, RIGHT_HEEL};
const RString FEET_LABELS[] = {"N", "L", "l", "R", "r", "5??", "6??"};
const RString TapNoteTypeShortNames[] = { "Empty", "Tap", "Mine", "Attack", "AutoKeySound", "Fake", "", "" };
const RString TapNoteSubTypeShortNames[] = { "Hold", "Roll", "", "" };
enum Cost
{
COST_DOUBLESTEP = 0,
COST_BRACKETJACK,
COST_JACK,
COST_JUMP,
COST_SLOW_BRACKET,
COST_TWISTED_FOOT,
COST_BRACKETTAP,
COST_HOLDSWITCH,
COST_MINE,
COST_FOOTSWITCH,
COST_MISSED_FOOTSWITCH,
COST_FACING,
COST_DISTANCE,
COST_SPIN,
COST_SIDESWITCH,
COST_CROWDED_BRACKET ,
COST_OTHER,
COST_TOTAL,
NUM_Cost
};
const RString COST_LABELS[] = {
"DOUBLESTEP",
"BRACKETJACK",
"JACK",
"JUMP",
"SLOW_BRACKET",
"TWISTED_FOOT",
"BRACKETTAP",
"HOLDSWITCH",
"MINE",
"FOOTSWITCH",
"MISSED_FOOTSWITCH",
"FACING",
"DISTANCE",
"SPIN",
"SIDESWITCH",
"CROWDED_BRACKET",
"OTHER",
"TOTAL"
};
struct StagePoint {
float x;
float y;
};
// StageLayout represents the relative position of each panel on the dance stage,
// and provides some basic math function
struct StageLayout {
StepsType type;
int columnCount;
std::vector<StagePoint> columns;
std::vector<int> upArrows;
std::vector<int> downArrows;
std::vector<int> sideArrows;
StageLayout(StepsType t,
const std::vector<StagePoint>& c,
const std::vector<int> & u,
const std::vector<int> & d,
const std::vector<int> & s) : type(t), columns(c), upArrows(u), downArrows(d), sideArrows(s) {
this->columnCount = static_cast<int>(this->columns.size());
}
bool bracketCheck(int column1, int column2);
bool isSideArrow(int column);
bool isUpArrow(int column);
bool isDownArrow(int column);
float getDistanceSq(int c1, int c2);
float getDistanceSq(StagePoint p1, StagePoint p2);
float getXDifference(int leftIndex, int rightIndex);
float getYDifference(int leftIndex, int rightIndex);
StagePoint averagePoint(int leftIndex, int rightIndex);
float getPlayerAngle(int c1, int c2);
float getPlayerAngle(StepParity::StagePoint left, StepParity::StagePoint right);
};
/// @brief A vector of Foot values, which represents the player's
/// foot placement on the dance stage.
typedef std::vector<Foot> FootPlacement;
/// @brief Represents a specific possible state of the player's position
/// for a given row of the step chart.
struct State {
FootPlacement columns; // what the feet are hitting on this row
FootPlacement combinedColumns; // The resulting position of the player
FootPlacement movedFeet; // Any feet that have moved from the previous state to this one
FootPlacement holdFeet; // Any feet that stayed in place due to a hold/roll note.
int whereTheFeetAre[NUM_Foot]; // the inverse of combinedColumns
int whatNoteTheFootIsHitting[NUM_Foot]; // the inverse of columns
bool didTheFootMove[NUM_Foot]; // the inverse of movedFeet
bool isTheFootHolding[NUM_Foot]; //inverse of holdFeet
State(int columnCount)
{
columns = FootPlacement(columnCount, NONE);
combinedColumns = FootPlacement(columnCount, NONE);
movedFeet = FootPlacement(columnCount, NONE);
holdFeet = FootPlacement(columnCount, NONE);
for(int i = 0; i < NUM_Foot; i++)
{
whatNoteTheFootIsHitting[i] = INVALID_COLUMN;
whereTheFeetAre[i] = INVALID_COLUMN;
didTheFootMove[i] = false;
isTheFootHolding[i] = false;
}
}
bool operator==(const State& other) const;
};
/// @brief A convenience struct used to encapsulate data from NoteData in an
/// easier to work with format.
struct IntermediateNoteData {
TapNoteType type = TapNoteType_Empty; // type of the note
TapNoteSubType subtype = TapNoteSubType_Invalid;
int col = 0; // column/track number
int row = 0; // row on which the note occurs
float beat = 0; // beat on which the note occurs
float hold_length = 0; // If type is TapNoteType_HoldTail, length of hold, in beats
bool warped = false; // Is this note warped?
bool fake = false; // Is this note fake (besides being TapNoteType_Fake)?
float second = false; // time into the song on which the note occurs
Foot parity = NONE; // Which foot (and which part of the foot) will most likely be used
};
/// @brief A slightly complicated structure to encapsulate all of the data for a given
/// row of a step chart.
/// 'notes' and 'holds' will always have 'columnCount' entries. "Empty" columns will have a type of TapNoteType_Empty.
/// This shouldn't be confused with the idea of "rows" elsewhere in SM. Here, we only use
/// these Rows to represent a row that isn't empty.
struct Row {
// notes for the given row
std::vector<IntermediateNoteData> notes;
// Any active hold notes, including ones that started before this row
std::vector<IntermediateNoteData> holds;
// Column index of any holds that end on this row
std::set<int> holdTails;
// If a mine occurred either on this row, or on a row on its own immediately
// preceding this one, the time of when that mine occurred, indexed by column.
std::vector<float> mines;
// The same thing, but for fake mines
std::vector<float> fakeMines;
FootPlacement columns;
std::vector<int> whereTheFeetAre;
float second = 0;
float beat = 0;
int rowIndex = 0;
int columnCount = 0;
int noteCount = 0;
Row()
{
Row(0);
}
Row(int _columnCount)
{
columnCount = _columnCount;
notes = std::vector<IntermediateNoteData>(columnCount);
holds = std::vector<IntermediateNoteData>(columnCount);
holdTails.clear();
mines = std::vector<float>(columnCount, 0);
fakeMines = std::vector<float>(columnCount, 0);
columns = std::vector<StepParity::Foot>(columnCount, StepParity::NONE);
whereTheFeetAre = std::vector<int>(StepParity::NUM_Foot, INVALID_COLUMN);
}
void setFootPlacement(const std::vector<Foot> & footPlacement);
bool operator==(const Row& other) const;
bool operator!=(const Row& other) const;
};
/// @brief A counter used while creating rows
struct RowCounter
{
// Notes for the "current" row being generated
std::vector<IntermediateNoteData> notes;
// Any holds that are active for the current row
std::vector<IntermediateNoteData> activeHolds;
float lastColumnSecond = CLM_SECOND_INVALID;
float lastColumnBeat = CLM_SECOND_INVALID;
// The time at which a mine occurred for the current row,
// indexed by column
std::vector<float> mines;
// The time at which a fake mine occurred for the current row,
// indexed by column
std::vector<float> fakeMines;
// The time at which a mine occurred in the _previous_ row,
// indexed by column
std::vector<float> nextMines;
// The time at which a fake mine occurred in the _previous_ row,
// indexed by column
std::vector<float> nextFakeMines;
// number of "notes" added to the counter for the current row.
int noteCount = 0;
RowCounter(int columnCount)
{
notes = std::vector<IntermediateNoteData>(columnCount);
activeHolds = std::vector<IntermediateNoteData>(columnCount);
mines = std::vector<float>(columnCount, 0);
fakeMines = std::vector<float>(columnCount, 0);
nextMines = std::vector<float>(columnCount, 0);
nextFakeMines = std::vector<float>(columnCount, 0);
lastColumnSecond = CLM_SECOND_INVALID;
lastColumnBeat = CLM_SECOND_INVALID;
}
};
/// @brief A node within a StepParityGraph.
/// Represents a given state, and its connections to the states in the
/// following row of the step chart.
struct StepParityNode
{
// The index of this node in its graph
int id = 0;
State * state;
int rowIndex = 0;
float second = 0;
// Connections to, and the cost of moving to, the connected nodes
std::unordered_map<StepParityNode *, float> neighbors;
~StepParityNode()
{
neighbors.clear();
}
StepParityNode(State *_state, float _second, int _rowIndex)
{
state = _state;
rowIndex = _rowIndex;
second = _second;
}
int neighborCount()
{
return static_cast<int>(neighbors.size());
}
};
};
#endif