using System.Collections;
using System.Collections.Generic;
public static class DirectionOrderExtensions
public static Direction NextClockwise(this Direction direction)
Direction.Top => Direction.Right,
Direction.Right => Direction.Bottom,
Direction.Bottom => Direction.Left,
Direction.Left => Direction.Top,
_ => throw new NotImplementedException(),
public static Direction NextCounterclockwise(this Direction direction)
Direction.Top => Direction.Left,
Direction.Left => Direction.Bottom,
Direction.Bottom => Direction.Right,
Direction.Right => Direction.Top,
_ => throw new NotImplementedException(),
public Cell(int row, int col)
public int Row { get; init; }
public int Col { get; init; }
public static Cell operator +(Cell cell, Direction direction)
Direction.Top => new Cell(cell.Row - 1, cell.Col),
Direction.Bottom => new Cell(cell.Row + 1, cell.Col),
Direction.Left => new Cell(cell.Row, cell.Col - 1),
Direction.Right => new Cell(cell.Row, cell.Col + 1),
_ => throw new NotImplementedException(),
private readonly string[][] _matrix;
public Matrix(string[][] matrix)
if (matrix.Any(row => row.Length != matrix[0].Length))
throw new ArgumentOutOfRangeException(nameof(matrix));
public string this[Cell cell]
return _matrix[cell.Row][cell.Col];
_matrix[cell.Row][cell.Col] = value;
public bool IsOutOfBounds(Cell cell)
return cell.Row >= _matrix.Length
|| cell.Col >= _matrix[cell.Row].Length
public override string ToString()
_matrix.Select(row => string.Join("\t", row))
public class MatrixGenerator
public class RandomLetter
static readonly Random _random = new();
int num = _random.Next(0, 26);
_letter = (char)('a' + num);
public override string ToString()
return _letter.ToString();
public Matrix Generate(int rows, int cols)
string[][] matrixStrings = Enumerable.Range(0, rows)
Enumerable.Range(0, cols).Select(_ => new RandomLetter().ToString()).ToArray()
return new Matrix(matrixStrings);
public class MatrixSnakeEnumerable : IEnumerable<string>
private readonly Matrix _matrix;
public MatrixSnakeEnumerable(Matrix matrix)
public IEnumerator<string> GetEnumerator()
return new MatrixSnakeEnumerator(_matrix);
IEnumerator IEnumerable.GetEnumerator()
return new MatrixSnakeEnumerator(_matrix);
public class MatrixSnakeEnumerator : IEnumerator<string>
private readonly Matrix _matrix;
private HashSet<Cell> _visited;
private Direction _movement;
private Cell _currentPosition;
public MatrixSnakeEnumerator(Matrix matrix)
public string Current => _matrix[_currentPosition];
object IEnumerator.Current => Current;
if (_currentPosition == null)
_currentPosition = new Cell(0, 0);
var nextPosition = _currentPosition + _movement;
if (_matrix.IsOutOfBounds(nextPosition) || _visited.Contains(nextPosition))
_movement = _movement.NextClockwise();
nextPosition = _currentPosition + _movement;
if (_matrix.IsOutOfBounds(nextPosition) || _visited.Contains(nextPosition))
_visited.Add(_currentPosition);
_currentPosition = nextPosition;
_movement = Direction.Right;
static void Main(string[] args)
var nonRandom = new Matrix(new string[][] {
new string[] {"a", "b", "c"},
new string[] {"h", "i", "d"},
new string[] {"g", "f", "e"},
var snakePath = string.Join("", new MatrixSnakeEnumerable(nonRandom));
Console.WriteLine(nonRandom);
Console.WriteLine(snakePath);
Console.WriteLine("\n\n");
var random = new MatrixGenerator().Generate(5, 6);
snakePath = string.Join("", new MatrixSnakeEnumerable(random));
Console.WriteLine(random);
Console.WriteLine(snakePath);