using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QueenPlacer {
	internal class Calculations {

		public static List<Solution> GetSolutions(int i = 0, Solution? parent = null, int size = 8) {
			var returned = new List<Solution>();

			if (parent is null)
				parent = new Solution();

			if (parent.Queens.Count == size) {
				returned.Add(parent);
			} else {
				for (var x = 0; x < size; x++) {
					var newQueen = new SimpleVector(x, i);

					if (CheckQueenPositionLegibility(newQueen, parent.Queens)) {
						returned.AddRange(GetSolutions(i + 1, new Solution(parent, newQueen), size));
					}
				}
			}

			return GetUniqueSolutions(returned);
		}

		public static List<Solution> GetUniqueSolutions(List<Solution> solutions) {
			var queenCount = 0;

			var uniques = new List<Solution>() { };

			foreach (var sol in solutions) {
				var add = true;

				if (queenCount == 0)
					queenCount = sol.Queens.Count;
				else foreach (var unique in uniques)
						if (CheckComparableQueens(unique, sol) == queenCount)
							add = false;

				if (add)
					uniques.Add(sol);
			}

			return uniques;
		}

		public static bool CheckQueenPositionLegibility(SimpleVector queen, List<SimpleVector> queens) {
			foreach (var q in queens) {
				if (!CompareQueenPositions(queen, q))
					return false;
			}

			return true;
		}

		public static bool CompareQueenPositions(SimpleVector queen0, SimpleVector queen1) {
			if (queen0.X == queen1.X)
				return false;
			if (queen0.Y == queen1.Y)
				return false;

			var modified = queen1 - queen0;
			if (modified.X == modified.Y || modified.X == -modified.Y)
				return false;

			return true;
		}

		public static int CheckComparableQueens(Solution sol0, Solution sol1) {
			var returned = 0;

			foreach (var q0 in sol0.Queens)
				foreach (var q1 in sol1.Queens)
					if (q0.X == q1.X && q0.Y == q1.Y) returned++;

			return returned;
		}
	}

	internal struct SimpleVector {
		public int X; public int Y;
		public SimpleVector(int x, int y) {
			X = x;
			Y = y;
		}

		public override string ToString() {
			return $"{X},{Y}";
		}

		public static SimpleVector operator +(SimpleVector i, SimpleVector j) => new SimpleVector(i.X + j.X, i.Y + j.Y);
		public static SimpleVector operator -(SimpleVector i, SimpleVector j) => new SimpleVector(i.X - j.X, i.Y - j.Y);
	}

	internal class Solution {
		public List<SimpleVector> Queens { get; set; } = new();

		public Solution() {

		}

		public Solution(int x, int y) {
			Queens.Add(new SimpleVector(x, y));
		}

		public Solution(Solution oldSolution, SimpleVector newQueen) {
			Queens = new List<SimpleVector>(oldSolution.Queens) {
				newQueen
			};
		}

		public override string ToString() {
			var returned = "";

			foreach (var q in Queens)
				returned += $"{q} ";

			return returned.Trim();
		}
	}
}
