205 lines
5.1 KiB
C#
205 lines
5.1 KiB
C#
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<Tuple<int, int>> MaxColumnDeltaPairs()
|
|
{
|
|
return MaxDeltaPairs(ColumnDeltas, Size);
|
|
}
|
|
|
|
public IEnumerable<Tuple<int, int>> MaxRowDeltaPairs()
|
|
{
|
|
return MaxDeltaPairs(RowDeltas, Size);
|
|
}
|
|
|
|
public Tuple<int, int> 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<int, int>(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<Tuple<int, int>> MaxDeltaPairs(int[] deltas, int size)
|
|
{
|
|
const int limit = 4;
|
|
var deltaIs = (from i in Enumerable.Range(0, size)
|
|
select new Tuple<int, int>(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<int, int>, Tuple<int, int>>(lo, hi)
|
|
select pair;
|
|
return
|
|
pairs
|
|
.OrderBy(pair => Math.Abs(pair.Item1.Item2 + pair.Item2.Item2))
|
|
.Select(pair => new Tuple<int,int>(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<int,int> 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<int, int> coord1, Tuple<int, int> coord2)
|
|
{
|
|
return AbsDeltaDiff(coord1.Item1, coord1.Item2, coord2.Item1, coord2.Item2);
|
|
}
|
|
|
|
public void Swap(Tuple<int, int> coord1, Tuple<int, int> 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);
|
|
}
|
|
}
|
|
} |