IGRODELOFF

Brave new world

Feb 26th, 2026 (edited)
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 16.60 KB | Gaming | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. namespace SimpleGameMap
  6. {
  7.     internal struct Record
  8.     {
  9.         public int Width;
  10.         public int Height;
  11.         public int TreasureCount;
  12.         public TimeSpan Time;
  13.     }
  14.  
  15.     internal class Game
  16.     {
  17.         private const char Wall = '#';
  18.         private const char Floor = '.';
  19.         private const char Treasure = 'T';
  20.         private const char Player = '@';
  21.  
  22.         private const char BorderTopLeft = '+';
  23.         private const char BorderTopRight = '+';
  24.         private const char BorderBottomLeft = '+';
  25.         private const char BorderBottomRight = '+';
  26.         private const char BorderHorizontal = '-';
  27.         private const char BorderVertical = '|';
  28.  
  29.         private char[,] _map;
  30.         private int _playerY;
  31.         private int _playerX;
  32.         private int _score;
  33.         private int _totalTreasures;
  34.         private readonly int _height;
  35.         private readonly int _width;
  36.         private readonly int _treasureCount;
  37.  
  38.         private DateTime _startTime;
  39.         public TimeSpan PlayTime { get; private set; }
  40.  
  41.         private int MapRows => _map.GetLength(0);
  42.         private int MapCols => _map.GetLength(1);
  43.  
  44.         private const int InfoLines = 3;
  45.         private int TotalDrawLines => MapRows + 2 + InfoLines;
  46.  
  47.         private readonly Random _random = new Random();
  48.  
  49.         public Game(int height, int width, int treasureCount)
  50.         {
  51.             _height = height;
  52.             _width = width;
  53.             _treasureCount = treasureCount;
  54.             InitializeMap();
  55.             SpawnPlayer();
  56.             PlaceTreasures();
  57.             _score = 0;
  58.         }
  59.  
  60.         public bool Run()
  61.         {
  62.             Console.CursorVisible = false;
  63.             Console.Clear();
  64.             _startTime = DateTime.Now;
  65.             bool isRunning = true;
  66.             bool victory = false;
  67.  
  68.             while (isRunning == true)
  69.             {
  70.                 DrawMap();
  71.                 ConsoleKeyInfo keyInfo = Console.ReadKey(true);
  72.  
  73.                 if (keyInfo.Key == ConsoleKey.Escape)
  74.                 {
  75.                     var menuResult = ShowPauseMenu();
  76.                     if (menuResult == PauseMenuResult.ExitToMainMenu)
  77.                     {
  78.                         isRunning = false;
  79.                     }
  80.                 }
  81.                 else
  82.                 {
  83.                     HandleInput(keyInfo);
  84.                     if (_score == _totalTreasures)
  85.                     {
  86.                         victory = true;
  87.                         isRunning = false;
  88.                     }
  89.                 }
  90.             }
  91.  
  92.             PlayTime = DateTime.Now - _startTime;
  93.  
  94.             if (victory == true)
  95.             {
  96.                 ShowVictory();
  97.                 return true;
  98.             }
  99.             else
  100.             {
  101.                 ShowGameInterrupted();
  102.                 Console.CursorVisible = true;
  103.                 return false;
  104.             }
  105.         }
  106.  
  107.         private void InitializeMap()
  108.         {
  109.             _map = new char[_height, _width];
  110.             for (int y = 0; y < _height; y++)
  111.                 for (int x = 0; x < _width; x++)
  112.                     _map[y, x] = Wall;
  113.  
  114.             GenerateMaze();
  115.         }
  116.  
  117.         private void GenerateMaze()
  118.         {
  119.             int startY = _random.Next(1, _height - 1);
  120.             int startX = _random.Next(1, _width - 1);
  121.             _map[startY, startX] = Floor;
  122.  
  123.             var frontiers = new List<(int y, int x)>();
  124.             AddFrontiers(startY, startX, frontiers);
  125.  
  126.             while (frontiers.Count > 0)
  127.             {
  128.                 int index = _random.Next(frontiers.Count);
  129.                 var (fy, fx) = frontiers[index];
  130.                 frontiers.RemoveAt(index);
  131.  
  132.                 int passageCount = 0;
  133.                 int[] dy = { -1, 1, 0, 0 };
  134.                 int[] dx = { 0, 0, -1, 1 };
  135.  
  136.                 foreach (var dir in new[] { 0, 1, 2, 3 })
  137.                 {
  138.                     int ny = fy + dy[dir];
  139.                     int nx = fx + dx[dir];
  140.                     if (ny >= 0 && ny < _height && nx >= 0 && nx < _width && _map[ny, nx] == Floor)
  141.                         passageCount++;
  142.                 }
  143.  
  144.                 if (passageCount == 1)
  145.                 {
  146.                     _map[fy, fx] = Floor;
  147.                     AddFrontiers(fy, fx, frontiers);
  148.                 }
  149.             }
  150.         }
  151.  
  152.         private void AddFrontiers(int y, int x, List<(int, int)> frontiers)
  153.         {
  154.             int[] dy = { -1, 1, 0, 0 };
  155.             int[] dx = { 0, 0, -1, 1 };
  156.  
  157.             for (int d = 0; d < 4; d++)
  158.             {
  159.                 int ny = y + dy[d];
  160.                 int nx = x + dx[d];
  161.                 if (ny >= 0 && ny < _height && nx >= 0 && nx < _width && _map[ny, nx] == Wall)
  162.                 {
  163.                     if (frontiers.Contains((ny, nx)) == false)
  164.                         frontiers.Add((ny, nx));
  165.                 }
  166.             }
  167.         }
  168.  
  169.         private List<(int y, int x)> GetFreeCells(int excludeY = -1, int excludeX = -1)
  170.         {
  171.             var free = new List<(int, int)>();
  172.             for (int y = 0; y < _height; y++)
  173.                 for (int x = 0; x < _width; x++)
  174.                     if (_map[y, x] != Wall && (y == excludeY && x == excludeX) == false)
  175.                         free.Add((y, x));
  176.             return free;
  177.         }
  178.  
  179.         private void SpawnPlayer()
  180.         {
  181.             var free = GetFreeCells();
  182.             if (free.Count == 0)
  183.             {
  184.                 _playerY = 1;
  185.                 _playerX = 1;
  186.                 return;
  187.             }
  188.             int index = _random.Next(free.Count);
  189.             (_playerY, _playerX) = free[index];
  190.         }
  191.  
  192.         private void PlaceTreasures()
  193.         {
  194.             var free = GetFreeCells(_playerY, _playerX);
  195.             int treasuresToPlace = _treasureCount;
  196.             if (treasuresToPlace > free.Count)
  197.                 treasuresToPlace = free.Count;
  198.  
  199.             for (int i = 0; i < free.Count; i++)
  200.             {
  201.                 int j = _random.Next(i, free.Count);
  202.                 var temp = free[i];
  203.                 free[i] = free[j];
  204.                 free[j] = temp;
  205.             }
  206.  
  207.             for (int i = 0; i < treasuresToPlace; i++)
  208.             {
  209.                 var (y, x) = free[i];
  210.                 _map[y, x] = Treasure;
  211.             }
  212.  
  213.             _totalTreasures = treasuresToPlace;
  214.         }
  215.  
  216.         private void ClearLines(int lineCount, int startY = 0)
  217.         {
  218.             int width = Console.WindowWidth;
  219.             for (int i = 0; i < lineCount; i++)
  220.             {
  221.                 Console.SetCursorPosition(0, startY + i);
  222.                 Console.Write(new string(' ', width));
  223.             }
  224.         }
  225.  
  226.         private void DrawMap()
  227.         {
  228.             int mapWidth = MapCols + 2;
  229.             int startX = (Console.WindowWidth - mapWidth) / 2;
  230.             if (startX < 0) startX = 0;
  231.  
  232.             ClearLines(TotalDrawLines);
  233.  
  234.             Console.SetCursorPosition(startX, 0);
  235.             Console.Write(BorderTopLeft);
  236.             Console.Write(new string(BorderHorizontal, MapCols));
  237.             Console.Write(BorderTopRight);
  238.  
  239.             for (int y = 0; y < MapRows; y++)
  240.             {
  241.                 Console.SetCursorPosition(startX, y + 1);
  242.                 Console.Write(BorderVertical);
  243.                 for (int x = 0; x < MapCols; x++)
  244.                 {
  245.                     if (y == _playerY && x == _playerX)
  246.                         Console.Write(Player);
  247.                     else
  248.                         Console.Write(_map[y, x]);
  249.                 }
  250.                 Console.Write(BorderVertical);
  251.             }
  252.  
  253.             int bottomLine = MapRows + 1;
  254.             Console.SetCursorPosition(startX, bottomLine);
  255.             Console.Write(BorderBottomLeft);
  256.             Console.Write(new string(BorderHorizontal, MapCols));
  257.             Console.Write(BorderBottomRight);
  258.  
  259.             int infoLine = bottomLine + 1;
  260.             string scoreText = $"Счёт: {_score}  Осталось сокровищ: {_totalTreasures - _score}";
  261.             string helpText = "Стрелки - движение, Esc - меню";
  262.  
  263.             Console.SetCursorPosition(startX, infoLine);
  264.             Console.Write(scoreText.PadRight(mapWidth));
  265.  
  266.             Console.SetCursorPosition(startX, infoLine + 1);
  267.             Console.Write(helpText.PadRight(mapWidth));
  268.         }
  269.  
  270.         private void HandleInput(ConsoleKeyInfo keyInfo)
  271.         {
  272.             int newY = _playerY;
  273.             int newX = _playerX;
  274.  
  275.             switch (keyInfo.Key)
  276.             {
  277.                 case ConsoleKey.UpArrow: newY--; break;
  278.                 case ConsoleKey.DownArrow: newY++; break;
  279.                 case ConsoleKey.LeftArrow: newX--; break;
  280.                 case ConsoleKey.RightArrow: newX++; break;
  281.                 default: return;
  282.             }
  283.  
  284.             if (newY >= 0 && newY < MapRows &&
  285.                 newX >= 0 && newX < MapCols &&
  286.                 _map[newY, newX] != Wall)
  287.             {
  288.                 if (_map[newY, newX] == Treasure)
  289.                 {
  290.                     _score++;
  291.                     _map[newY, newX] = Floor;
  292.                 }
  293.  
  294.                 _playerY = newY;
  295.                 _playerX = newX;
  296.             }
  297.         }
  298.  
  299.         private PauseMenuResult ShowPauseMenu()
  300.         {
  301.             int menuWidth = 30;
  302.             int menuHeight = 8;
  303.             int startX = (Console.WindowWidth - menuWidth) / 2;
  304.             int startY = (Console.WindowHeight - menuHeight) / 2;
  305.  
  306.             Console.Clear();
  307.             DrawFrame(startX, startY, menuWidth, menuHeight);
  308.  
  309.             string title = "МЕНЮ";
  310.             Console.SetCursorPosition(startX + (menuWidth - title.Length) / 2, startY + 1);
  311.             Console.Write(title);
  312.  
  313.             string continueText = "1. Продолжить";
  314.             string exitToMainText = "2. Выйти в главное меню";
  315.             string escHint = "Esc - вернуться в игру";
  316.  
  317.             Console.SetCursorPosition(startX + (menuWidth - continueText.Length) / 2, startY + 3);
  318.             Console.Write(continueText);
  319.             Console.SetCursorPosition(startX + (menuWidth - exitToMainText.Length) / 2, startY + 4);
  320.             Console.Write(exitToMainText);
  321.             Console.SetCursorPosition(startX + (menuWidth - escHint.Length) / 2, startY + 6);
  322.             Console.Write(escHint);
  323.  
  324.             bool waiting = true;
  325.             PauseMenuResult result = PauseMenuResult.Continue;
  326.  
  327.             while (waiting == true)
  328.             {
  329.                 ConsoleKeyInfo key = Console.ReadKey(true);
  330.                 if (key.Key == ConsoleKey.D1 || key.Key == ConsoleKey.NumPad1 || key.Key == ConsoleKey.Escape)
  331.                 {
  332.                     result = PauseMenuResult.Continue;
  333.                     waiting = false;
  334.                 }
  335.                 else if (key.Key == ConsoleKey.D2 || key.Key == ConsoleKey.NumPad2)
  336.                 {
  337.                     result = PauseMenuResult.ExitToMainMenu;
  338.                     waiting = false;
  339.                 }
  340.             }
  341.  
  342.             Console.Clear();
  343.             return result;
  344.         }
  345.  
  346.         private void ShowVictory()
  347.         {
  348.             Console.Clear();
  349.  
  350.             int menuWidth = 40;
  351.             int menuHeight = 10;
  352.             int startX = (Console.WindowWidth - menuWidth) / 2;
  353.             int startY = (Console.WindowHeight - menuHeight) / 2;
  354.  
  355.             DrawFrame(startX, startY, menuWidth, menuHeight);
  356.  
  357.             string title = "ПОБЕДА!";
  358.             Console.SetCursorPosition(startX + (menuWidth - title.Length) / 2, startY + 1);
  359.             Console.Write(title);
  360.  
  361.             string info1 = $"Размер карты: {_width} x {_height}";
  362.             string info2 = $"Сокровищ собрано: {_score} из {_totalTreasures}";
  363.             string info3 = $"Время: {PlayTime:mm\\:ss}";
  364.  
  365.             Console.SetCursorPosition(startX + (menuWidth - info1.Length) / 2, startY + 3);
  366.             Console.Write(info1);
  367.             Console.SetCursorPosition(startX + (menuWidth - info2.Length) / 2, startY + 4);
  368.             Console.Write(info2);
  369.             Console.SetCursorPosition(startX + (menuWidth - info3.Length) / 2, startY + 5);
  370.             Console.Write(info3);
  371.  
  372.             string continueText = "Нажмите любую клавишу для продолжения...";
  373.             Console.SetCursorPosition(startX + (menuWidth - continueText.Length) / 2, startY + 7);
  374.             Console.Write(continueText);
  375.  
  376.             Console.ReadKey(true);
  377.             Console.Clear();
  378.         }
  379.  
  380.         private void ShowGameInterrupted()
  381.         {
  382.             Console.Clear();
  383.  
  384.             int menuWidth = 40;
  385.             int menuHeight = 8;
  386.             int startX = (Console.WindowWidth - menuWidth) / 2;
  387.             int startY = (Console.WindowHeight - menuHeight) / 2;
  388.  
  389.             DrawFrame(startX, startY, menuWidth, menuHeight);
  390.  
  391.             string title = "ИГРА ПРЕРВАНА";
  392.             Console.SetCursorPosition(startX + (menuWidth - title.Length) / 2, startY + 1);
  393.             Console.Write(title);
  394.  
  395.             string scoreText = $"Ваш счёт: {_score}";
  396.             Console.SetCursorPosition(startX + (menuWidth - scoreText.Length) / 2, startY + 3);
  397.             Console.Write(scoreText);
  398.  
  399.             string continueText = "Нажмите любую клавишу для возврата...";
  400.             Console.SetCursorPosition(startX + (menuWidth - continueText.Length) / 2, startY + 5);
  401.             Console.Write(continueText);
  402.  
  403.             Console.ReadKey(true);
  404.         }
  405.  
  406.         private void DrawFrame(int left, int top, int width, int height)
  407.         {
  408.             Console.SetCursorPosition(left, top);
  409.             Console.Write('┌' + new string('─', width - 2) + '┐');
  410.  
  411.             for (int i = 1; i < height - 1; i++)
  412.             {
  413.                 Console.SetCursorPosition(left, top + i);
  414.                 Console.Write('│' + new string(' ', width - 2) + '│');
  415.             }
  416.  
  417.             Console.SetCursorPosition(left, top + height - 1);
  418.             Console.Write('└' + new string('─', width - 2) + '┘');
  419.         }
  420.  
  421.         private enum PauseMenuResult
  422.         {
  423.             Continue,
  424.             ExitToMainMenu
  425.         }
  426.     }
  427.  
  428.     internal static class Program
  429.     {
  430.         private static List<Record> _records = new List<Record>();
  431.  
  432.         private static void Main()
  433.         {
  434.             Console.OutputEncoding = System.Text.Encoding.UTF8;
  435.             bool exitProgram = false;
  436.  
  437.             while (exitProgram == false)
  438.             {
  439.                 Console.Clear();
  440.                 int menuWidth = 30;
  441.                 int menuHeight = 7;
  442.                 int startX = (Console.WindowWidth - menuWidth) / 2;
  443.                 int startY = (Console.WindowHeight - menuHeight) / 2;
  444.  
  445.                 DrawFrame(startX, startY, menuWidth, menuHeight);
  446.  
  447.                 string title = "ГЛАВНОЕ МЕНЮ";
  448.                 Console.SetCursorPosition(startX + (menuWidth - title.Length) / 2, startY + 1);
  449.                 Console.Write(title);
  450.  
  451.                 string newGameText = "1. Новая игра";
  452.                 string recordsText = "2. История побед";
  453.                 string exitText = "3. Выход";
  454.  
  455.                 Console.SetCursorPosition(startX + (menuWidth - newGameText.Length) / 2, startY + 3);
  456.                 Console.Write(newGameText);
  457.                 Console.SetCursorPosition(startX + (menuWidth - recordsText.Length) / 2, startY + 4);
  458.                 Console.Write(recordsText);
  459.                 Console.SetCursorPosition(startX + (menuWidth - exitText.Length) / 2, startY + 5);
  460.                 Console.Write(exitText);
  461.  
  462.                 ConsoleKeyInfo key = Console.ReadKey(true);
  463.                 switch (key.KeyChar)
  464.                 {
  465.                     case '1':
  466.                         StartNewGame();
  467.                         break;
  468.                     case '2':
  469.                         ShowRecords();
  470.                         break;
  471.                     case '3':
  472.                         exitProgram = true;
  473.                         break;
  474.                 }
  475.                 Console.Clear();
  476.             }
  477.         }
  478.  
  479.         private static int GetIntFromUser(string prompt, int min, int max)
  480.         {
  481.             int result = 0;
  482.             bool valid = false;
  483.  
  484.             while (valid == false)
  485.             {
  486.                 Console.Clear();
  487.  
  488.                 int menuWidth = 50;
  489.                 int menuHeight = 7;
  490.                 int startX = (Console.WindowWidth - menuWidth) / 2;
  491.                 int startY = (Console.WindowHeight - menuHeight) / 2;
  492.  
  493.                 DrawFrame(startX, startY, menuWidth, menuHeight);
  494.  
  495.                 string title = "ВВОД ПАРАМЕТРА";
  496.                 Console.SetCursorPosition(startX + (menuWidth - title.Length) / 2, startY + 1);
  497.                 Console.Write(title);
  498.  
  499.                 string fullPrompt = $"{prompt} (от {min} до {max}):";
  500.                 Console.SetCursorPosition(startX + (menuWidth - fullPrompt.Length) / 2, startY + 3);
  501.                 Console.Write(fullPrompt);
  502.  
  503.                 Console.SetCursorPosition(startX + 2, startY + 5);
  504.                 Console.Write(new string(' ', menuWidth - 4));
  505.                 Console.SetCursorPosition(startX + 2, startY + 5);
  506.                 Console.CursorVisible = true;
  507.                 string input = Console.ReadLine();
  508.                 Console.CursorVisible = false;
  509.  
  510.                 if (int.TryParse(input, out result) == true && result >= min && result <= max)
  511.                 {
  512.                     valid = true;
  513.                 }
  514.                 else
  515.                 {
  516.                     Console.SetCursorPosition(startX + 2, startY + 6);
  517.                     Console.Write("Ошибка! Нажмите любую клавишу...".PadRight(menuWidth - 4));
  518.                     Console.ReadKey(true);
  519.                 }
  520.             }
  521.  
  522.             return result;
  523.         }
  524.  
  525.         private static void StartNewGame()
  526.         {
  527.             int width = GetIntFromUser("Введите ширину карты", 5, Console.WindowWidth - 2);
  528.             int height = GetIntFromUser("Введите высоту карты", 5, Console.WindowHeight - 5);
  529.             int maxTreasures = (height - 2) * (width - 2) / 2;
  530.             int treasureCount = GetIntFromUser("Введите количество сокровищ", 1, maxTreasures);
  531.  
  532.             Game game = new Game(height, width, treasureCount);
  533.             bool victory = game.Run();
  534.             if (victory == true)
  535.             {
  536.                 Record rec = new Record
  537.                 {
  538.                     Width = width,
  539.                     Height = height,
  540.                     TreasureCount = treasureCount,
  541.                     Time = game.PlayTime
  542.                 };
  543.                 _records.Add(rec);
  544.                 ShowRecords();
  545.             }
  546.         }
  547.  
  548.         private static void ShowRecords()
  549.         {
  550.             Console.Clear();
  551.             int menuWidth = 50;
  552.             int menuHeight = Math.Max(10, _records.Count + 5);
  553.             int startX = (Console.WindowWidth - menuWidth) / 2;
  554.             int startY = (Console.WindowHeight - menuHeight) / 2;
  555.  
  556.             DrawFrame(startX, startY, menuWidth, menuHeight);
  557.  
  558.             string title = "ИСТОРИЯ ПОБЕД";
  559.             Console.SetCursorPosition(startX + (menuWidth - title.Length) / 2, startY + 1);
  560.             Console.Write(title);
  561.  
  562.             if (_records.Count == 0)
  563.             {
  564.                 string noRecords = "Пока нет записей";
  565.                 Console.SetCursorPosition(startX + (menuWidth - noRecords.Length) / 2, startY + 3);
  566.                 Console.Write(noRecords);
  567.             }
  568.             else
  569.             {
  570.                 string header = "Ширина Высота Сокровища Время";
  571.                 Console.SetCursorPosition(startX + (menuWidth - header.Length) / 2, startY + 3);
  572.                 Console.Write(header);
  573.  
  574.                 var sorted = _records.OrderBy(r => r.Time).ToList();
  575.                 for (int i = 0; i < sorted.Count; i++)
  576.                 {
  577.                     var r = sorted[i];
  578.                     string line = $"{r.Width,7} {r.Height,6} {r.TreasureCount,9} {r.Time:mm\\:ss}";
  579.                     Console.SetCursorPosition(startX + (menuWidth - line.Length) / 2, startY + 4 + i);
  580.                     Console.Write(line);
  581.                 }
  582.             }
  583.  
  584.             string backText = "Нажмите любую клавишу для возврата...";
  585.             Console.SetCursorPosition(startX + (menuWidth - backText.Length) / 2, startY + menuHeight - 2);
  586.             Console.Write(backText);
  587.  
  588.             Console.ReadKey(true);
  589.         }
  590.  
  591.         private static void DrawFrame(int left, int top, int width, int height)
  592.         {
  593.             Console.SetCursorPosition(left, top);
  594.             Console.Write('┌' + new string('─', width - 2) + '┐');
  595.  
  596.             for (int i = 1; i < height - 1; i++)
  597.             {
  598.                 Console.SetCursorPosition(left, top + i);
  599.                 Console.Write('│' + new string(' ', width - 2) + '│');
  600.             }
  601.  
  602.             Console.SetCursorPosition(left, top + height - 1);
  603.             Console.Write('└' + new string('─', width - 2) + '┘');
  604.         }
  605.     }
  606. }
Advertisement
Add Comment
Please, Sign In to add comment