#include <iostream>
#include <memory>
#include <tuple>
#include <map>

struct Position { int x, y; };
bool operator<(Position const &a, Position const &b)
{
	return std::tie(a.x, a.y) < std::tie(b.x, b.y);
}
std::ostream &operator<<(std::ostream &os, Position const &p)
{
	return os << '(' << p.x << ", " << p.y << ')';
}

struct Board
{
	class Piece
	{
		Position p;
		friend struct ::Board;
	public:
		Position const &pos = p;
		Piece(Position const &p)
		: p(p)
		{
		}
	};

	void swap(Position const &source, Position const &target)
	{
		std::cout << "Swapping " << source << " to " << target << std::endl;
		pieces[target].swap(pieces[source]);
		pieces[target]->p = target;
		pieces[source]->p = source;
		std::cout << "Swapped  " << source << " to " << target << std::endl;
	}
	
	void add(Position const &p)
	{
		pieces[p] = std::unique_ptr<Piece>(new Piece(p));
	}
	Piece *at(Position const &p)
	{
		return pieces[p].get();
	}

private:
	std::map<Position, std::unique_ptr<Piece>> pieces;
};

int main()
{
	Board b;
	b.add({1, 1});
	b.add({1, 2});
	b.add({2, 1});
	b.add({2, 2});
	
	std::cout << "First swap:" << std::endl;
	b.swap({1, 1}, {1, 2});
	std::cout << std::endl
	          << "Second swap:" << std::endl;
	b.swap(b.at({2, 1})->pos, {2, 2});
}
