Files
2025-08-03 20:24:38 -07:00

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);
}
}
}