EDIT 1: Added an alternative method body
Hi.
Here is my solution.
You will find 3 overloaded methods to accept a 2D matrix of all chars (
char[,]), a list of lines (
string[]), a text (
string).
The
char[,] overload is the only doing the computation (the others two delegates to it).
static string RebuildClockwise(string text)
{
var result = RebuildClockwise(text.Split(new[] { Environment.NewLine }, StringSplitOptions.None));
return result;
}
static string RebuildClockwise(params string[] lines)
{
var nRowCount = lines.Length;
var nColCount = lines.Max(line => line.Length);
for (int ixLine = 0; ixLine < lines.Length; ixLine++)
{
var line = lines[ixLine];
if (line.Length < nColCount)
lines[ixLine] = line.PadRight(nColCount);
}
var chars = new char[nRowCount, nColCount];
for (int ixRow = 0; ixRow < nRowCount; ixRow++)
{
for (int ixCol = 0; ixCol < nColCount; ixCol++)
{
chars[ixRow, ixCol] = lines[ixRow][ixCol];
}
}
var result = RebuildClockwise(chars);
return result;
}
static string RebuildClockwise(char[,] chars)
{
var nTotalCount = chars.GetLength(0) * chars.GetLength(1);
var aLimits = new int[4];
aLimits[Dir_Right] = chars.GetLength(1) - 1;
aLimits[Dir_Down] = chars.GetLength(0) - 1;
aLimits[Dir_Left] = 0;
aLimits[Dir_Up] = 0;
var result = string.Empty;
var ixCol = 0;
var ixRow = 0;
var nDirection = Dir_Right;
for (var nProcessedCount = 0; nProcessedCount < nTotalCount; nProcessedCount++)
{
result += chars[ixRow, ixCol];
if (!RebuildClockwise_Move(aLimits, ref nDirection, ref ixCol, ref ixRow))
break;
}
return result;
}
The main function (
RebuildClockwise(char[,] chars)), first stores the matrix limits and initializes the direction and cell location to start with.
Then loops updating the result and calling another function (
RebuildClockwise_Move) that changes the cell location and direction.
private static bool RebuildClockwise_Move(int[] aLimits, ref int nDirection, ref int ixCol, ref int ixRow)
{
for (var nTrial = MinDir + 1; nTrial <= MaxDir + 1; nTrial++)
{
switch (nDirection)
{
case Dir_Right:
if (ixCol < aLimits[nDirection])
{
ixCol++;
return true;
}
aLimits[(nDirection + 3) % 4]++;
break;
case Dir_Down:
if (ixRow < aLimits[nDirection])
{
ixRow++;
return true;
}
aLimits[(nDirection + 3) % 4]--;
break;
case Dir_Left:
if (ixCol > aLimits[nDirection])
{
ixCol--;
return true;
}
aLimits[(nDirection + 3) % 4]--;
break;
case Dir_Up:
if (ixRow > aLimits[nDirection])
{
ixRow--;
return true;
}
aLimits[(nDirection + 3) % 4]++;
break;
}
nDirection++;
if (nDirection > MaxDir)
nDirection = MinDir;
}
return false;
}
RebuildClockwise_Move, based on the direction, change the row and/or column index and updates the limits.
When no row or column is available, it returns false to stop looping.
Both methods make use of some constants to manage the direction:
const int Dir_Right = 0;
const int Dir_Down = Dir_Right + 1;
const int Dir_Left = Dir_Down + 1;
const int Dir_Up = Dir_Left + 1;
const int MinDir = 0;
const int MaxDir = 3;
The following test code allow to check the computation is correct:
MessageBox.Show(RebuildClockwise("1234", "CDE5", "BGF6", "A987"));
MessageBox.Show(RebuildClockwise("12345", "EFGH6", "DKJI7", "CBA98"));
MessageBox.Show(RebuildClockwise("1234", "EFG5", "DKH6", "CJI7", "BA98"));
MessageBox.Show(RebuildClockwise("12345678"));
MessageBox.Show(RebuildClockwise("1234", "8765"));
MessageBox.Show(RebuildClockwise("12", "83", "74", "65"));
MessageBox.Show(RebuildClockwise("1", "2", "3", "4", "5", "6", "7", "8"));
They should display a text between
12345678 and
123456789ABCDEFGHIJK (the input values are arranged in order to obtain an understandable result).
Overall, this solution is more generalized (and complex) than your sample code but it can be simplified replacing the
aLimits array and the switch block with code using constants or plain variables.
Regards,
Daniele.
EDIT 1: The following functions is an alternative to the
char[,] overload.
This one will use two concurrent variables to move row and column instead of relying on the
nDirection variable; this version also incorporate the movement logic.
static string RebuildClockwise(char[,] chars)
{
var nMaxCol = chars.GetLength(1) - 1;
var nMaxRow = chars.GetLength(0) - 1;
var nTotalCount = (nMaxRow + 1) * (nMaxCol + 1);
var result = string.Empty;
var nMinCol = 0;
var nMinRow = 0;
var ixCol = 0;
var ixRow = 0;
var nDeltaCol = 1;
var nDeltaRow = 0;
for (var nProcessedCount = 0; nProcessedCount < nTotalCount; nProcessedCount++)
{
result += chars[ixRow, ixCol];
var bMoved = false;
for (var nTrial = 1; nTrial <= 4; nTrial++)
{
var ixColN = ixCol + nDeltaCol;
var ixRowN = ixRow + nDeltaRow;
if ((ixColN >= nMinCol) && (ixColN <= nMaxCol) && (ixRowN >= nMinRow) && (ixRowN <= nMaxRow))
{
ixCol = ixColN;
ixRow = ixRowN;
bMoved = true;
break;
}
if (ixColN < nMinCol)
nMaxRow--;
else if (ixColN > nMaxCol)
nMinRow++;
else if (ixRowN < nMinRow)
nMinCol++;
else if (ixRowN > nMaxRow)
nMaxCol--;
var nTemp = nDeltaCol;
nDeltaCol = -nDeltaRow;
nDeltaRow = nTemp;
}
if (!bMoved)
break;
}
return result;
}