project-kyoku/include/precisionevaluator.h

67 lines
1.8 KiB
C++

#ifndef PRECISIONEVALUATOR_H
#define PRECISIONEVALUATOR_H
#include <numeric>
#include <type_traits>
#include <vector>
#include <cmath>
#include <SFML/System/Clock.hpp>
using microsec = sf::Int64;
template<typename GRADE, typename = std::enable_if_t<std::is_enum<GRADE>::value>>
class PrecisionEvaluator
{
public:
PrecisionEvaluator(std::vector<microsec>&& intervals, microsec offset) :
_offset(offset),
_intervals(std::move(intervals))
{
microsec&& handling_offset = std::accumulate(intervals.begin(), intervals.end(), 0);
_start_handling_offset = _offset - handling_offset;
_end_handling_offset = _offset + handling_offset;
}
inline microsec offset() const noexcept
{
return _offset;
}
inline bool isActive(microsec music_play_offset) const noexcept
{
return music_play_offset > _start_handling_offset
&& music_play_offset < _end_handling_offset;
}
inline GRADE calculatePrecision(microsec odds) const
{
microsec shift_from_perfect = std::abs(odds - offset());
std::size_t raw_grade;
for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade)
{
if (shift_from_perfect <= _intervals[raw_grade])
break;
}
return static_cast<GRADE>(raw_grade);
}
private:
microsec _offset;
microsec _start_handling_offset;
microsec _end_handling_offset;
/* Amount of values in enum instanced as GRADES
* represents capacity of _intervals.
* So, for each V value in GRADES enum, _intervals[V]
* should return time shift from V - 1.
* V0 is PERFECT SCORE and the last V represents the worst
* grades which is death of note by expiration */
std::vector<microsec> _intervals;
};
#endif // PRECISIONEVALUATOR_H