/// <summary> /// Get the possible initial position of a given <see cref="TetriminoKind" /> which is closest to the upper edge. /// </summary> /// <param name="kind">Kind of the Tetrimino</param> /// <returns>A <see cref="Position" /> indicating the position</returns> public static Position GetInitialPositionByKind(TetriminoKind kind) { var length = 0; switch (kind) { case TetriminoKind.Linear: length = 4; break; case TetriminoKind.Cubic: length = 2; break; case TetriminoKind.LShapedCis: case TetriminoKind.LShapedTrans: case TetriminoKind.ZigZagTrans: case TetriminoKind.ZigZagCis: case TetriminoKind.TShaped: length = 3; break; default: throw new ArgumentException(nameof(kind)); } var row = 0; var column = (TetrisConst.PlayAreaWidth - length) / 2; return(new Position(column, row)); }
/// <summary> /// Rotates tetrimino /// </summary> /// <param name="rotationDirection">Direction of rotation</param> /// <param name="checkCollision">Collision checker</param> /// <returns>True if tetrimino has rotated</returns> public bool Rotation(RotationDirection rotationDirection, Func <Block, bool> checkCollision) { var count = Enum.GetValues(typeof(Direction)).Length; var delta = (rotationDirection == RotationDirection.Right) ? 1 : -1; var direction = (int)Direction + delta; if (direction < 0) { direction += count; } if (direction >= count) { direction %= count; } var adjustPattern = TetriminoKind == TetriminoKind.I ? new[] { 0, 1, -1, 2, -2 } : new[] { 0, 1, -1 }; foreach (var adjust in adjustPattern) { var position = new Position(Position.Row, Position.Column + adjust); var blocks = TetriminoKind.CreateBlocks(position, (Direction)direction); if (blocks.Any(checkCollision)) { continue; } Direction = (Direction)direction; Position = position; Blocks = blocks; return(true); } return(false); }
public static SolidColorBrush GetBlockColorByTetriminoKind(TetriminoKind tetriminoKind) { switch (tetriminoKind) { case TetriminoKind.Linear: return(new SolidColorBrush(Colors.Blue)); case TetriminoKind.Cubic: return(new SolidColorBrush(Colors.Lime)); case TetriminoKind.LShapedCis: return(new SolidColorBrush(Colors.Green)); case TetriminoKind.LShapedTrans: return(new SolidColorBrush(Colors.Red)); case TetriminoKind.ZigZagCis: return(new SolidColorBrush(Colors.Yellow)); case TetriminoKind.ZigZagTrans: return(new SolidColorBrush(Colors.Purple)); case TetriminoKind.TShaped: return(new SolidColorBrush(Colors.Gray)); default: throw new ArgumentException(nameof(tetriminoKind)); } }
public Block(TetriminoKind filledBy, Position position, int atomicNumber, int identifier) { FilledBy = filledBy; Position = position; AtomicNumber = atomicNumber; Identifier = identifier; }
public static Position GetFirstBlockPositionByPosition(Position position, TetriminoKind kind, Direction facingDirection) { var blockPattern = CreateBlockPattern(kind, facingDirection); var firstBlockRow = 0; var firstBlockCol = 0; var firstBlockFound = false; for (var nRow = 0; nRow < blockPattern.GetLength(0); nRow++) { for (var nCol = 0; nCol < blockPattern.GetLength(1); nCol++) { if (blockPattern[nRow, nCol] != 0) { firstBlockRow = nRow; firstBlockCol = nCol; firstBlockFound = true; break; } } if (firstBlockFound) { break; } } return(new Position(position.X + firstBlockCol, position.Y + firstBlockRow)); }
/// <summary> /// ブロックの初期位置を取得します。 /// </summary> /// <param name="self">テトリミノの種類</param> /// <returns>初期位置</returns> public static Position InitialPosition(this TetriminoKind self) { int length = 0; switch (self) { case TetriminoKind.I: length = 4; break; case TetriminoKind.O: length = 2; break; case TetriminoKind.S: case TetriminoKind.Z: case TetriminoKind.J: case TetriminoKind.L: case TetriminoKind.T: length = 3; break; case TetriminoKind.RANDOM: length = 3; break; case TetriminoKind.NEXTRANDOM: length = 3; break; default: throw new InvalidOperationException("Unknown Tetrimino"); } var row = -length; var column = (Field.ColumnCount - length) / 2; return(new Position(row, column)); }
public Tetrimino(TetriminoKind kind) { Kind = kind; Position = TetriminoHelper.GetInitialPositionByKind(kind); Blocks = TetriminoHelper.CreateOffsetedBlocks(kind, Position); FacingDirection = Direction.Up; }
/// <summary> /// インスタンスを生成します。 /// </summary> /// <param name="kind">テトリミノの種類</param> private Tetrimino(TetriminoKind kind) { this.Kind = kind; this.Position = kind.InitialPosition(); //TetriminoExtensions.SetRandomPattern(); this.Blocks = kind.CreateBlock(this.Position); }
public static Tetrimino ByPosition(TetriminoKind kind, Position position, Direction facingDirection) { return(new Tetrimino(kind, position, TetriminoHelper.GetFirstBlockPositionByPosition(position, kind, facingDirection), facingDirection)); }
/// <summary> /// 開始します。 /// </summary> /// <param name="kind">最初のテトリミノの種類</param> public void Start(TetriminoKind kind) { this.Reset(); this.isActivated.Value = true; this.Tetrimino.Value = new Tetrimino(kind); this.Timer.Start(); }
/// <summary> /// Moves tetrimino /// </summary> /// <param name="moveDirection">Direction of movement</param> /// <param name="checkCollision">Collision checker</param> /// <returns>True if tetrimino has moved</returns> public bool Move(MoveDirection moveDirection, Func <Block, bool> checkCollision) { var position = Position; if (moveDirection == MoveDirection.Down) { var row = position.Row + 1; position = new Position(row, position.Column); } else { var delta = (moveDirection == MoveDirection.Right) ? 1 : -1; var column = position.Column + delta; position = new Position(position.Row, column); } var blocks = TetriminoKind.CreateBlocks(position, Direction); if (blocks.Any(checkCollision)) { return(false); } Position = position; Blocks = blocks; return(true); }
public static Tetrimino ByFirstBlockPosition(TetriminoKind kind, Position firstBlockPosition, Direction facingDirection) { return(new Tetrimino(kind, GeneratorHelper.GetPositionByFirstBlockPosition(firstBlockPosition, kind, facingDirection), firstBlockPosition, facingDirection)); }
/// <summary> /// 次の場におけるブロックの初期位置を取得します。 /// </summary> /// <param name="self">テトリミノの種類</param> /// <returns>初期位置</returns> private static Position InitialPosition(TetriminoKind self) { var length = self.GetBoundingBoxHeight(); var row = (RowCount - length) / 2; var column = (ColumnCount - length) / 2; return(new Position(row, column)); }
private Tetrimino(TetriminoKind kind, Position position, Position firstBlockPosition, Direction facingDirection) { Kind = kind; Position = position; FacingDirection = facingDirection; FirstBlockPosition = firstBlockPosition; Blocks = TetriminoHelper.CreateOffsetedBlocks(kind, Position, facingDirection); }
/// <summary> /// 場におけるブロックの初期位置を取得します。 /// </summary> /// <param name="self">テトリミノの種類</param> /// <returns>初期位置</returns> public static Position InitialPosition(this TetriminoKind self) { var length = self.GetBoundingBoxHeight(); var row = -length; var column = (Field.ColumnCount - length) / 2; return(new Position(row, column)); }
public static Position GetFirstBlockPositionByPosition(Position position, TetriminoKind kind, Direction facingDirection) { int firstBlockRow, firstBlockCol; (firstBlockRow, firstBlockCol) = GetFirstBlockPosFromMask(kind, facingDirection); return(new Position(position.X + firstBlockCol, position.Y + firstBlockRow)); }
protected Tetrimino(TetriminoKind kind, Position position, Position firstBlockPosition, Direction facingDirection) { Kind = kind; Position = position; FacingDirection = facingDirection; FirstBlockPosition = firstBlockPosition; Blocks = GeneratorHelper.CreateOffsetBlocks(kind, Position, facingDirection); }
/// <summary> /// アクティブ化します。 /// </summary> /// <param name="kind">最初のテトリミノの種類</param> public void Activate(TetriminoKind kind) { this.isActivated.Value = true; this.isUpperLimitOvered.Value = false; this.Tetrimino.Value = Models.Tetrimino.Create(kind); this.placedBlocks.Value = Array.Empty <Block>(); this.Timer.Interval = 1000; this.Timer.Start(); }
/// <summary> /// Activates game area /// </summary> /// <param name="tetriminoKind">Active tetrimino kind</param> public void Activate(TetriminoKind tetriminoKind) { _isActivated.Value = true; _isUpperLimitReached.Value = false; Tetrimino.Value = Models.Tetrimino.Create(tetriminoKind); _placedBlocks.Value = Array.Empty <Block>(); Timer.Interval = 1000; Timer.Start(); }
public TetriminoKindDirectionsPair(TetriminoKind kind, Random rand) { Kind = kind; PendingDirections = new Stack <Direction>(new[] { Direction.Left, Direction.Right, Direction.Up, Direction.Down }.ToList().OrderBy(x => rand.Next())); }
/// <summary> /// Sets color of the blocks building tetrimino /// </summary> /// <param name="self">Tetrimino kind</param> /// <returns>Color of given tetrimino kind</returns> public static Color BlockColor(this TetriminoKind self) { return(self switch { TetriminoKind.I => Colors.LightBlue, TetriminoKind.O => Colors.Yellow, TetriminoKind.S => Colors.YellowGreen, TetriminoKind.Z => Colors.Red, TetriminoKind.J => Colors.Blue, TetriminoKind.L => Colors.Orange, TetriminoKind.T => Colors.Purple, _ => throw new ArgumentOutOfRangeException(nameof(self), self, null), });
/// <summary> /// <see cref="Direction.Up"/> なブロックを囲う最小矩形の高さを取得します。 /// </summary> /// <param name="self">テトリミノの種類</param> /// <returns>長さ</returns> public static int GetBoundingBoxHeight(this TetriminoKind self) { switch (self) { case TetriminoKind.I: return(4); case TetriminoKind.O: case TetriminoKind.S: case TetriminoKind.Z: case TetriminoKind.J: case TetriminoKind.L: case TetriminoKind.T: return(2); default: throw new InvalidOperationException("Unknown Tetrimino"); } }
/// <summary> /// Get a list of <see cref="Block" />s well positioned according to the offset. /// </summary> /// <returns>A <see cref="IReadOnlyList{Block}" /> which contains properly offseted blocks</returns> public static IReadOnlyList <Block> CreateOffsetedBlocks(TetriminoKind kind, Position offset, Direction direction = Direction.Up) { var blockPattern = CreateBlockPattern(kind, direction); var offsetedBlocks = new List <Block>(); for (var nRow = 0; nRow < blockPattern.GetLength(0); nRow++) { for (var nCol = 0; nCol < blockPattern.GetLength(1); nCol++) { if (blockPattern[nRow, nCol] != 0) { offsetedBlocks.Add(new Block(kind, new Position(nCol + offset.X, nRow + offset.Y))); } } } return(offsetedBlocks.ToArray()); }
/// <summary> /// ブロックの色を取得します。 /// </summary> /// <param name="self">テトリミノの種類</param> /// <returns>色</returns> public static Color BlockColor(this TetriminoKind self) { switch (self) { case TetriminoKind.I: return(Color.LightBlue); case TetriminoKind.O: return(Color.Yellow); case TetriminoKind.S: return(Color.YellowGreen); case TetriminoKind.Z: return(Color.Red); case TetriminoKind.J: return(Color.Blue); case TetriminoKind.L: return(Color.Orange); case TetriminoKind.T: return(Color.Purple); } throw new InvalidOperationException("Unknown Tetrimino"); }
/// <summary> /// Get a list of <see cref="Block" />s well positioned according to the offset. /// </summary> /// <returns>A <see cref="IReadOnlyList{Block}" /> which contains properly offset blocks</returns> public static IReadOnlyList <Block> CreateOffsetBlocks(TetriminoKind kind, Position offset, Direction direction = Direction.Up) { var mask = CreateBlocksMask(kind, direction); var offsetBlocks = new List <Block>(4); for (var nRow = 0; nRow < mask.GetLength(0); nRow++) { for (var nCol = 0; nCol < mask.GetLength(1); nCol++) { var identifier = mask[nRow, nCol]; if (identifier != 0) { offsetBlocks.Add(new Block(kind, new Position(nCol + offset.X, nRow + offset.Y), 0, identifier)); } } } return(offsetBlocks); }
public Block(TetriminoKind filledBy, Position position) { FilledBy = filledBy; Position = position; }
public TetriminoNode(TetriminoKind kind, Position position, Position firstBlockPosition, Direction facingDirection) : base(kind, position, firstBlockPosition, facingDirection) { }
/// <summary> /// インスタンスを生成します。 /// </summary> /// <param name="kind">テトリミノの種類</param> private Tetrimino(TetriminoKind kind) { this.Kind = kind; this.Position = kind.InitialPosition(); this.Blocks = kind.CreateBlock(this.Position); }
/// <summary> /// 指定されたテトリミノの種類と方向に一致したブロックを生成します。 /// </summary> /// <param name="self">テトリミノの種類</param> /// <param name="offset">絶対座標への移動分</param> /// <param name="direction">方向</param> /// <returns>ブロックのコレクション</returns> public static Block[] CreateBlock(this TetriminoKind self, Position offset, Direction direction) { //--- ブロック形状をビットで表現 //--- ベタ書きだけど、これが最も分かりやすく高速 int[,] pattern = null; switch (self) { #region I case TetriminoKind.I: switch (direction) { case Direction.Up: pattern = new int[, ] { { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, }; break; case Direction.Right: pattern = new int[, ] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, }; break; case Direction.Down: pattern = new int[, ] { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, }; break; case Direction.Left: pattern = new int[, ] { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, }; break; } break; #endregion #region O case TetriminoKind.O: pattern = new int[, ] { { 1, 1 }, { 1, 1 }, }; break; #endregion #region S case TetriminoKind.S: switch (direction) { case Direction.Up: pattern = new int[, ] { { 0, 1, 1 }, { 1, 1, 0 }, { 0, 0, 0 }, }; break; case Direction.Right: pattern = new int[, ] { { 0, 1, 0 }, { 0, 1, 1 }, { 0, 0, 1 }, }; break; case Direction.Down: pattern = new int[, ] { { 0, 0, 0 }, { 0, 1, 1 }, { 1, 1, 0 }, }; break; case Direction.Left: pattern = new int[, ] { { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, }; break; } break; #endregion #region Z case TetriminoKind.Z: switch (direction) { case Direction.Up: pattern = new int[, ] { { 1, 1, 0 }, { 0, 1, 1 }, { 0, 0, 0 }, }; break; case Direction.Right: pattern = new int[, ] { { 0, 0, 1 }, { 0, 1, 1 }, { 0, 1, 0 }, }; break; case Direction.Down: pattern = new int[, ] { { 0, 0, 0 }, { 1, 1, 0 }, { 0, 1, 1 }, }; break; case Direction.Left: pattern = new int[, ] { { 0, 1, 0 }, { 1, 1, 0 }, { 1, 0, 0 }, }; break; } break; #endregion #region J case TetriminoKind.J: switch (direction) { case Direction.Up: pattern = new int[, ] { { 1, 0, 0 }, { 1, 1, 1 }, { 0, 0, 0 }, }; break; case Direction.Right: pattern = new int[, ] { { 0, 1, 1 }, { 0, 1, 0 }, { 0, 1, 0 }, }; break; case Direction.Down: pattern = new int[, ] { { 0, 0, 0 }, { 1, 1, 1 }, { 0, 0, 1 }, }; break; case Direction.Left: pattern = new int[, ] { { 0, 1, 0 }, { 0, 1, 0 }, { 1, 1, 0 }, }; break; } break; #endregion #region L case TetriminoKind.L: switch (direction) { case Direction.Up: pattern = new int[, ] { { 0, 0, 1 }, { 1, 1, 1 }, { 0, 0, 0 }, }; break; case Direction.Right: pattern = new int[, ] { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 1 }, }; break; case Direction.Down: pattern = new int[, ] { { 0, 0, 0 }, { 1, 1, 1 }, { 1, 0, 0 }, }; break; case Direction.Left: pattern = new int[, ] { { 1, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, }; break; } break; #endregion #region T case TetriminoKind.T: switch (direction) { case Direction.Up: pattern = new int[, ] { { 0, 1, 0 }, { 1, 1, 1 }, { 0, 0, 0 }, }; break; case Direction.Right: pattern = new int[, ] { { 0, 1, 0 }, { 0, 1, 1 }, { 0, 1, 0 }, }; break; case Direction.Down: pattern = new int[, ] { { 0, 0, 0 }, { 1, 1, 1 }, { 0, 1, 0 }, }; break; case Direction.Left: pattern = new int[, ] { { 0, 1, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, }; break; } break; #endregion } //--- どれにも当てはまらなかった if (pattern == null) { throw new InvalidOperationException("Unknown Tetrimino"); } //--- ビットが立っている部分にブロックを作成 var color = self.BlockColor(); return(Enumerable.Range(0, pattern.GetLength(0)) .SelectMany(r => Enumerable.Range(0, pattern.GetLength(1)).Select(c => new Position(r, c))) .Where(x => pattern[x.Row, x.Column] != 0) //--- bit が立っているところ .Select(x => new Position(x.Row + offset.Row, x.Column + offset.Column)) //--- 絶対座標変換 .Select(x => new Block(color, x)) .ToArray()); }
public Block(TetriminoKind filledBy, Position position) : this(filledBy, position, 0, 0) { }