Let's go!

In total, we have 3 different routes, the rest can be obtained from them by rotating, mirroring the main diagonal and the direction of following (from 1 to 9 and from 9 to 1, see the picture).
From one cell you can get to 4 neighboring ones, it can be encoded with two bits (see picture: 00 - to the left, 01 - down, etc.), all you need to do is 8 steps, totaling one route is encoded with a 16-bit number.
I figured them out and signed them in the picture. For example, route 1452:
left (00) => left (00) => down (01) => down (01) => right (10) => right (10) => up (11) => left (00), total 0000 0101 1010 1100 = 1452
For route 1680, there will be 8, not 16 unique mappings (since the route is mapped to itself when rotated 180 degrees), but for the sake of simplicity we will generate all 16.
That is, there are 40 routes in total, we will bypass 48, I think this is not critical :)
What can you do about it?
Let's get the structure describing the position:
struct Pos { public int X { get; } public int Y { get; } public Pos(int x, int y) { X = x; Y = y; } public Pos Move(int code) { switch (code) { case 0: return new Pos(X + 1, Y); case 1: return new Pos(X, Y + 1); case 2: return new Pos(X - 1, Y); case 3: return new Pos(X, Y - 1); } throw new NotSupportedException(); } }
It also defines a method for moving to the next cell using the direction code.
Let's get a class describing the path, it's just a container for the characteristics:
class WayDescription { public int Way { get; } public Pos Start { get; } public Pos End { get; } public WayDescription(int way, Pos start, Pos end) { Way = way; Start = start; End = end; } }
Now we need an iterator along the way, it will have 2 implementations: in the forward direction and in the opposite direction:
abstract class StepEnumerable : IEnumerable<int> { protected readonly WayDescription wd; public StepEnumerable(WayDescription wd) => this.wd = wd; public abstract Pos Start(); protected abstract int Next(); public IEnumerator<int> GetEnumerator() { for (int i = 0; i < 8; ++i) yield return Next(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class ForwardStepEnumerable : StepEnumerable { private int shift = 16; private readonly int way; public ForwardStepEnumerable(WayDescription wd) : base(wd) => way = wd.Way; public override Pos Start() => wd.Start; protected override int Next() { shift -= 2; return (way >> shift) % 4; } } class ReverseStepEnumerable : StepEnumerable { private int way; public ReverseStepEnumerable(WayDescription wd) : base(wd) => way = wd.Way * 4; public override Pos Start() => wd.End; protected override int Next() { way /= 4; return (way + 2) % 4; // Циклический сдвиг, переводит 00 <=> 10 и 01 <=> 11 } }
We also need a position interpreter, which will impose the necessary transformations on the coordinates: mapping and rotation.
Base class:
abstract class PosInterpreter { public abstract Pos Translate(Pos pos); }
Implementations for direct and mirror image:
class StraightPosInterpreter : PosInterpreter { public override Pos Translate(Pos pos) => pos; } class MirrorPosInterpreter : PosInterpreter { public override Pos Translate(Pos pos) => new Pos(pos.Y, pos.X); }
As well as the implementation-decorator that accepts the display function:
class FuncPosInterpreter : PosInterpreter { private readonly PosInterpreter posInterpreter; private readonly Func<Pos, Pos> func; public FuncPosInterpreter(PosInterpreter posInterpreter, Func<Pos, Pos> func) { this.posInterpreter = posInterpreter; this.func = func; } public override Pos Translate(Pos pos) => func(posInterpreter.Translate(pos)); }
It will assume a rotating function and an interpreter for mirroring.
Great, we have everything we need, it remains to create the necessary instances and iterate on them:
static void Main() { // 3 пути WayDescription[] wayDescs = { new WayDescription(1452, new Pos(0, 0), new Pos(1, 1)), new WayDescription(1465, new Pos(0, 0), new Pos(0, 2)), new WayDescription(1680, new Pos(0, 0), new Pos(2, 2)) }; // 2 фабрики итераторов пути var stepEnumerableFactories = new Func<WayDescription, StepEnumerable>[] { wd => new ForwardStepEnumerable(wd), wd => new ReverseStepEnumerable(wd) }; // 2 интерпретатора позиции (прямой и зеркальный) var smPosInterps = new PosInterpreter[] { new StraightPosInterpreter(), new MirrorPosInterpreter() }; // 4 функции для вращательного отображения координат var posFuncs = new Func<Pos, Pos>[] { pos => pos, pos => new Pos(2 - pos.Y, pos.X), // 90 градусов pos => new Pos(2 - pos.X, 2 - pos.Y), // 180 pos => new Pos(pos.Y, 2 - pos.X) // 270 }; // Входной массив int[,] array = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; foreach (var wd in wayDescs) { foreach (var sef in stepEnumerableFactories) { foreach (var pi in smPosInterps) { foreach (var f in posFuncs) { // Создаем интерпретатор позиции над // указанным интерпретатором зеркального отображения // и с указанной функцией вращения var posInterp = new FuncPosInterpreter(pi, f); // Создаем итератор по пути var se = sef(wd); // Начальная позиция var pos = se.Start(); // Транслированная начальная позиция var tPos = posInterp.Translate(pos); int x = array[tPos.Y, tPos.X]; // Итерируем по шагам пути foreach (var s in se) { // Координаты после шага pos = pos.Move(s); tPos = posInterp.Translate(pos); x = 10 * x + array[tPos.Y, tPos.X]; } Console.WriteLine(x); } } } } Console.ReadLine(); }
Done! This code displays 48 numbers, choose the maximum of them yourself.
string.Join(table.Cast<int>().OrderByDescending(x => x))
- Kir_Antipov 5:17 pmперемещаться можно на соседнюю ячейку только по горизонтали и вертикали
- tym32167 5:48 pm