Advertisement
TeT91

Tetris source

Jun 4th, 2024 (edited)
521
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 19.56 KB | None | 0 0
  1. // Made by: Kat9_123
  2.  
  3.  
  4.  
  5. using System;
  6. using System.Threading;
  7. using System.Diagnostics;
  8.  
  9. namespace Tetris
  10. {
  11.  
  12.  
  13.     class Program
  14.     {
  15.         // Map / BG
  16.         const int mapSizeX = 10;
  17.         const int mapSizeY = 20;
  18.         static char[,] bg = new char[mapSizeY, mapSizeX];
  19.         // очевидно, что устанавливает размеры поля и массив символов на фоне.
  20.  
  21.  
  22.  
  23.         static int score = 0;
  24.  
  25.         // Hold variables
  26.         const int holdSizeX = 6;
  27.         const int holdSizeY = mapSizeY;
  28.         static int holdIndex = -1;
  29.         static char holdChar;
  30.  
  31.         const int upNextSize = 6;
  32.         // Не понятный блок
  33.         // Разобрался. Holf - это отступ слева, в который можно поместить фигуру в запас. holdIndex - не понятно
  34.  
  35.  
  36.  
  37.         static ConsoleKeyInfo input;
  38.  
  39.  
  40.         // Current info
  41.         static int currentX = 0;
  42.         static int currentY = 0;
  43.         static char currentChar = 'O';
  44.  
  45.         static int currentRot = 0;
  46.         // Вероятно, что это положение или фигуры или одного квадратика
  47.         // currentX - это отступ слева
  48.  
  49.  
  50.         // Block and Bogs        
  51.         static int[] bag;
  52.         static int[] nextBag;
  53.  
  54.         static int bagIndex;
  55.         static int currentIndex;
  56.         // Не понятно что за Bag. Возможно хранилище фигур или сама фигура
  57.  
  58.         // misc
  59.         static int maxTime = 20;
  60.         static int timer = 0;
  61.         static int amount = 0;
  62.         // Это участвует в ускорении фигуры
  63.  
  64.  
  65.         #region Assets
  66.  
  67.  
  68.         /* Possible modification
  69.         readonly static ConsoleColor[] colours =
  70.         {
  71.             ConsoleColor.Red,
  72.             ConsoleColor.Blue,
  73.             ConsoleColor.Green,
  74.             ConsoleColor.Magenta,
  75.             ConsoleColor.Yellow,
  76.             ConsoleColor.White,
  77.             ConsoleColor.Cyan
  78.         };
  79.         */
  80.         readonly static string characters = "OILJSZT"; //Символы из которых состоят фигуры
  81.         readonly static int[,,,] positions = // не понятно
  82.         {
  83.         {
  84.         {{0,0},{1,0},{0,1},{1,1}},
  85.         {{0,0},{1,0},{0,1},{1,1}},
  86.         {{0,0},{1,0},{0,1},{1,1}},
  87.         {{0,0},{1,0},{0,1},{1,1}}
  88.         },
  89.  
  90.         {
  91.         {{2,0},{2,1},{2,2},{2,3}},
  92.         {{0,2},{1,2},{2,2},{3,2}},
  93.         {{1,0},{1,1},{1,2},{1,3}},
  94.         {{0,1},{1,1},{2,1},{3,1}},
  95.         },
  96.         {
  97.         {{1,0},{1,1},{1,2},{2,2}},
  98.         {{1,2},{1,1},{2,1},{3,1}},
  99.         {{1,1},{2,1},{2,2},{2,3}},
  100.         {{2,1},{2,2},{1,2},{0,2}}
  101.         },
  102.  
  103.         {
  104.         {{2,0},{2,1},{2,2},{1,2}},
  105.         {{1,1},{1,2},{2,2},{3,2}},
  106.         {{2,1},{1,1},{1,2},{1,3}},
  107.         {{0,1},{1,1},{2,1},{2,2}}
  108.         },
  109.  
  110.         {
  111.         {{2,1},{1,1},{1,2},{0,2}},
  112.         {{1,0},{1,1},{2,1},{2,2}},
  113.         {{2,1},{1,1},{1,2},{0,2}},
  114.         {{1,0},{1,1},{2,1},{2,2}}
  115.         },
  116.         {
  117.         {{0,1},{1,1},{1,2},{2,2}},
  118.         {{1,0},{1,1},{0,1},{0,2}},
  119.         {{0,1},{1,1},{1,2},{2,2}},
  120.         {{1,0},{1,1},{0,1},{0,2}}
  121.         },
  122.  
  123.         {
  124.         {{0,1},{1,1},{1,0},{2,1}},
  125.         {{1,0},{1,1},{2,1},{1,2}},
  126.         {{0,1},{1,1},{1,2},{2,1}},
  127.         {{1,0},{1,1},{0,1},{1,2}}
  128.         }
  129.         };
  130.         #endregion
  131.         static void Main()
  132.         {
  133.             // Make the console cursor invisible
  134.             Console.CursorVisible = false;
  135.  
  136.             // Title
  137.             Console.Title = "Tetris | By: Kat9_123";
  138.  
  139.             // Start the inputthread to get live inputs
  140.             Thread inputThread = new Thread(Input);
  141.             inputThread.Start();
  142.  
  143.             // Generate bag / current block
  144.             bag = GenerateBag();
  145.             nextBag = GenerateBag();
  146.             NewBlock();
  147.             // Что-то связанное с новой фигурой/сумкой
  148.  
  149.  
  150.  
  151.             // Generate an empty bg
  152.             for (int y = 0; y < mapSizeY; y++)
  153.                 for (int x = 0; x < mapSizeX; x++)
  154.                     bg[y, x] = '-';
  155.             // Создает пустое поле
  156.  
  157.             while (true) //Бесконечный цикл
  158.             {
  159.  
  160.                 // Force block down
  161.                 if (timer >= maxTime)
  162.                 {
  163.                     // If it doesn't collide, just move it down. If it does call BlockDownCollision
  164.                     if (!Collision(currentIndex, bg, currentX, currentY + 1, currentRot)) currentY++;
  165.                     else BlockDownCollision();
  166.  
  167.                     timer = 0;
  168.                 }
  169.                 timer++;
  170.                 // Каким-то образом ускоряет фигуру. Возможно рассчитывается время падения.
  171.  
  172.  
  173.  
  174.                 // INPUT
  175.                 InputHandler(); // Call InputHandler
  176.                 input = new ConsoleKeyInfo(); // Reset input var
  177.  
  178.  
  179.                 // RENDER CURRENT
  180.                 char[,] view = RenderView(); // Render view (Playing field)
  181.  
  182.                 // RENDER HOLD
  183.                 char[,] hold = RenderHold(); // Render hold (the current held block)
  184.  
  185.  
  186.                 //RENDER UP NEXT
  187.                 char[,] next = RenderUpNext(); // Render the next three blocks as an 'up next' feature
  188.  
  189.                 // PRINT VIEW
  190.                 Print(view, hold, next); // Print everything to the screen
  191.  
  192.                 Thread.Sleep(20); // Wait to not overload the processor (I think it's better because it has no impact on game feel)
  193.             }
  194.  
  195.  
  196.         }
  197.  
  198.  
  199.         static void InputHandler()
  200.         {
  201.             switch (input.Key)
  202.             {
  203.                 // Left arrow = move left (if it doesn't collide)
  204.                 case ConsoleKey.A:
  205.                 case ConsoleKey.LeftArrow:
  206.                     if (!Collision(currentIndex, bg, currentX - 1, currentY, currentRot)) currentX -= 1;
  207.                     break;
  208.  
  209.                 // Right arrow = move right (if it doesn't collide)
  210.                 case ConsoleKey.D:
  211.                 case ConsoleKey.RightArrow:
  212.                     if (!Collision(currentIndex, bg, currentX + 1, currentY, currentRot)) currentX += 1;
  213.                     break;
  214.  
  215.                 // Rotate block (if it doesn't collide)
  216.                 case ConsoleKey.W:
  217.                 case ConsoleKey.UpArrow:
  218.                     int newRot = currentRot + 1;
  219.                     if (newRot >= 4) newRot = 0;
  220.                     if (!Collision(currentIndex, bg, currentX, currentY, newRot)) currentRot = newRot;
  221.  
  222.                     break;
  223.  
  224.                 // Move the block instantly down (hard drop)
  225.                 case ConsoleKey.Spacebar:
  226.                     int i = 0;
  227.                     while (true)
  228.                     {
  229.                         i++;
  230.                         if (Collision(currentIndex, bg, currentX, currentY + i, currentRot))
  231.                         {
  232.                             currentY += i - 1;
  233.                             break;
  234.                         }
  235.  
  236.                     }
  237.                     score += i + 1;
  238.                     break;
  239.  
  240.                 // Quit
  241.                 case ConsoleKey.Escape:
  242.                     Environment.Exit(1);
  243.                     break;
  244.  
  245.                 // Hold block
  246.                 case ConsoleKey.Enter:
  247.  
  248.                     // If there isnt a current held block:
  249.                     if (holdIndex == -1)
  250.                     {
  251.                         holdIndex = currentIndex;
  252.                         holdChar = currentChar;
  253.                         NewBlock();
  254.                     }
  255.                     // If there is:
  256.                     else
  257.                     {
  258.                         if (!Collision(holdIndex, bg, currentX, currentY, 0)) // Check for collision
  259.                         {
  260.  
  261.                             // Switch current and hold
  262.                             int c = currentIndex;
  263.                             char ch = currentChar;
  264.                             currentIndex = holdIndex;
  265.                             currentChar = holdChar;
  266.                             holdIndex = c;
  267.                             holdChar = ch;
  268.                         }
  269.  
  270.                     }
  271.                     break;
  272.  
  273.                 // Move down faster
  274.                 case ConsoleKey.S:
  275.                 case ConsoleKey.DownArrow:
  276.                     timer = maxTime;
  277.                     break;
  278.  
  279.                 case ConsoleKey.R:
  280.                     Restart();
  281.                     break;
  282.  
  283.                 default:
  284.                     break;
  285.             }
  286.         }
  287.         static void BlockDownCollision()
  288.         {
  289.  
  290.             // Add blocks from current to background
  291.             for (int i = 0; i < positions.GetLength(2); i++)
  292.             {
  293.                 bg[positions[currentIndex, currentRot, i, 1] + currentY, positions[currentIndex, currentRot, i, 0] + currentX] = currentChar;
  294.             }
  295.  
  296.             // Loop
  297.             while (true)
  298.             {
  299.                 // Check for line
  300.                 int lineY = Line(bg);
  301.  
  302.                 // If a line is detected
  303.                 if (lineY != -1)
  304.                 {
  305.                     ClearLine(lineY);
  306.  
  307.                     continue;
  308.                 }
  309.                 break;
  310.             }
  311.             // New block
  312.             NewBlock();
  313.  
  314.         }
  315.  
  316.  
  317.         static void Restart()
  318.         {
  319.             // Quite messy but it kinda works. Code by: KeremEskicinar
  320.             var applicationPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
  321.             Process.Start(applicationPath);
  322.             Environment.Exit(Environment.ExitCode);
  323.         }
  324.  
  325.         static void ClearLine(int lineY)
  326.         {
  327.             score += 40;
  328.             // Clear said line
  329.             for (int x = 0; x < mapSizeX; x++) bg[lineY, x] = '-';
  330.  
  331.             // Loop through all blocks above line
  332.             for (int y = lineY - 1; y > 0; y--)
  333.             {
  334.                 for (int x = 0; x < mapSizeX; x++)
  335.                 {
  336.                     // Move each character down
  337.                     char character = bg[y, x];
  338.                     if (character != '-')
  339.                     {
  340.                         bg[y, x] = '-';
  341.                         bg[y + 1, x] = character;
  342.                     }
  343.  
  344.                 }
  345.             }
  346.         }
  347.  
  348.         static char[,] RenderView() //Скорее всего обновляет отрисовку экрана
  349.         {
  350.             char[,] view = new char[mapSizeY, mapSizeX];
  351.  
  352.             // Make view equal to bg
  353.             for (int y = 0; y < mapSizeY; y++)
  354.                 for (int x = 0; x < mapSizeX; x++)
  355.                     view[y, x] = bg[y, x];
  356.  
  357.  
  358.  
  359.             // Overlay current
  360.             for (int i = 0; i < positions.GetLength(2); i++)
  361.             {
  362.                 view[positions[currentIndex, currentRot, i, 1] + currentY, positions[currentIndex, currentRot, i, 0] + currentX] = currentChar;
  363.             }
  364.             return view;
  365.         }
  366.  
  367.         static char[,] RenderHold()
  368.         {
  369.             char[,] hold = new char[holdSizeY, holdSizeX];
  370.             // Hold = ' ' array
  371.             for (int y = 0; y < holdSizeY; y++)
  372.                 for (int x = 0; x < holdSizeX; x++)
  373.                     hold[y, x] = ' ';
  374.  
  375.  
  376.             // If there is a held block
  377.             if (holdIndex != -1)
  378.             {
  379.                 // Overlay blocks from hold
  380.                 for (int i = 0; i < positions.GetLength(2); i++)
  381.                 {
  382.                     hold[positions[holdIndex, 0, i, 1] + 1, positions[holdIndex, 0, i, 0] + 1] = holdChar;
  383.                 }
  384.             }
  385.             return hold;
  386.  
  387.             // Hold - это некоторое хранилище запасной фигуры. Если нажать Enter, то фигура поместится в хранилище (слева) и зменится на фигуру их хранилища
  388.             // Собственно - метод орисовывает это хранилище
  389.         }
  390.         static char[,] RenderUpNext()
  391.         {
  392.             // Up next = ' ' array  
  393.             char[,] next = new char[mapSizeY, upNextSize];
  394.             for (int y = 0; y < mapSizeY; y++)
  395.                 for (int x = 0; x < upNextSize; x++)
  396.                     next[y, x] = ' ';
  397.  
  398.  
  399.             int nextBagIndex = 0;
  400.             for (int i = 0; i < 3; i++) // Next 3 blocks
  401.             {
  402.  
  403.                 for (int l = 0; l < positions.GetLength(2); l++)
  404.                 {
  405.                     if (i + bagIndex >= 7) // If we need to acces the next bag
  406.                         next[positions[nextBag[nextBagIndex], 0, l, 1] + 5 * i, positions[nextBag[nextBagIndex], 0, l, 0] + 1] = characters[nextBag[nextBagIndex]];
  407.                     else
  408.                         next[positions[bag[bagIndex + i], 0, l, 1] + 5 * i, positions[bag[bagIndex + i], 0, l, 0] + 1] = characters[bag[bagIndex + i]];
  409.  
  410.  
  411.                 }
  412.                 if (i + bagIndex >= 7) nextBagIndex++;
  413.             }
  414.             return next;
  415.             // Здесь все просто. Этот метод отрисовывает хранилище следующи фигур
  416.  
  417.         }
  418.  
  419.         static void Print(char[,] view, char[,] hold, char[,] next)
  420.         {
  421.             for (int y = 0; y < mapSizeY; y++)
  422.             {
  423.  
  424.                 for (int x = 0; x < holdSizeX + mapSizeX + upNextSize; x++)
  425.                 {
  426.                     char i = ' ';
  427.                     // Add hold + Main View + up next to view (basically dark magic)
  428.                     if (x < holdSizeX) i = hold[y, x];
  429.                     else if (x >= holdSizeX + mapSizeX) i = next[y, x - mapSizeX - upNextSize];
  430.                     else i = view[y, (x - holdSizeX)];
  431.  
  432.                     //Что-то главной отрисовки экрана
  433.  
  434.                     // Colours
  435.                     switch (i)
  436.                     {
  437.                         case 'O':
  438.                             Console.ForegroundColor = ConsoleColor.Red;
  439.                             Console.Write(i);
  440.                             break;
  441.                         case 'I':
  442.                             Console.ForegroundColor = ConsoleColor.Blue;
  443.                             Console.Write(i);
  444.                             break;
  445.  
  446.                         case 'T':
  447.                             Console.ForegroundColor = ConsoleColor.Cyan;
  448.                             Console.Write(i);
  449.                             break;
  450.  
  451.                         case 'S':
  452.                             Console.ForegroundColor = ConsoleColor.DarkMagenta;
  453.                             Console.Write(i);
  454.                             break;
  455.                         case 'Z':
  456.                             Console.ForegroundColor = ConsoleColor.DarkCyan;
  457.                             Console.Write(i);
  458.                             break;
  459.                         case 'L':
  460.                             Console.ForegroundColor = ConsoleColor.Green;
  461.                             Console.Write(i);
  462.                             break;
  463.  
  464.                         case 'J':
  465.                             Console.ForegroundColor = ConsoleColor.DarkCyan;
  466.                             Console.Write(i);
  467.                             break;
  468.                         default:
  469.                             Console.ForegroundColor = ConsoleColor.DarkGray;
  470.                             Console.Write(i);
  471.                             break;
  472.                     }
  473.                     // Даем цвета фигуре
  474.  
  475.  
  476.                 }
  477.                 if (y == 1)
  478.                 {
  479.                     Console.ForegroundColor = ConsoleColor.DarkGray;
  480.                     Console.Write("   " + score);
  481.                 }
  482.                 // Вывод очков
  483.                 Console.WriteLine();
  484.             }
  485.  
  486.             // Reset console cursor position
  487.             Console.SetCursorPosition(0, Console.CursorTop - mapSizeY);
  488.         }
  489.         static int[] GenerateBag()
  490.         {
  491.             // Not my code, source https://stackoverflow.com/questions/108819/best-way-to-randomize-an-array-with-net
  492.             Random random = new Random();
  493.             int n = 7;
  494.             int[] ret = { 0, 1, 2, 3, 4, 5, 6, 7 };
  495.             while (n > 1)
  496.             {
  497.                 int k = random.Next(n--);
  498.                 int temp = ret[n];
  499.                 ret[n] = ret[k];
  500.                 ret[k] = temp;
  501.  
  502.             }
  503.             return ret;
  504.  
  505.             //Случайно перемешиваем какой-то массив. Зачем?
  506.             // Разобрался(кажется).Bag - это хранилище фигур. Когда использовал фигуры из одного массива создается новый массив
  507.  
  508.         }
  509.         static bool Collision(int index, char[,] bg, int x, int y, int rot)
  510.         {
  511.  
  512.             for (int i = 0; i < positions.GetLength(2); i++)
  513.             {
  514.                 // Check if out of bounds
  515.                 if (positions[index, rot, i, 1] + y >= mapSizeY || positions[index, rot, i, 0] + x < 0 || positions[index, rot, i, 0] + x >= mapSizeX)
  516.                 {
  517.                     return true;
  518.                 }
  519.                 // Check if not '-'
  520.                 if (bg[positions[index, rot, i, 1] + y, positions[index, rot, i, 0] + x] != '-')
  521.                 {
  522.                     return true;
  523.                 }
  524.             }
  525.  
  526.             return false;
  527.  
  528.             // Не вникал, но это как-то отслеживает столкновения
  529.         }
  530.  
  531.         static int Line(char[,] bg)
  532.         {
  533.             for (int y = 0; y < mapSizeY; y++)
  534.             {
  535.                 bool i = true;
  536.                 for (int x = 0; x < mapSizeX; x++)
  537.                 {
  538.                     if (bg[y, x] == '-')
  539.                     {
  540.                         i = false;
  541.                     }
  542.                 }
  543.                 if (i) return y;
  544.             }
  545.  
  546.             // If no line return -1
  547.             return -1;
  548.  
  549.             //Скорее всего проверяем собралась ли линия или нет. Если не собралась, то почему возвращаем -1? почему не bool?
  550.         }
  551.  
  552.         static void NewBlock()
  553.         {
  554.             // Check if new bag is necessary
  555.             if (bagIndex >= 7)
  556.             {
  557.                 bagIndex = 0;
  558.                 bag = nextBag;
  559.                 nextBag = GenerateBag();
  560.             }
  561.  
  562.             // Reset everything
  563.             currentY = 0;
  564.             currentX = 4;
  565.             currentChar = characters[bag[bagIndex]];
  566.             currentIndex = bag[bagIndex];
  567.  
  568.             // Check if the next block position collides. If it does its gameover
  569.             if (Collision(currentIndex, bg, currentX, currentY, currentRot) && amount > 0)
  570.             {
  571.                 GameOver();
  572.             }
  573.             bagIndex++;
  574.             amount++;
  575.             // Создает новый блок и отлеживает столкнулся ли он с верхним краем
  576.         }
  577.  
  578.  
  579.         static void GameOver()
  580.         {
  581.             // Possible restart functionality
  582.             Environment.Exit(1);
  583.         }
  584.         static void Input()
  585.         {
  586.             while (true)
  587.             {
  588.                 // Get input
  589.                 input = Console.ReadKey(true);
  590.             }
  591.         }
  592.     }
  593. }
  594.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement