public TetrisFiguresRandom(int Size, bool CheckConnected = true, int MinBlocks = 0, int MaxBlocks = 0) { int Variants = (int)Math.Pow(2, Size * Size); // количество вариантов для анализа for (int Variant = 1; Variant < Variants; Variant++) { bool[] Bits = Convert.ToString(Variant, 2).PadLeft(Size * Size, '0').Select(c => c == '1').ToArray(); // проверяем количество точек int BlockCount = Bits.Count(b => b); if ((MinBlocks != 0 && BlockCount < MinBlocks) || (MaxBlocks != 0 && BlockCount > MaxBlocks)) { continue; } // заполняем точки фигуры, проверяем положение в левом верхнем углу TetrisBlock[] Blocks = new TetrisBlock[BlockCount]; bool FirstRow = false; bool FirstColumn = false; int BlockNumber = 0; for (int X = 0; X < Size; X++) { for (int Y = 0; Y < Size; Y++) { if (Bits[X * Size + Y]) { Blocks[BlockNumber] = new TetrisBlock(X, Y); BlockNumber++; if (Y == 0) { FirstRow = true; } if (X == 0) { FirstColumn = true; } } } } if (!FirstRow || !FirstColumn) { continue; } // проверяем связность фигуры if (CheckConnected) { // http://algolist.manual.ru/maths/graphs/linked.php // начальное значение - точки не связаны foreach (TetrisBlock Block in Blocks) { Block.Mark = 1; } // начинаем проверку связности с этой точки Blocks[0].Mark = 2; TetrisBlock StartBlock; while ((StartBlock = Blocks.FirstOrDefault(p => p.Mark == 2)) != null) { // точка обработана StartBlock.Mark = 3; // связанные точки ставим в очередь на обработку foreach (TetrisBlock Block in Blocks.Where(p => p.Mark == 1 && Math.Abs(StartBlock.X - p.X) + Math.Abs(StartBlock.Y - p.Y) == 1)) { Block.Mark = 2; } } // остались не связанные точки if (Blocks.Any(p => p.Mark == 1)) { continue; } } // проверяем совпадение фигур и добавляем фигуру TetrisFigure Figure = new TetrisFigure(Blocks); if (!Figures.Any(f => f.IsSimilar(Figure))) { AddFigure(Figure); } } }