2021-12-31 14:59:39 +01:00
|
|
|
#include "note.hpp"
|
|
|
|
|
2019-01-19 17:12:41 +01:00
|
|
|
#include <assert.h>
|
2019-03-28 02:16:29 +01:00
|
|
|
#include <optional>
|
2021-12-31 14:59:39 +01:00
|
|
|
#include <stdexcept>
|
2017-08-17 23:41:11 +02:00
|
|
|
|
2019-01-19 17:12:41 +01:00
|
|
|
Note::Note(int pos, int timing, int length, int tail_pos) {
|
2021-12-31 14:59:39 +01:00
|
|
|
if (timing < 0) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
"Tried creating a note with negative timing : " + std::to_string(timing));
|
|
|
|
}
|
|
|
|
if (!(pos >= 0 and pos <= 15)) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
"Tried creating a note with invalid position : " + std::to_string(pos));
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
"Tried creating a note with invalid length : " + std::to_string(length));
|
|
|
|
}
|
|
|
|
if (length > 0) {
|
|
|
|
if (tail_pos < 0 or tail_pos > 11 or !tail_pos_correct(pos, tail_pos)) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
"Tried creating a long note with invalid tail position : "
|
|
|
|
+ std::to_string(tail_pos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this->timing = timing;
|
|
|
|
this->pos = pos;
|
|
|
|
this->length = length;
|
|
|
|
this->tail_pos = tail_pos;
|
2017-08-18 17:42:56 +02:00
|
|
|
}
|
|
|
|
|
2019-03-28 02:16:29 +01:00
|
|
|
/*
|
|
|
|
* Constructor to create a long note out of a pair
|
|
|
|
*/
|
|
|
|
Note::Note(const Note& note_a, const Note& note_b) {
|
2021-12-31 14:59:39 +01:00
|
|
|
this->initAsClosestLongNote(note_a, note_b.timing, note_b.pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Note::initAsClosestLongNote(const Note& start, int end_timing, int wanted_tail_pos) {
|
|
|
|
pos = start.getPos();
|
|
|
|
timing = std::min(start.getTiming(), end_timing);
|
|
|
|
length = std::abs(start.getTiming() - end_timing);
|
|
|
|
|
|
|
|
std::optional<int> best_tail_pos = {};
|
|
|
|
for (int i = 0; i < 12; ++i) {
|
|
|
|
if (Note::tail_pos_correct(pos, i)) {
|
|
|
|
if (not best_tail_pos) {
|
|
|
|
best_tail_pos = i;
|
|
|
|
} else {
|
|
|
|
int potential_tail = Note::tail_pos_to_note_pos(pos, i);
|
|
|
|
int best_tail = Note::tail_pos_to_note_pos(pos, *best_tail_pos);
|
|
|
|
if (distance(potential_tail, wanted_tail_pos)
|
|
|
|
< distance(best_tail, wanted_tail_pos)) {
|
|
|
|
best_tail_pos = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(best_tail_pos.has_value());
|
|
|
|
tail_pos = *best_tail_pos;
|
2019-03-28 02:16:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-19 17:12:41 +01:00
|
|
|
bool Note::tail_pos_correct(int n, int p) {
|
2021-12-31 14:59:39 +01:00
|
|
|
assert(n >= 0 and n <= 15);
|
|
|
|
assert(p >= 0 and p <= 11);
|
2017-08-18 17:42:56 +02:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
int x = n % 4;
|
|
|
|
int y = n / 4;
|
2017-08-18 17:42:56 +02:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
int dx = 0;
|
|
|
|
int dy = 0;
|
2017-08-18 17:42:56 +02:00
|
|
|
|
2019-01-19 17:12:41 +01:00
|
|
|
// Vertical
|
2021-12-31 14:59:39 +01:00
|
|
|
if (p % 2 == 0) {
|
2019-01-19 17:12:41 +01:00
|
|
|
// Going up
|
2021-12-31 14:59:39 +01:00
|
|
|
if ((p / 2) % 2 == 0) {
|
|
|
|
dy = -(p / 4 + 1);
|
2019-01-19 17:12:41 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Going down
|
|
|
|
} else {
|
|
|
|
dy = p / 4 + 1;
|
|
|
|
}
|
2019-01-19 17:12:41 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Horizontal
|
|
|
|
} else {
|
|
|
|
// Going right
|
|
|
|
if ((p / 2) % 2 == 0) {
|
|
|
|
dx = p / 4 + 1;
|
2017-08-18 17:42:56 +02:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Going left
|
|
|
|
} else {
|
|
|
|
dx = -(p / 4 + 1);
|
|
|
|
}
|
|
|
|
}
|
2017-08-18 17:42:56 +02:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
return ((0 <= x + dx) and (x + dx <= 4)) and ((0 <= y + dy) and (y + dy <= 4));
|
2017-08-18 17:42:56 +02:00
|
|
|
}
|
|
|
|
|
2019-03-28 02:16:29 +01:00
|
|
|
int Note::tail_pos_to_note_pos(int pos, int tail_pos) {
|
2021-12-31 14:59:39 +01:00
|
|
|
int x = pos % 4;
|
|
|
|
int y = pos / 4;
|
2019-03-28 02:16:29 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
int dx = 0;
|
|
|
|
int dy = 0;
|
2019-03-28 02:16:29 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Vertical
|
|
|
|
if (tail_pos % 2 == 0) {
|
|
|
|
// Going up
|
|
|
|
if ((tail_pos / 2) % 2 == 0) {
|
|
|
|
dy = -(tail_pos / 4 + 1);
|
2019-03-28 02:16:29 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Going down
|
|
|
|
} else {
|
|
|
|
dy = tail_pos / 4 + 1;
|
|
|
|
}
|
2019-03-28 02:16:29 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Horizontal
|
|
|
|
} else {
|
|
|
|
// Going right
|
|
|
|
if ((tail_pos / 2) % 2 == 0) {
|
|
|
|
dx = tail_pos / 4 + 1;
|
2019-03-28 02:16:29 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
// Going left
|
|
|
|
} else {
|
|
|
|
dx = -(tail_pos / 4 + 1);
|
|
|
|
}
|
|
|
|
}
|
2019-03-28 02:16:29 +01:00
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
return x + dx + 4 * (y + dy);
|
2019-03-28 02:16:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int Note::distance(int pos_a, int pos_b) {
|
2021-12-31 14:59:39 +01:00
|
|
|
int x = (pos_a % 4) - (pos_b % 4);
|
|
|
|
int y = (pos_a / 4) - (pos_b / 4);
|
|
|
|
return x * x + y * y;
|
2019-03-28 02:16:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-18 17:42:56 +02:00
|
|
|
int Note::getPos() const {
|
2021-12-31 14:59:39 +01:00
|
|
|
return pos;
|
2017-08-18 17:42:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int Note::getLength() const {
|
2021-12-31 14:59:39 +01:00
|
|
|
return length;
|
2017-08-18 17:42:56 +02:00
|
|
|
}
|
|
|
|
|
2019-01-19 17:12:41 +01:00
|
|
|
int Note::getTail_pos() const {
|
2021-12-31 14:59:39 +01:00
|
|
|
return tail_pos;
|
2017-08-17 23:41:11 +02:00
|
|
|
}
|
2017-08-25 13:14:38 +02:00
|
|
|
|
|
|
|
int Note::getTiming() const {
|
2021-12-31 14:59:39 +01:00
|
|
|
return timing;
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
bool Note::operator==(const Note& rhs) const {
|
|
|
|
return timing == rhs.timing && pos == rhs.pos;
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
bool Note::operator!=(const Note& rhs) const {
|
|
|
|
return !(rhs == *this);
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
bool Note::operator<(const Note& rhs) const {
|
|
|
|
if (timing < rhs.timing)
|
|
|
|
return true;
|
|
|
|
if (rhs.timing < timing)
|
|
|
|
return false;
|
|
|
|
return pos < rhs.pos;
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
bool Note::operator>(const Note& rhs) const {
|
|
|
|
return rhs < *this;
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
bool Note::operator<=(const Note& rhs) const {
|
|
|
|
return !(rhs < *this);
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|
|
|
|
|
2021-12-31 14:59:39 +01:00
|
|
|
bool Note::operator>=(const Note& rhs) const {
|
|
|
|
return !(*this < rhs);
|
2017-08-25 13:14:38 +02:00
|
|
|
}
|