public static IReadOnlyList <TetriminoNode> GetTetriminoDependencyGraph(IReadOnlyList <Tetrimino> tetriminos, int playAreaWidth, int playAreaHeight) { // Build block map var tetriminoNodes = new List <TetriminoNode>(tetriminos.Count); var memoizedMap = new MemoizedBlock[playAreaHeight, playAreaWidth]; foreach (var tetrimino in tetriminos) { var tetriminoNode = new TetriminoNode(tetrimino.Kind, tetrimino.Position, GeneratorHelper.GetFirstBlockPositionByPosition(tetrimino.Position, tetrimino.Kind, tetrimino.FacingDirection), tetrimino.FacingDirection ); tetriminoNode.Blocks = tetriminoNode.MemoizedBlocks = GetMemoizedBlocksForTetriminoNode(tetriminoNode, tetrimino); foreach (var block in tetriminoNode.MemoizedBlocks) { memoizedMap[block.Position.Y, block.Position.X] = block; } tetriminoNodes.Add(tetriminoNode); } // Get dependency relationship foreach (var tetriminoNode in tetriminoNodes) { foreach (var block in tetriminoNode.MemoizedBlocks) { // if a blocker under the current block is occupied then // this tetrimino can not be placed until the underlying block's // owner is placed, i.e., this tetrimino depends on the underlying // block's owner. var dependedBlockRow = block.Position.Y + 1; var dependedBlockCol = block.Position.X; if (!TryGetOccupiedTetriminoNode( memoizedMap, dependedBlockRow, dependedBlockCol, playAreaWidth, playAreaHeight, out var dependOn ) || dependOn == tetriminoNode) { continue; } dependOn.DependedBy.Add(tetriminoNode); tetriminoNode.Depending.Add(dependOn); } } return(tetriminoNodes); }
/// <summary> /// Get a list of playable and encapsulated <see cref="Tetrimino" /> in the pattern of the /// periodic table. /// </summary> public static IReadOnlyList <Tetrimino> GetPlayablePattern(Random rand) { var dim0Len = GeneratorHelper.PeriodicTableTemplate.GetLength(0); var dim1Len = GeneratorHelper.PeriodicTableTemplate.GetLength(1); var template = new Block[dim0Len, dim1Len]; for (var i = 0; i < dim0Len; i++) { for (var j = 0; j < dim1Len; j++) { template[i, j] = new Block(GeneratorHelper.PeriodicTableTemplate[i, j].FilledBy, GeneratorHelper.PeriodicTableTemplate[i, j].Position, GeneratorHelper.PeriodicTableTemplate[i, j].AtomicNumber ); } } var tetriminos = TetriminoSorter.Sort( GetPossibleTetriminoPattern(template, rand), dim1Len, dim0Len); Parallel.ForEach(tetriminos, tetrimino => { // Repositioning the tetriminos. var originalPosition = tetrimino.Position; var newPosition = GeneratorHelper.GetInitialPositionByKind(tetrimino.Kind); var deltaX = newPosition.X - originalPosition.X; var deltaY = newPosition.Y - originalPosition.Y; var newBlocks = new List <Block>(tetrimino.Blocks.Count); newBlocks .AddRange( tetrimino.Blocks.Select( block => new Block(block.FilledBy, new Position(block.Position.X + deltaX, block.Position.Y + deltaY), block.AtomicNumber, block.Identifier) ) ); tetrimino.Blocks = newBlocks; tetrimino.Position = newPosition; // Randomly rotate the current Tetrimino. var rotationCount = rand.Next(0, Enum.GetValues(typeof(Direction)).Length); for (var i = 0; i < rotationCount; i++) { tetrimino.TryRotate(RotationDirection.Right, _ => false); } }); return(tetriminos); }