#pragma once

#include <iostream>
#include <cstdint>

/**
 * A position on a 2D grid
 */
struct Position {
    std::int8_t x; // x position
    std::int8_t y; // y position
};


/**
 * Addition operator
 * @return The sums of the coordinates of both positions
 */
inline Position operator+(const Position& left, const Position& right) {
    return Position(left.x + right.x, left.y + right.y);
}

/**
 * Additive assignation operator, adds the coordinates of the right position to the left one
 * @return A reference to the left position
 */
inline Position& operator+=(Position& left, const Position& right) {
    left = left + right;
    return left;
}

/**
 * Substraction operator
 * @return The difference of the coordinate between the left and right position
 */
inline Position operator-(const Position& left, const Position& right) {
    return Position(left.x - right.x, left.y - right.y);
}

/**
 * Substractive assignation operator, substracts the coordinates of the right position from the left one
 * @return A reference to the left position
 */
inline Position& operator-=(Position& left, const Position& right) {
    left = left + right;
    return left;
}

/**
 * Strict inferiority operator, a position is inferior to another if it is lower or at the same height and more to the left
 * @return If the left position is inferior to the right position
 */
inline bool operator<(const Position& left, const Position& right) {
    return (left.x == right.x) ? (left.y < right.y) : (left.x < right.x);
}

/**
 * Equality operator, two positions are equal if they have the same coordinates
 * @return If the two positions are equals
 */
inline bool operator==(const Position& left, const Position& right) {
    return (left.x == right.x) && (left.y == right.y);
}

/**
 * Inequality operator, two positions aren't equal if their coordinates aren't
 * @return If the two positions aren't equals
 */
inline bool operator!=(const Position& left, const Position& right) {
    return (left.x != right.x) || (left.y != right.y);
}

/**
 * Stream output operator, adds the coordinates of the position to the stream
 * @return A reference to the output stream
 */
inline std::ostream& operator<<(std::ostream& os, const Position& position) {
    os << "x: " << position.x << " y: " << position.y;
    return os;
}
