首页  编辑  

俄罗斯方块

Tags: /C#/项目实例/   Date Created:

using System ;

using System . Collections . Generic;

using System . Runtime . InteropServices;

using System . Drawing . Drawing2D;

using System . Drawing . Imaging;

using System . Text;

using System . Windows . Forms;

using System . Data;

using System . Drawing;

using System . ComponentModel;

using System . Threading;

using System . Diagnostics;

using System . IO;

namespace Tetris

{

    public class TetrisControl : Control

   {

       #region Field

        private const int rowCount = 21 ; //

        private const int colCount = 11 ; //

        private int brickWidth = 16 ; //

        private int brickHeight = 16 ; //

        private ImageList imageList; //

        private Bitmap backBitmap; //

        private List < List < List < Point >>> brickTemplets = new List < List < List < Point >>> (); //

        private byte [,] points = new byte [colCount, rowCount]; //

        private byte brickIndex = 0 ; //

        private byte facingIndex = 0 ; //

        private Point brickPoint = new Point (); //

        private byte afterBrickIndex = 0 ; //

        private byte afterFacingIndex = 0 ; //

        private System . Windows . Forms . Timer timer; //

        private int lines; //

        private Random random = new Random (); //

        private int level = 0 ; //

        private int score = 0 ; //

        private int [] speeds = new int [] { 800 , 650 , 500 , 400 , 350 , 200 , 180 , 150 , 130 , 100 , 60 };

        private int [] scoress = new int [] { 0001 , 0100 , 0300 , 0500 , 1000 , 2000 };

        private bool playing = false ;

        private TetrisNext tetrisNext;

        private TetrisScore tetrisScore;

        private int stepIndex = - 1 ;

        private bool reviewing = false ;

        private Thread threadReview = null ;

        private int reviewSpeed = 1 ;

        private List < StepInfo > StepInfos = new List < StepInfo > ();

        private int lastRecordTime = 0 ; //

        private bool recordMode = false ; //

        private ProgressBar progressBar;

       #endregion Field

        /// <summary>

        ///

        /// </summary>

        public int Lines { get { return lines; } }

        public int Score { get { return score; } }

        public int Level { get { return level; } }

        /// <summary>

        ///

        /// </summary>

        public enum BrickOperates

       {

           boMoveLeft = 0 , //

           boMoveRight = 1 , //

           boMoveDown = 2 , //

           boMoveBottom = 3 , //

           boTurnLeft = 4 , //

           boTurnRight = 5 , //

       }

        /// <summary>

        ///

        /// </summary>

        public struct StepInfo

       {

            public byte command; //

            public ushort timeTick; //

            public byte param1; //

            public byte param2; //

            public StepInfo( int ATimeTick, byte ACommand, byte AParam1, byte AParam2)

           {

               timeTick = ( ushort )ATimeTick;

               command = ACommand;

               param1 = AParam1;

               param2 = AParam2;

           }

       }

        public TetrisControl()

       {

           Width = colCount * brickWidth;

           Height = rowCount * brickHeight;

           BackColor = Color . Black;

            List < List < Point >> templets;

            List < Point > bricks;

           #region

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 0 , 0 )); //[00][10][  ][  ]

           bricks . Add( new Point ( 1 , 0 )); //[01][11][  ][  ]

           bricks . Add( new Point ( 0 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][  ][  ]

           bricks . Add( new Point ( 0 , 1 )); //[01][11][21][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][11][21][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 0 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[01][11][21][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][  ][  ]

           bricks . Add( new Point ( 0 , 1 )); //[01][11][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][11][21][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 3 )); //[  ][13][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 0 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[01][11][21][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][  ][22][  ]

           bricks . Add( new Point ( 2 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 2 , 0 )); //[  ][  ][20][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][  ][21][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][12][22][  ]

           bricks . Add( new Point ( 2 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][11][  ][  ]

           bricks . Add( new Point ( 2 , 2 )); //[  ][12][22][32]

           bricks . Add( new Point ( 3 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][11][21][  ]

           bricks . Add( new Point ( 2 , 2 )); //[  ][  ][22][  ]

           bricks . Add( new Point ( 2 , 3 )); //[  ][  ][23][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 2 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 0 , 2 )); //[  ][  ][21][  ]

           bricks . Add( new Point ( 1 , 2 )); //[02][12][22][  ]

           bricks . Add( new Point ( 2 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][11][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][12][22][  ]

           bricks . Add( new Point ( 2 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][11][21][31]

           bricks . Add( new Point ( 3 , 1 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][11][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 3 )); //[  ][13][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 0 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[01][11][21][31]

           bricks . Add( new Point ( 2 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 3 , 1 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[01][11][  ][  ]

           bricks . Add( new Point ( 0 , 1 )); //[02][  ][  ][  ]

           bricks . Add( new Point ( 0 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 0 , 0 )); //[00][10][  ][  ]

           bricks . Add( new Point ( 1 , 0 )); //[  ][11][21][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 2 , 1 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            //

           templets = new List < List < Point >> ();

           bricks = new List < Point > ();

           bricks . Add( new Point ( 0 , 0 )); //[00][  ][  ][  ]

           bricks . Add( new Point ( 0 , 1 )); //[01][11][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][12][  ][  ]

           bricks . Add( new Point ( 1 , 2 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           bricks = new List < Point > ();

           bricks . Add( new Point ( 1 , 0 )); //[  ][10][20][  ]

           bricks . Add( new Point ( 2 , 0 )); //[01][11][  ][  ]

           bricks . Add( new Point ( 0 , 1 )); //[  ][  ][  ][  ]

           bricks . Add( new Point ( 1 , 1 )); //[  ][  ][  ][  ]

           templets . Add(bricks);

           brickTemplets . Add(templets);

            ////

            //templets = new List<List<Point>>();

            //bricks = new List<Point>();

            //bricks.Add(new Point(1, 0)); //[  ][10][  ][  ]

            //bricks.Add(new Point(0, 1)); //[01][11][21][  ]

            //bricks.Add(new Point(1, 1)); //[  ][12][  ][  ]

            //bricks.Add(new Point(2, 1)); //[  ][  ][  ][  ]

            //bricks.Add(new Point(1, 2));

            //templets.Add(bricks);

            //brickTemplets.Add(templets);

           #endregion

            base . SetStyle( ControlStyles . OptimizedDoubleBuffer, true );

            base . SetStyle( ControlStyles . Selectable, true );

           afterBrickIndex = ( byte )random . Next(brickTemplets . Count);

           afterFacingIndex = ( byte )random . Next(brickTemplets[afterBrickIndex] . Count);

           timer = new System . Windows . Forms . Timer ();

           timer . Interval = 100 ;

           timer . Tick += new EventHandler (timer_Tick);

           DoChange();

           GameOver();

       }

        void timer_Tick(object sender, EventArgs e)

       {

           BrickOperate( BrickOperates . boMoveDown);

       }

        public void Replay( bool ARecordMode)

       {

            if (threadReview != null )

           {

               threadReview . Abort();

               threadReview = null ;

           }

           reviewing = false ;

           playing = true ;

           recordMode = ARecordMode;

           Clear();

           StepInfos . Clear();

           afterBrickIndex = ( byte )random . Next(brickTemplets . Count);

           afterFacingIndex = ( byte )random . Next(brickTemplets[afterBrickIndex] . Count);

            if (recordMode && ! reviewing)

           {

               StepInfos . Add( new StepInfo ( 0 , 0 , afterBrickIndex, afterFacingIndex));

               lastRecordTime = Environment . TickCount;

           }

           level = 0 ;

           score = 0 ;

            if (progressBar != null ) progressBar . Value = 0 ;

           NextBrick();

           timer . Interval = speeds[level];

           timer . Enabled = true ;

            if (CanFocus) Focus();

       }

        public void NextStep()

       {

            if (stepIndex < 0 ) return ;

            if (stepIndex >= StepInfos . Count) return ;

            switch (StepInfos[stepIndex] . command)

           {

                case 0 :

                   afterBrickIndex = StepInfos[stepIndex] . param1;

                   afterFacingIndex = StepInfos[stepIndex] . param2;

                    break ;

                case 1 :

                   brickIndex = afterBrickIndex;

                   facingIndex = afterFacingIndex;

                   brickPoint . X = colCount / 2 - 1 ;

                   brickPoint . Y = 0 ;

                   afterBrickIndex = StepInfos[stepIndex] . param1;

                   afterFacingIndex = StepInfos[stepIndex] . param2;

                    if (tetrisNext != null && afterBrickIndex != brickIndex)

                       tetrisNext . Update( this );

                    if (tetrisScore != null )

                       tetrisScore . Update( this );

                   DrawCurrent( Graphics . FromImage(backBitmap), false );

                   Invalidate();

                    break ;

                case 2 :

                   BrickOperate(( BrickOperates )StepInfos[stepIndex] . param1);

                   Invalidate();

                    break ;

                case 3 :

                   GameOver();

                   Invalidate();

                    break ;

           }

           stepIndex ++ ;

       }

        public int ReviewSpeed //

       {

            set

           {

               reviewSpeed = value > 0 ? value : 1 ;

           }

            get

           {

                return reviewSpeed;

           }

       }

        private void DoReview()

       {

            while (reviewing)

           {

                if (stepIndex < 0 || stepIndex >= StepInfos . Count)

               {

                   reviewing = false ;

                    break ;

               }

                Thread . Sleep(( int )(( double )StepInfos[stepIndex] . timeTick / reviewSpeed));

                if ( ! reviewing) break ;

               

               Invoke( new EventHandler (DoInvoke));

           }

           Invoke( new EventHandler (DoInvoke));

           threadReview = null ;

       }

        private void DoInvoke( object sender, EventArgs e)

       {

            if (reviewing)

           {

               NextStep();

                if (progressBar != null )

                   progressBar . Value = stepIndex;

           }

            else if (playing)

           {

               timer . Enabled = true ;

                if (CanFocus) Focus();

           }

       }

        /// <summary>

        ///

        /// </summary>

        public void Review()

       {

            if (threadReview != null )

           {

               threadReview . Abort();

               threadReview = null ;

           }

           timer . Enabled = false ;

           reviewing = true ;

           playing = true ;

           Clear();

           level = 0 ;

           score = 0 ;

           lines = 0 ;

           stepIndex = 0 ;

           NextStep();

           NextStep();

            if (progressBar != null )

               progressBar . Maximum = StepInfos . Count;

           threadReview = new Thread ( new ThreadStart (DoReview));

           threadReview . Start();

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="ABitmap"> </param>

        /// <returns> </returns>

        public static bool BitmapGray( Bitmap ABitmap)

       {

            if (ABitmap == null ) return false ;

            byte R = 0 , G = 0 , B = 0 ;

            BitmapData vBitmapData = ABitmap . LockBits(

                new Rectangle ( 0 , 0 , ABitmap . Width, ABitmap . Height),

                ImageLockMode . ReadWrite, PixelFormat . Format32bppRgb);

            int vAddress = ( int )vBitmapData . Scan0;

            int vOffset = vBitmapData . Stride - ABitmap . Width * 4 ;

            int h = ABitmap . Height, w = ABitmap . Width;

            for ( int y = 0 ; y < h; y ++ )

           {

                for ( int x = 0 ; x < w; x ++ )

               {

                    int i = Marshal . ReadInt32(( IntPtr )vAddress);

                   R = ( byte )(i >> 0 & 0xff );

                   G = ( byte )(i >> 8 & 0xff );

                   B = ( byte )(i >> 16 & 0xff );

                   R = ( byte )(( 77 * R + 151 * G + 28 * B) >> 8 );

                   i = ( int )(i & 0xff000000 ) | R << 0 | R << 8 | R << 16 ;

                    Marshal . WriteInt32(( IntPtr )vAddress, i);

                   vAddress += 4 ;

               }

               vAddress += vOffset;

           }

           ABitmap . UnlockBits(vBitmapData);

            return true ;

       }

        public void GameOver()

       {

           BitmapGray(backBitmap);

           playing = false ;

           timer . Enabled = false ;

       }

        public void DoChange()

       {

           Width = brickWidth * colCount;

           Height = brickHeight * rowCount;

           backBitmap = new Bitmap (Width, Height);

            Graphics vGraphics = Graphics . FromImage(backBitmap);

           vGraphics . FillRectangle( new SolidBrush (BackColor), vGraphics . ClipBounds);

           DrawPoints(vGraphics);

           DrawCurrent(vGraphics, false );

           Invalidate();

       }

        public void Clear()

       {

            for ( int i = 0 ; i < colCount; i ++ )

                for ( int j = 0 ; j < rowCount; j ++ )

                   points[i, j] = 0 ;

            Graphics vGraphics = Graphics . FromImage(backBitmap);

           vGraphics . FillRectangle( new SolidBrush (BackColor), vGraphics . ClipBounds);

       }

        public void LoadFromFile( string AFileName)

       {

            if ( ! File . Exists(AFileName)) return ;

            FileStream vFileStream = new FileStream (AFileName,

                FileMode . Open, FileAccess . Read);

           LoadFromStream(vFileStream);

           vFileStream . Close();

       }

        public void LoadFromStream( Stream AStream)

       {

            if (AStream == null ) return ;

            byte [] vBuffer = new byte[ 3 ];

            if (AStream . Read(vBuffer, 0 , vBuffer . Length) != 3 ) return ;

            if (vBuffer[ 0 ] != 116 || vBuffer[ 1 ] != 114 || vBuffer[ 2 ] != 102 ) return ;

            if (colCount != ( byte )AStream . ReadByte()) return ;

            if (rowCount != ( byte )AStream . ReadByte()) return ;

            if (threadReview != null )

           {

               threadReview . Abort(); //

               threadReview = null ;

           }

           timer . Enabled = false ;

           playing = false ;

           reviewing = false ;

           brickTemplets . Clear();

            int vTempletsCount = AStream . ReadByte();

            for ( int i = 0 ; i < vTempletsCount; i ++ )

           {

                List < List < Point >> templets = new List < List < Point >> ();

                int vPointsLength = AStream . ReadByte();

                for ( int j = 0 ; j < vPointsLength; j ++ )

               {

                    List < Point > bricks = new List < Point > ();

                    int vPointCount = AStream . ReadByte();

                    for ( int k = 0 ; k < vPointCount; k ++ )

                   {

                        int vData = AStream . ReadByte();

                        if (vData < 0 ) break;

                                                       

                       bricks . Add( new Point (vData & 3 , vData >> 4 & 3 ));

                   }

                   templets . Add(bricks);

               }

               brickTemplets . Add(templets);

           }

           StepInfos . Clear();

           vBuffer = new byte [ sizeof ( int )];

            if (AStream . Read(vBuffer, 0 , vBuffer . Length) != vBuffer . Length) return ;

            int vStepCount = BitConverter . ToInt32(vBuffer, 0 );

            for ( int i = 0 ; i < vStepCount; i ++ )

           {

                StepInfo vStepInfo = new StepInfo ();

               vStepInfo . param1 = ( byte )AStream . ReadByte();

               vBuffer = new byte[ sizeof ( ushort )];

                if (AStream . Read(vBuffer, 0 , vBuffer . Length) != vBuffer . Length) return ;

               vStepInfo . timeTick = ( ushort ) BitConverter . ToInt16(vBuffer, 0 );

                int vData = AStream . ReadByte();

               vStepInfo . command = ( byte )(vData & 3 );

               vStepInfo . param2 = ( byte )(vData >> 4 & 3 );

               StepInfos . Add(vStepInfo);

           }

           Clear();

           Invalidate();

       }

        public void SaveToFile( string AFileName)

       {

            FileStream vFileStream = new FileStream (AFileName,

                FileMode . Create, FileAccess . Write);

           SaveToStream(vFileStream);

           vFileStream . Close();

       }

        public void SaveToStream( Stream AStream)

       {

            if (AStream == null ) return ;

            byte [] vBuffer = Encoding . ASCII . GetBytes( "trf" );

           AStream . Write(vBuffer, 0 , vBuffer . Length); //

           AStream . WriteByte(( byte )colCount);

           AStream . WriteByte(( byte )rowCount);

            byte vByte = ( byte )brickTemplets . Count;

           AStream . WriteByte(vByte);

            foreach ( List < List < Point >> vList in brickTemplets)

           {

               vByte = ( byte )vList . Count;

               AStream . WriteByte(vByte);

                foreach ( List < Point > vPoints in vList)

               {

                   vByte = ( byte )vPoints . Count;

                   AStream . WriteByte(vByte);

                    foreach ( Point vPoint in vPoints)

                   {

                       vByte = ( byte )(vPoint . Y << 4 | vPoint . X);

                       AStream . WriteByte(vByte);

                   }

               }

           }

           AStream . Write( BitConverter . GetBytes(StepInfos . Count), 0 , sizeof ( int ));

            foreach ( StepInfo vStepInfo in StepInfos)

           {

               AStream . WriteByte(vStepInfo . param1);

               AStream . Write( BitConverter . GetBytes(vStepInfo . timeTick), 0 , sizeof ( ushort ));

               vByte = ( byte )(vStepInfo . param2 << 4 | vStepInfo . command);

               AStream . WriteByte(vByte);

           }

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="AGraphics"> </param>

        /// <param name="APoint"> </param>

        /// <param name="ABrick"> </param>

        public void DrawPoint( Graphics AGraphics, Point APoint, byte ABrick)

       {

            if (ImageList == null ) return ;

            if (ImageList . Images . Count <= 0 ) return ;

            if (APoint . X < 0 || APoint . X >= colCount) return ;

            if (APoint . Y < 0 || APoint . Y >= rowCount) return ;

            Rectangle vRectangle = new Rectangle (

               APoint . X * brickWidth, APoint . Y * brickHeight,

               brickWidth, brickHeight);

           AGraphics . FillRectangle( new SolidBrush (BackColor), vRectangle);

            if (ABrick <= 0 ) return ;

           ABrick = ( byte ) Math . Min(ABrick - 1 , ImageList . Images . Count - 1 );

            Image vImage = ImageList . Images[ABrick];

           AGraphics . DrawImage(vImage, vRectangle . Location);

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="AGraphics"> </param>

        public void DrawPoints( Graphics AGraphics)

       {

            if (ImageList == null ) return ;

            if (ImageList . Images . Count <= 0 ) return ;

            for ( int i = 0 ; i < colCount; i ++ )

                for ( int j = 0 ; j < rowCount; j ++ )

                   DrawPoint(AGraphics, new Point (i, j), points[i, j]);

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="AGraphics"> </param>

        /// <param name="AClear"> </param>

        public void DrawCurrent( Graphics AGraphics, bool AClear)

       {

            if (ImageList == null ) return ;

            if (ImageList . Images . Count <= 0 ) return ;

            foreach ( Point vPoint in brickTemplets[brickIndex][facingIndex])

               DrawPoint(AGraphics, new Point (vPoint . X + brickPoint . X,

                   vPoint . Y + brickPoint . Y),

                   AClear ? ( byte ) 0 : ( byte )(brickIndex + 1 ));

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="AGraphics"> </param>

        public void DrawNext( Graphics AGraphics)

       {

            if (AGraphics == null ) return ;

            if (ImageList == null ) return ;

            if (ImageList . Images . Count <= 0 ) return ;

            foreach ( Point vPoint in brickTemplets[afterBrickIndex][afterFacingIndex])

               DrawPoint(AGraphics, new Point (vPoint . X, vPoint . Y),

                   ( byte )(afterBrickIndex + 1 ));

       }

        public void DrawScore( Graphics AGraphics)

       {

            if (AGraphics == null ) return ;

            RectangleF vRectangleF = new Rectangle ( 0 , 0 , brickWidth * 4 , brickHeight);

            StringFormat vStringFormat = new StringFormat ();

           vStringFormat . FormatFlags |= StringFormatFlags . LineLimit;

           vStringFormat . Alignment = StringAlignment . Center;

           AGraphics . DrawString( "Score" , new Font (Font, FontStyle . Bold),

                Brushes . White, vRectangleF, vStringFormat);

           vRectangleF . Offset( 0 , brickHeight);

           AGraphics . DrawString(score . ToString(), Font,

                Brushes . White, vRectangleF, vStringFormat);

           vRectangleF . Offset( 0 , brickHeight);

           AGraphics . DrawString( "Level" , new Font (Font, FontStyle . Bold),

                Brushes . White, vRectangleF, vStringFormat);

           vRectangleF . Offset( 0 , brickHeight);

           AGraphics . DrawString(level . ToString(), Font,

                Brushes . White, vRectangleF, vStringFormat);

           vRectangleF . Offset( 0 , brickHeight);

           AGraphics . DrawString( "Lines" , new Font (Font, FontStyle . Bold),

                Brushes . White, vRectangleF, vStringFormat);

           vRectangleF . Offset( 0 , brickHeight);

           AGraphics . DrawString(lines . ToString(), Font,

                Brushes . White, vRectangleF, vStringFormat);

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="ABrickIndex"> </param>

        /// <param name="AFacingIndex"> </param>

        /// <param name="ABrickPoint"> </param>

        /// <returns> </returns>

        public bool CheckBrick(byte ABrickIndex, byte AFacingIndex, Point ABrickPoint)

       {

            foreach ( Point vPoint in brickTemplets[ABrickIndex][AFacingIndex])

           {

                if (vPoint . X + ABrickPoint . X < 0 ||

                   vPoint . X + ABrickPoint . X >= colCount) return false ;

                if (vPoint . Y + ABrickPoint . Y < 0 ||

                   vPoint . Y + ABrickPoint . Y >= rowCount) return false ;

                if (points[vPoint . X + ABrickPoint . X,

                   vPoint . Y + ABrickPoint . Y] != 0 ) return false ;

           }

            return true ;

       }

        /// <summary>

        ///

        /// </summary>

        public void FreeLine()

       {

            int vFreeCount = 0 ;

            for ( int j = rowCount - 1 ; j >= 0 ; j -- )

           {

                bool vExistsFull = true ; //

                for ( int i = 0 ; i < colCount && vExistsFull; i ++ )

                    if (points[i, j] == 0 )

                       vExistsFull = false ;

                if ( ! vExistsFull) continue ;

               #region

                Graphics vGraphics = Graphics . FromImage(backBitmap);

                Rectangle srcRect = new Rectangle ( 0 , 0 , backBitmap . Width, j * brickHeight);

                Rectangle destRect = srcRect;

               destRect . Offset( 0 , brickHeight);

                Bitmap vBitmap = new Bitmap (srcRect . Width, srcRect . Height);

                Graphics . FromImage(vBitmap) . DrawImage(backBitmap, 0 , 0 );

               vGraphics . DrawImage(vBitmap, destRect, srcRect, GraphicsUnit . Pixel);

               vGraphics . FillRectangle( new SolidBrush (BackColor), 0 , 0 ,

                   backBitmap . Width, brickHeight);

               #endregion

               lines ++ ;

               vFreeCount ++ ;

                for ( int k = j; k >= 0 ; k -- )

               {

                    for ( int i = 0 ; i < colCount; i ++ )

                        if (k == 0 )

                           points[i, k] = 0 ;

                        else points[i, k] = points[i, k - 1 ];

               }

               j ++ ;

           }

           score += scoress[vFreeCount];

            if (vFreeCount > 0 )

           {

               level = Math . Min(lines / 30 , speeds . Length - 1 );

               timer . Interval = speeds[level];

               Invalidate();

           }

            if (tetrisScore != null ) tetrisScore . Update( this );

       }

        /// <summary>

        ///

        /// </summary>

        /// <param name="ABrickOperates"> </param>

        /// <returns> </returns>

        public bool BrickOperate( BrickOperates ABrickOperates)

       {

            byte vFacingIndex = facingIndex;

            Point vBrickPoint = brickPoint;

            switch (ABrickOperates)

           {

                case BrickOperates . boTurnLeft:

                   vFacingIndex = ( byte )((vFacingIndex + 1 ) %

                       brickTemplets[brickIndex] . Count);

                    break ;

                case BrickOperates . boTurnRight:

                   vFacingIndex = ( byte )((brickTemplets[brickIndex] . Count +

                       vFacingIndex - 1 ) % brickTemplets[brickIndex] . Count);

                    break ;

                case BrickOperates . boMoveLeft:

                   vBrickPoint . Offset( - 1 , 0 );

                    break ;

                case BrickOperates . boMoveRight:

                   vBrickPoint . Offset( + 1 , 0 );

                    break ;

                case BrickOperates . boMoveDown:

                   vBrickPoint . Offset( 0 , + 1 );

                    break ;

                case BrickOperates . boMoveBottom:

                   vBrickPoint . Offset( 0 , + 1 );

                    while (CheckBrick(brickIndex, vFacingIndex, vBrickPoint))

                       vBrickPoint . Offset( 0 , + 1 );

                   vBrickPoint . Offset( 0 , - 1 );

                    break ;

           }

            if (CheckBrick(brickIndex, vFacingIndex, vBrickPoint))

           {

                if (playing && recordMode && ! reviewing)

               {

                   StepInfos . Add(new StepInfo ( Environment . TickCount - lastRecordTime,

                        2 , ( byte )ABrickOperates, 0 ));

                   lastRecordTime = Environment . TickCount;

               }

               

                Graphics vGraphics = Graphics . FromImage(backBitmap);

               DrawCurrent(vGraphics, true );

               facingIndex = vFacingIndex;

               brickPoint = vBrickPoint;

               DrawCurrent(vGraphics, false );

                if (ABrickOperates == BrickOperates . boMoveBottom)

                   Downfall();

                else Invalidate();

           }

            else if (ABrickOperates == BrickOperates . boMoveDown)

           {

                if (playing && recordMode && ! reviewing)

               {

                   StepInfos . Add( new StepInfo ( Environment . TickCount - lastRecordTime,

                        2 , ( byte )ABrickOperates, 0 ));

                   lastRecordTime = Environment . TickCount;

               }

               Downfall();

           }

            return true ;

       }

        /// <summary>

        ///

        /// </summary>

        private void NextBrick()

       {

           brickIndex = afterBrickIndex;

           facingIndex = afterFacingIndex;

           brickPoint . X = colCount / 2 - 1 ;

           brickPoint . Y = 0 ;

           afterBrickIndex = ( byte )random . Next(brickTemplets . Count);

           afterFacingIndex = ( byte )random . Next(brickTemplets[afterBrickIndex] . Count);

            if (playing && recordMode && ! reviewing)

           {

               StepInfos . Add(new StepInfo ( 0 , 1 , afterBrickIndex, afterFacingIndex));

               lastRecordTime = Environment . TickCount;

           }

            if (tetrisNext != null && afterBrickIndex != brickIndex)

               tetrisNext . Update( this );

           DrawCurrent( Graphics . FromImage(backBitmap), false );

            if ( ! CheckBrick(brickIndex, facingIndex, brickPoint))

           {

                if (playing && recordMode && ! reviewing)

               {

                   StepInfos . Add( new StepInfo ( 0 , 3 , 0 , 0 ));

                   lastRecordTime = Environment . TickCount;

               }

               GameOver();

           }

           Invalidate();

       }

        /// <summary>

        ///

        /// </summary>

        private void Downfall()

       {

           foreach ( Point vPoint in brickTemplets[brickIndex][facingIndex])

               points[vPoint . X + brickPoint . X,

                   vPoint . Y + brickPoint . Y] = (byte)(brickIndex + 1 );

           FreeLine();

            if (playing && ! reviewing) NextBrick();

       }

        private void ImageListRecreateHandle(object sender, EventArgs e)

       {

           DoChange();

       }

        private void DetachImageList( object sender, EventArgs e)

       {

           ImageList = null ;

       }

        public ImageList ImageList

       {

            get

           {

                return imageList;

           }

            set

           {

                if ( value != imageList)

               {

                    EventHandler handler = new EventHandler (ImageListRecreateHandle);

                    EventHandler handler2 = new EventHandler (DetachImageList);

                    if (imageList != null )

                   {

                       imageList . RecreateHandle -= handler;

                       imageList . Disposed -= handler2;

                   }

                   imageList = value ;

                    if ( value != null )

                   {

                       brickWidth = ImageList . ImageSize . Width;

                       brickHeight = ImageList . ImageSize . Height;

                       DoChange();

                        if ( ! playing && ! reviewing) GameOver();

                        if (tetrisNext != null )

                       {

                           tetrisNext . BackColor = BackColor;

                           tetrisNext . SetSize(brickWidth * 4 , brickHeight * 4 );

                           tetrisNext . Update( this );

                       }

                        value . RecreateHandle += handler;

                        value . Disposed += handler2;

                   }

               }

           }

       }

        private void DetachTetrisNext( object sender, EventArgs e)

       {

           TetrisNext = null ;

       }

        public TetrisNext TetrisNext

       {

            get

           {

                return tetrisNext;

           }

            set

           {

                if ( value != tetrisNext)

               {

                    EventHandler handler = new EventHandler (DetachTetrisNext);

                    if (tetrisNext != null ) tetrisNext . Disposed -= handler;

                   tetrisNext = value ;

                    if ( value != null )

                   {

                        value . SetSize( 4 * brickWidth, 4 * brickHeight);

                        value . Update( this );

                        value . Disposed += handler;

                   }

               }

           }

       }

        private void DetachTetrisScore( object sender, EventArgs e)

       {

           TetrisScore = null ;

       }

        public TetrisScore TetrisScore

       {

            get

           {

                return tetrisScore;

           }

            set

           {

                if (value != tetrisScore)

               {

                    EventHandler handler = new EventHandler (DetachTetrisScore);

                   if (tetrisScore != null ) tetrisScore . Disposed -= handler;

                   tetrisScore = value;

                    if ( value != null )

                   {

                        value . SetSize( 4 * brickWidth, 6 * brickHeight);

                        value . Update( this );

                        value . Disposed += handler;

                   }

               }

           }

       }

        private void DetachProgressBar( object sender, EventArgs e)

       {

           progressBar = null ;

       }

        public ProgressBar ProgressBar

       {

            get

           {

                return progressBar;

           }

            set

           {

                if ( value != progressBar)

               {

                    EventHandler handler = new EventHandler (DetachProgressBar);

                    if (progressBar != null ) progressBar . Disposed -= handler;

                   progressBar = value ;

                    if ( value != null )

                   {

                       progressBar . Minimum = 0 ;

                       progressBar . Maximum = StepInfos . Count;

                       progressBar . Value = stepIndex < 0 ? 0 : stepIndex;

                       value . Disposed += handler;

                   }

               }

           }

       }

        protected override void OnPaint( PaintEventArgs e)

       {

            base . OnPaint(e);

            if (backBitmap != null ) e . Graphics . DrawImage(backBitmap, 0 , 0 );

       }

        protected override bool IsInputKey( Keys keydata)

       {

            return (keydata == Keys . Down) || (keydata == Keys . Up) ||

               (keydata == Keys . Left) || (keydata == Keys . Right) ||

               (keydata == Keys . Escape) || base . IsInputKey(keydata);

       }

        protected override void OnMouseDown( MouseEventArgs e)

       {

            base . OnMouseDown(e);

            if (CanFocus) Focus();

       }

        protected override void Dispose(bool disposing)

       {

            if (threadReview != null ) threadReview . Abort();

            base . Dispose(disposing);

       }

        protected override void OnKeyDown( KeyEventArgs e)

       {

            base . OnKeyDown(e);

            if ( ! playing || reviewing) return ;

            switch (e . KeyCode)

           {

                case Keys . A: //

                case Keys . Left:

                   BrickOperate( BrickOperates . boMoveLeft);

                    break ;

                case Keys . D: //

                case Keys . Right:

                   BrickOperate( BrickOperates . boMoveRight);

                    break ;

                case Keys . W: //

                case Keys . Up:

                   BrickOperate( BrickOperates . boTurnLeft);

                    break ;

                case Keys . J: //

                   BrickOperate( BrickOperates . boTurnRight);

                    break ;

                case Keys . Down: //

                case Keys . S:

                   BrickOperate( BrickOperates . boMoveDown);

                    break ;

                case Keys . Enter: //

                case Keys . Space:

                case Keys . End:

                   BrickOperate( BrickOperates . boMoveBottom);

                    break ;

           }

       }

   }

    public class TetrisNext : Control

   {

        public TetrisNext()

       {

           BackColor = Color . Black;

            base . SetStyle( ControlStyles . OptimizedDoubleBuffer, true );

       }

        private Bitmap backBitmap;

        public void Clear()

       {

            Graphics vGraphics = Graphics . FromImage(backBitmap);

           vGraphics . FillRectangle( new SolidBrush (BackColor), vGraphics . ClipBounds);

       }

        public void Update( TetrisControl ATetrisControl)

       {

            if (ATetrisControl == null ) return ;

           Clear();

           ATetrisControl . DrawNext( Graphics . FromImage(backBitmap));

           Invalidate();

       }

        public void SetSize( int AWidth, int AHeight)

       {

           Width = AWidth;

           Height = AHeight;

           backBitmap = new Bitmap (AWidth, AHeight);

       }

        protected override void OnPaint( PaintEventArgs e)

       {

            base . OnPaint(e);

            if (backBitmap != null ) e . Graphics . DrawImage(backBitmap, 0 , 0 );

       }

   }

    public class TetrisScore : Control

   {

        private Bitmap backBitmap;

        public TetrisScore()

       {

           BackColor = Color . Black;

           base . SetStyle( ControlStyles . OptimizedDoubleBuffer, true );

       }

        public void Clear()

       {

            Graphics vGraphics = Graphics . FromImage(backBitmap);

           vGraphics . FillRectangle(new SolidBrush (BackColor), vGraphics . ClipBounds);

       }

        public void Update( TetrisControl ATetrisControl)

       {

            if (ATetrisControl == null ) return ;

           Clear();

           ATetrisControl . DrawScore( Graphics . FromImage(backBitmap));

           Invalidate();

       }

        public void SetSize( int AWidth, int AHeight)

       {

           Width = AWidth;

           Height = AHeight;

           backBitmap = new Bitmap (AWidth, AHeight);

       }

        protected override void OnPaint( PaintEventArgs e)

       {

            base . OnPaint(e);

            if (backBitmap != null ) e . Graphics . DrawImage(backBitmap, 0 , 0 );

       }

   }

}