patterncsharpMinor
HackerRank NCR codesprint: Spiral Message
Viewed 0 times
messagecodesprintspiralhackerrankncr
Problem
Problem statement:
https://www.hackerrank.com/contests/ncr-codesprint/challenges/spiral-message
You've intercepted an encoded spy message! The message originated as a
single line of one or more space-separated words, but it was encoded
into an matrix as a clockwise spiral starting in the lower left-hand
corner. For example, the diagram below shows the decoding process for
an encoded message:
The message is decoded spirally starting from the lower left-hand
corner of the matrix and moving in the clockwise direction (i.e., up,
right, down, left, up, right, etc.). From the starting position, you
must clockwise-traverse the matrix, scanning characters and switching
to the next clockwise direction each time you reach a boundary (i.e.,
an already-scanned character or the end of the matrix). Continue
scanning characters in this manner until you've scanned all the
matrix's characters into a single decoded string. The word separator
for the decoded string is the hash mark (#).
Given n, m, and an encoded message, decode the message and print the
number of words in the decoded message.
Input Format
The first line contains two space-separated positive integers
describing the respective values of n and m. Each line i of the n
subsequent lines contains a string of m characters describing row i of
the encoded message.
Constraints
Each word consists of lowercase English alphabetic characters (a to
z). The encoded message consists of words and hash marks (#). Each
hash mark denotes a single space.
0
Print an integer denoting the number of decoded words.
Sample Input
3 5
a##ar
a#aa#
xxwsr
Sample Output
4
Explanation
The diagram at the top of the challenge demonstrates the decoding
process for the given Sample Input. The decoded message is
xaa##ar#rswx#aa. Because hash marks denote spaces, we can break the
message into four words: xaa, ar, rswx, and aa. Thus, we print 4 as our
answer.
My introduction of the algorithm:
The algorithm is an
https://www.hackerrank.com/contests/ncr-codesprint/challenges/spiral-message
You've intercepted an encoded spy message! The message originated as a
single line of one or more space-separated words, but it was encoded
into an matrix as a clockwise spiral starting in the lower left-hand
corner. For example, the diagram below shows the decoding process for
an encoded message:
The message is decoded spirally starting from the lower left-hand
corner of the matrix and moving in the clockwise direction (i.e., up,
right, down, left, up, right, etc.). From the starting position, you
must clockwise-traverse the matrix, scanning characters and switching
to the next clockwise direction each time you reach a boundary (i.e.,
an already-scanned character or the end of the matrix). Continue
scanning characters in this manner until you've scanned all the
matrix's characters into a single decoded string. The word separator
for the decoded string is the hash mark (#).
Given n, m, and an encoded message, decode the message and print the
number of words in the decoded message.
Input Format
The first line contains two space-separated positive integers
describing the respective values of n and m. Each line i of the n
subsequent lines contains a string of m characters describing row i of
the encoded message.
Constraints
Each word consists of lowercase English alphabetic characters (a to
z). The encoded message consists of words and hash marks (#). Each
hash mark denotes a single space.
0
Print an integer denoting the number of decoded words.
Sample Input
3 5
a##ar
a#aa#
xxwsr
Sample Output
4
Explanation
The diagram at the top of the challenge demonstrates the decoding
process for the given Sample Input. The decoded message is
xaa##ar#rswx#aa. Because hash marks denote spaces, we can break the
message into four words: xaa, ar, rswx, and aa. Thus, we print 4 as our
answer.
My introduction of the algorithm:
The algorithm is an
Solution
I think this needs to be separated into multiple modules and functions. If you do this, you can even docode messages encoded in various ways starting at any corner or (counter)clockwise.
This can be achieved by mixing functional and oo-programming.
The core part should be a class that can generate spiral coordinates and return them as
Internally it uses four methods to move in each direction:
To track the current boundaries you should create a struct for this.
It's easier to use then separate variables that can be grouped together.
You can define some enums to specify where to start and in which direction.
The final part should be a method that utilizes t
This can be achieved by mixing functional and oo-programming.
The core part should be a class that can generate spiral coordinates and return them as
IEnumerable like this totaly overengineered one.static class Spiral
{
public static IEnumerable Generate(int m, int n, Corner startAt, Direction direction)
{
var length = m * n;
m--;
n--;
var corners = new Dictionary
{
[Corner.TopLeft] = new Point(0, 0),
[Corner.TopRight] = new Point(m, 0),
[Corner.BottomLeft] = new Point(0, n),
[Corner.BottomRight] = new Point(m, n),
};
var boundary = new Dictionary, Boundary>
{
[Tuple.Create(Corner.TopLeft, Direction.Clockwise)] = new Boundary(0, m, 1, n),
[Tuple.Create(Corner.TopRight, Direction.Clockwise)] = new Boundary(0, m - 1, 0, n),
[Tuple.Create(Corner.BottomRight, Direction.Clockwise)] = new Boundary(0, m, 0, n - 1),
[Tuple.Create(Corner.BottomLeft, Direction.Clockwise)] = new Boundary(1, m, 0, n),
[Tuple.Create(Corner.TopRight, Direction.Counterclockwise)] = new Boundary(0, m, 1, n),
[Tuple.Create(Corner.TopLeft, Direction.Counterclockwise)] = new Boundary(1, m, 0, n),
[Tuple.Create(Corner.BottomLeft, Direction.Counterclockwise)] = new Boundary(0, m, 0, n - 1),
[Tuple.Create(Corner.BottomRight, Direction.Counterclockwise)] = new Boundary(0, m - 1, 0, n),
}
[Tuple.Create(startAt, direction)];
var pt = corners[startAt];
var moveUp = new Func(() =>
{
pt.Y--;
if (pt.Y == boundary.yMin)
{
boundary.yMin++;
return false;
}
return true;
});
var moveRight = new Func(() =>
{
pt.X++;
if (pt.X == boundary.xMax)
{
boundary.xMax--;
return false;
}
return true;
});
var moveDown = new Func(() =>
{
pt.Y++;
if (pt.Y == boundary.yMax)
{
boundary.yMax--;
return false;
}
return true;
});
var moveLeft = new Func(() =>
{
pt.X--;
if (pt.X == boundary.xMin)
{
boundary.xMin++;
return false;
}
return true;
});
var moves = new Dictionary[]>
{
[Direction.Clockwise] = new[] { moveRight, moveDown, moveLeft, moveUp },
[Direction.Counterclockwise] = new[] { moveLeft, moveDown, moveRight, moveUp, },
}
[direction];
var moveId = new Dictionary, int>
{
[Tuple.Create(Corner.TopLeft, Direction.Clockwise)] = 0,
[Tuple.Create(Corner.TopRight, Direction.Clockwise)] = 1,
[Tuple.Create(Corner.BottomRight, Direction.Clockwise)] = 2,
[Tuple.Create(Corner.BottomLeft, Direction.Clockwise)] = 3,
[Tuple.Create(Corner.TopRight, Direction.Counterclockwise)] = 0,
[Tuple.Create(Corner.TopLeft, Direction.Counterclockwise)] = 1,
[Tuple.Create(Corner.BottomLeft, Direction.Counterclockwise)] = 2,
[Tuple.Create(Corner.BottomRight, Direction.Counterclockwise)] = 3,
}
[Tuple.Create(startAt, direction)];
while (length > 0)
{
yield return pt;
length--;
if (moves[moveId]())
{
continue;
}
moveId++;
if (moveId > moves.Length - 1)
{
moveId = 0;
}
}
}
}Internally it uses four methods to move in each direction:
moveLeft, moveRight, moveTop, moveBottom. You can call them in the desired order to move in the desired direction and the few dictionaries let you configure each movement type, its starting points and starting boundaries.To track the current boundaries you should create a struct for this.
struct Boundary
{
public Boundary(int xMin, int xMax, int yMin, int yMax)
{
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
}
public int xMin;
public int xMax;
public int yMin;
public int yMax;
}It's easier to use then separate variables that can be grouped together.
You can define some enums to specify where to start and in which direction.
enum Corner
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
enum Direction
{
Clockwise,
Counterclockwise
}The final part should be a method that utilizes t
Code Snippets
static class Spiral
{
public static IEnumerable<Point> Generate(int m, int n, Corner startAt, Direction direction)
{
var length = m * n;
m--;
n--;
var corners = new Dictionary<Corner, Point>
{
[Corner.TopLeft] = new Point(0, 0),
[Corner.TopRight] = new Point(m, 0),
[Corner.BottomLeft] = new Point(0, n),
[Corner.BottomRight] = new Point(m, n),
};
var boundary = new Dictionary<Tuple<Corner, Direction>, Boundary>
{
[Tuple.Create(Corner.TopLeft, Direction.Clockwise)] = new Boundary(0, m, 1, n),
[Tuple.Create(Corner.TopRight, Direction.Clockwise)] = new Boundary(0, m - 1, 0, n),
[Tuple.Create(Corner.BottomRight, Direction.Clockwise)] = new Boundary(0, m, 0, n - 1),
[Tuple.Create(Corner.BottomLeft, Direction.Clockwise)] = new Boundary(1, m, 0, n),
[Tuple.Create(Corner.TopRight, Direction.Counterclockwise)] = new Boundary(0, m, 1, n),
[Tuple.Create(Corner.TopLeft, Direction.Counterclockwise)] = new Boundary(1, m, 0, n),
[Tuple.Create(Corner.BottomLeft, Direction.Counterclockwise)] = new Boundary(0, m, 0, n - 1),
[Tuple.Create(Corner.BottomRight, Direction.Counterclockwise)] = new Boundary(0, m - 1, 0, n),
}
[Tuple.Create(startAt, direction)];
var pt = corners[startAt];
var moveUp = new Func<bool>(() =>
{
pt.Y--;
if (pt.Y == boundary.yMin)
{
boundary.yMin++;
return false;
}
return true;
});
var moveRight = new Func<bool>(() =>
{
pt.X++;
if (pt.X == boundary.xMax)
{
boundary.xMax--;
return false;
}
return true;
});
var moveDown = new Func<bool>(() =>
{
pt.Y++;
if (pt.Y == boundary.yMax)
{
boundary.yMax--;
return false;
}
return true;
});
var moveLeft = new Func<bool>(() =>
{
pt.X--;
if (pt.X == boundary.xMin)
{
boundary.xMin++;
return false;
}
return true;
});
var moves = new Dictionary<Direction, Func<bool>[]>
{
[Direction.Clockwise] = new[] { moveRight, moveDown, moveLeft, moveUp },
[Direction.Counterclockwise] = new[] { moveLeft, moveDown, moveRight, moveUp, },
}
[direction];
var moveId = new Dictionary<Tuple<Corner, Direction>, int>
{
[Tuple.Create(Corner.TopLeft, Direction.Clockwise)] = 0,
[Tuple.Create(Corner.TopRight, Direction.Clockwise)] = 1,
[Tuple.Create(Corner.BottomRight, Direction.Clockwise)] = 2,
[Tuple.Create(Corstruct Boundary
{
public Boundary(int xMin, int xMax, int yMin, int yMax)
{
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
}
public int xMin;
public int xMax;
public int yMin;
public int yMax;
}enum Corner
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
enum Direction
{
Clockwise,
Counterclockwise
}static class SpiralMessage
{
public static IEnumerable<string> Decode(this string[] value)
{
var word = new StringBuilder();
foreach (var pt in Spiral.Generate(value.First().Length, value.Length, Corner.BottomLeft, Direction.Clockwise))
{
var c = value[pt.Y][pt.X];
if (c == '#')
{
if (word.Length > 0)
{
yield return word.ToString();
word = new StringBuilder();
}
}
else
{
word.Append(c);
}
}
// yield the last word if any
if (word.Length > 0)
{
yield return word.ToString();
word = new StringBuilder();
}
}
}var arr = new[]
{
"a##ar",
"a#aa#",
"xxwsr"
};
var words = arr.Decode().ToList(); // xaa, ar, rswx, aaContext
StackExchange Code Review Q#149375, answer score: 3
Revisions (0)
No revisions yet.