using System; using System.Collections.Generic; using System.Linq; namespace magicSquare { internal class SquareMatrix { public int Size { get; private set; } private int SizeSize { get; set; } public int MagicSum { get; private set; } private int[,] Values { get; set; } private int[] ColumnSums { get; set; } private int[] RowSums { get; set; } public int Diag1Sum { get; private set; } public int Diag2Sum { get; private set; } private int[] ColumnDeltas { get; set; } private int[] RowDeltas { get; set; } public int Diag1Delta { get; private set; } public int Diag2Delta { get; private set; } public SquareMatrix(int[,] values) { if (values.GetLength(0) != values.GetLength(1)) throw new ArgumentException("must be square matrix"); Values = values; Size = values.GetLength(0); SizeSize = Size * Size; MagicSum = (Size * (SizeSize + 1)) / 2; ColumnSums = (from col in Enumerable.Range(0, Size) let sum = (from row in Enumerable.Range(0, Size) select Values[row, col]).Sum() select sum).ToArray(); RowSums = (from row in Enumerable.Range(0, Size) let sum = (from col in Enumerable.Range(0, Size) select Values[row, col]).Sum() select sum).ToArray(); Diag1Sum = (from i in Enumerable.Range(0, Size) select Values[i, i]).Sum(); Diag2Sum = (from i in Enumerable.Range(0, Size) select Values[Size - 1 - i, i]).Sum(); ColumnDeltas = (from col in Enumerable.Range(0, Size) select ColumnSums[col] - MagicSum).ToArray(); RowDeltas = (from row in Enumerable.Range(0, Size) select RowSums[row] - MagicSum).ToArray(); Diag1Delta = Diag1Sum - MagicSum; Diag2Delta = Diag2Sum - MagicSum; } public IEnumerable> MaxColumnDeltaPairs() { return MaxDeltaPairs(ColumnDeltas, Size); } public IEnumerable> MaxRowDeltaPairs() { return MaxDeltaPairs(RowDeltas, Size); } public Tuple FindValueCoord(int values) { return ( from row in Enumerable.Range(0, Size) from col in Enumerable.Range(0, Size) where Values[row, col] == values let coord = new Tuple(row, col) select coord).First(); } public void SolveDiags() { var middleNumber = (SizeSize + 1)/2; var diag1Values = Enumerable.Range(middleNumber - (Size - 1)/2, Size); } private static IEnumerable> MaxDeltaPairs(int[] deltas, int size) { const int limit = 4; var deltaIs = (from i in Enumerable.Range(0, size) select new Tuple(i, deltas[i])).ToList(); var lows = deltaIs.OrderBy(tuple => tuple.Item2).Take(limit); var highs = deltaIs.OrderByDescending(tuple => tuple.Item2).Take(limit); var pairs = from lo in lows from hi in highs where lo.Item1 != hi.Item1 let pair = new Tuple, Tuple>(lo, hi) select pair; return pairs .OrderBy(pair => Math.Abs(pair.Item1.Item2 + pair.Item2.Item2)) .Select(pair => new Tuple(pair.Item1.Item1, pair.Item2.Item1)); } public static bool IsDiagonal(int i, int j, int size) { return i == j || size - 1 - j == i; } public bool IsDiagonal(int i, int j) { return i == j || Size - 1 - j == i; } public bool IsDiagonal(Tuple tpl) { return IsDiagonal(tpl.Item1, tpl.Item2); } public bool IsFeasible() { return Diag1Sum == MagicSum && Diag2Sum == MagicSum && ColumnSums.All(s => s == MagicSum) && RowSums.All(s => s == MagicSum); } public int GetValue(int row, int col) { return Values[row,col]; } public int ColumnSum(int col) { return ColumnSums[col]; } public int RowSum(int row) { return RowSums[row]; } public int ColumnDelta(int col) { return ColumnDeltas[col]; } public int RowDelta(int row) { return RowDeltas[row]; } private void UpdateValue(int row, int col, int value) { // update sums var delta = value - Values[row, col]; Values[row, col] = value; if (row == col) { Diag1Sum += delta; Diag1Delta += delta; } if (col == Size - 1 - row) { Diag2Sum += delta; Diag2Delta += delta;; } ColumnSums[col] += delta; ColumnDeltas[col] += delta; RowSums[row] += delta; RowDeltas[row] += delta; } private int AbsDelta(int row, int col) { return Math.Abs(RowDeltas[row]) + Math.Abs(ColumnDeltas[col]); } public int AbsDeltaDiff(int row1, int col1, int row2, int col2) { var v1 = Values[row1, col1]; var v2 = Values[row2, col2]; return Math.Abs(v1 - v2); } public int AbsDeltaDiff(Tuple coord1, Tuple coord2) { return AbsDeltaDiff(coord1.Item1, coord1.Item2, coord2.Item1, coord2.Item2); } public void Swap(Tuple coord1, Tuple coord2) { Swap(coord1.Item1, coord1.Item2, coord2.Item1, coord2.Item2); } public void Swap(int row1, int col1, int row2, int col2) { var v1 = Values[row1, col1]; var v2 = Values[row2, col2]; UpdateValue(row1,col1,v2); UpdateValue(row2,col2,v1); } } }