diff --git a/Core/Program.cs b/Core/Program.cs index 778781b..7ada5da 100644 --- a/Core/Program.cs +++ b/Core/Program.cs @@ -10,6 +10,7 @@ class Program static MenuForm snakeSizeMenuForm; static AboutMeForm aboutMeForm; static MathGameForm mathGameForm; + static SnakeForm snakeForm; [STAThread] // Требуется для Windows Forms static void Main() @@ -19,7 +20,7 @@ class Program int sizex = 20; int sizey = 20; - SnakeGame.Level difficulty = 0; + SnakeForm.Level difficulty = 0; Menu sizeMenu = new Menu("Select world size"); sizeMenu.AddOption("Small size (10x10)", () => { sizex = 10; sizey = 10; }); @@ -27,9 +28,9 @@ class Program sizeMenu.AddOption("Big size (40x20)", () => { sizex = 40; sizey = 20; }); Menu difficultyMenu = new Menu("Select difficulty"); - difficultyMenu.AddOption("Easy", () => { difficulty = SnakeGame.Level.Low; }); - difficultyMenu.AddOption("Medium", () => { difficulty = SnakeGame.Level.Medium; }); - difficultyMenu.AddOption("Hard", () => { difficulty = SnakeGame.Level.High; }); + difficultyMenu.AddOption("Easy", () => { difficulty = SnakeForm.Level.Low; }); + difficultyMenu.AddOption("Medium", () => { difficulty = SnakeForm.Level.Medium; }); + difficultyMenu.AddOption("Hard", () => { difficulty = SnakeForm.Level.High; }); Menu mainMenu = new Menu("Select option"); mainMenu.AddOption("Guess answer math game", () => mainMenuForm.SwitchToForm(mathGameForm)); @@ -50,9 +51,8 @@ class Program snakeSizeMenuForm = new MenuForm(sizeMenu, () => { snakeSizeMenuForm.Hide(); - SnakeGame game = new SnakeGame(difficulty, sizex, sizey); - game.start(); - snakeSizeMenuForm.SwitchToForm(mainMenuForm); + snakeForm = new SnakeForm(difficulty, sizex, sizey, mainMenuForm); + snakeForm.Show(); }); aboutMeForm = new AboutMeForm(mainMenuForm); @@ -71,7 +71,7 @@ Website: divan2000.su"; } private static void Exit() { - ExitDialog.Exit(); + Dialogs.Exit(); } private static bool ExitMenu() { diff --git a/GUI/ExitDialog.cs b/GUI/Dialogs.cs similarity index 68% rename from GUI/ExitDialog.cs rename to GUI/Dialogs.cs index 61d1b94..6e98eb8 100644 --- a/GUI/ExitDialog.cs +++ b/GUI/Dialogs.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace ProgLab1.GUI { - public static class ExitDialog + public static class Dialogs { public static bool Exit() { @@ -18,5 +18,11 @@ namespace ProgLab1.GUI } return false; } + + public static bool GameOver(string message) + { + DialogResult result = MessageBox.Show(message, "Игра окончена", MessageBoxButtons.OK); + return result == DialogResult.OK; + } } } diff --git a/GUI/GuessForm.cs b/GUI/GuessForm.cs index bacf220..5c81e74 100644 --- a/GUI/GuessForm.cs +++ b/GUI/GuessForm.cs @@ -1,4 +1,5 @@ -using System; +using laba3.Subprograms; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -79,23 +80,22 @@ namespace ProgLab1.GUI { input.BackColor = SystemColors.Window; double inputNum = double.Parse(input.Text); - Console.WriteLine(Math.Abs(answer - inputNum)); - if (Math.Abs(answer - inputNum) < 0.1) + if (Math.Abs(answer - inputNum) < 0.01) { - + Dialogs.GameOver("Победа!\nВы угадали значение функции!"); + this.Close(); } else { tryes--; - } - - if(tryes <= 0) - { - this.Close(); + tryCount.Text = $"Количество попыток: {tryes}"; + if (tryes <= 0) + { + Dialogs.GameOver($"Попытки кончились :(\nВерный ответ был {answer:F2}"); + this.Close(); + } } } - - tryCount.Text = $"Количество попыток: {tryes}"; } } } diff --git a/GUI/MathGameForm.cs b/GUI/MathGameForm.cs index ea63205..e3d6c26 100644 --- a/GUI/MathGameForm.cs +++ b/GUI/MathGameForm.cs @@ -131,21 +131,21 @@ namespace ProgLab1.GUI game.setArgs(a, b); bool funcValid = game.CheckArgs(); - + if (!funcValid) { error.Text = "Функция не определена при этих аргументах"; } - else { error.Text = ""; + game.ComputeResult(); guessForm.SetAnswer(game.GetResult()); this.Hide(); guessForm.Show(); } } - if (!(isAValid && isBValid)) + else { // Если есть ошибка, подсвечиваем поля if (!isAValid) textBoxA.BackColor = Color.Red; diff --git a/GUI/MenuForm.cs b/GUI/MenuForm.cs index 7f88a38..d190945 100644 --- a/GUI/MenuForm.cs +++ b/GUI/MenuForm.cs @@ -22,7 +22,7 @@ namespace ProgLab1.GUI this.Width = 800; this.Height = 600; AddMenu(consoleMenu); - this.FormClosing += new FormClosingEventHandler((object sender, FormClosingEventArgs e) => { e.Cancel = !ExitDialog.Exit(); }); + this.FormClosing += new FormClosingEventHandler((object sender, FormClosingEventArgs e) => { e.Cancel = !Dialogs.Exit(); }); } public MenuForm(Menu consoleMenu, Action onAny) @@ -32,7 +32,7 @@ namespace ProgLab1.GUI this.Width = 800; this.Height = 600; AddMenu(consoleMenu, onAny); - this.FormClosing += new FormClosingEventHandler((object sender, FormClosingEventArgs e) => { e.Cancel = !ExitDialog.Exit(); }); + this.FormClosing += new FormClosingEventHandler((object sender, FormClosingEventArgs e) => { e.Cancel = !Dialogs.Exit(); }); } public void SwitchToForm(Form form) diff --git a/GUI/SnakeForm.Designer.cs b/GUI/SnakeForm.Designer.cs new file mode 100644 index 0000000..7434fea --- /dev/null +++ b/GUI/SnakeForm.Designer.cs @@ -0,0 +1,39 @@ +namespace ProgLab1.GUI +{ + partial class SnakeForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "SnakeGUI"; + } + + #endregion + } +} \ No newline at end of file diff --git a/GUI/SnakeForm.cs b/GUI/SnakeForm.cs new file mode 100644 index 0000000..31a0737 --- /dev/null +++ b/GUI/SnakeForm.cs @@ -0,0 +1,194 @@ +using laba3.Subprograms; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using static System.Formats.Asn1.AsnWriter; + +namespace ProgLab1.GUI +{ + public partial class SnakeForm : Form + { + private System.Windows.Forms.Timer gameTimer = new System.Windows.Forms.Timer(); + private List snake = new List(); + private Point food = Point.Empty; + private int tileSize = 20; + private string direction = "Right"; + private string nextDirection = "Right"; + private bool isGameOver = false; + private int score = 0; + + private Level level; + private int sizex; + private int sizey; + + private Random rand = new Random(); + + public SnakeForm(Level level, int sizex, int sizey, Form onCloseForm) + { + this.level = level; + this.sizex = sizex; + this.sizey = sizey; + InitializeComponent(); + InitializeGame(); + + this.FormClosing += new FormClosingEventHandler((object sender, FormClosingEventArgs e) => {onCloseForm.Show();}); + } + + private void InitializeGame() + { + this.Text = "Snake Game"; + this.ClientSize = new Size(sizex*tileSize, sizey*tileSize); + this.DoubleBuffered = true; + this.KeyDown += OnKeyDown; + this.Paint += OnPaint; + + gameTimer.Interval = level switch + { + Level.Low => 250, + Level.Medium => 125, + Level.High => 50, + _ => 500, + }; ; + gameTimer.Tick += OnGameTick; + gameTimer.Start(); + + ResetGame(); + } + + private void ResetGame() + { + snake.Clear(); + snake.Add(new Point(2, sizey/2)); // Initial snake head + snake.Add(new Point(1, sizey/2)); // Initial snake body + snake.Add(new Point(0, sizey/2)); // Initial snake tail + direction = "Right"; + nextDirection = "Right"; + isGameOver = false; + SpawnFood(); + } + + private void SpawnFood() + { + int maxX = sizex; + int maxY = sizey; + do + { + food = new Point(rand.Next(0, maxX), rand.Next(0, maxY)); + } while (snake.Contains(food)); + } + + private void OnGameTick(object sender, EventArgs e) + { + if (isGameOver) return; + + // Update direction + direction = nextDirection; + + // Calculate new head position + Point newHead = snake[0]; + switch (direction) + { + case "Up": newHead.Y--; break; + case "Down": newHead.Y++; break; + case "Left": newHead.X--; break; + case "Right": newHead.X++; break; + } + + // Check collisions + if (newHead.X < 0 || newHead.Y < 0 || + newHead.X >= sizex || + newHead.Y >= sizey || + snake.Contains(newHead)) + { + isGameOver = true; + gameTimer.Stop(); + Dialogs.GameOver($"Счёт: {score}"); + this.Close(); + return; + } + + // Move snake + snake.Insert(0, newHead); + if (newHead == food) + { + SpawnFood(); + addScore(); + } + else + { + snake.RemoveAt(snake.Count - 1); // Remove tail + } + + this.Invalidate(); // Redraw + } + + private void OnPaint(object sender, PaintEventArgs e) + { + Graphics g = e.Graphics; + + // Draw snake + foreach (Point p in snake) + { + DrawTile(g, p.X, p.Y, Brushes.Green); + } + + // Draw food + DrawTile(g, food.X, food.Y, Brushes.Red); + + // Draw grid (optional) + for (int x = 0; x < this.ClientSize.Width; x += tileSize) + { + for (int y = 0; y < this.ClientSize.Height; y += tileSize) + { + g.DrawRectangle(Pens.Gray, x, y, tileSize, tileSize); + } + } + } + + private void DrawTile(Graphics g, int x, int y, Brush brush) + { + g.FillRectangle(brush, x * tileSize, y * tileSize, tileSize, tileSize); + } + + private void OnKeyDown(object sender, KeyEventArgs e) + { + if (isGameOver && e.KeyCode == Keys.R) + { + ResetGame(); + gameTimer.Start(); + return; + } + + switch (e.KeyCode) + { + case Keys.Up: if (direction != "Down") nextDirection = "Up"; break; + case Keys.Down: if (direction != "Up") nextDirection = "Down"; break; + case Keys.Left: if (direction != "Right") nextDirection = "Left"; break; + case Keys.Right: if (direction != "Left") nextDirection = "Right"; break; + } + } + + private void addScore() + { + score += level switch + { + Level.Low => 50, + Level.Medium => 100, + Level.High => 250, + _ => 1, + }; + } + public enum Level + { + Low, + Medium, + High + } + } +} diff --git a/GUI/SnakeForm.resx b/GUI/SnakeForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/GUI/SnakeForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ProgLab1.csproj b/ProgLab1.csproj index d4b3787..2cfef70 100644 --- a/ProgLab1.csproj +++ b/ProgLab1.csproj @@ -1,7 +1,7 @@  - Exe + WinExe net8.0-windows10.0.17763.0 enable enable diff --git a/Subprograms/SnakeGame.cs b/Subprograms/SnakeGame.cs deleted file mode 100644 index e118773..0000000 --- a/Subprograms/SnakeGame.cs +++ /dev/null @@ -1,380 +0,0 @@ -using System.Diagnostics; - -namespace laba3.Subprograms -{ - /// - /// TUI classic game "Snake"; - /// The player controls the snake. - /// The player has to eat apples to increase the length of the snake - /// and try not to crash into the wall or themselves; - /// - internal class SnakeGame - { - int size_x; - int size_y; - int score; - int size_xy; - Level difficulty; - Tiles[,] world; - Snake snake; - Random rnd; - - private bool gameover; - /// - /// Game world constructor; - /// - /// Game speed - /// Game world size dim x - /// Game world size dim y - public SnakeGame(Level difficulty, int size_x, int size_y) - { - this.size_x = size_x; - this.size_y = size_y; - this.difficulty = difficulty; - world = new Tiles[size_x, size_y]; - rnd = new Random(); - score = 0; - size_xy = size_x * size_y; - } - /// - /// Start game; - /// Console will be clean!; - /// - public void start() - { - int msPerTick = difficulty switch - { - Level.Low => 500, - Level.Medium => 250, - Level.High => 100, - _ => 500, - }; - gameover = false; - - Console.Clear(); - Console.CursorVisible = false; - snake = new Snake(new Point(size_x / 2, size_y / 2, this), 1, Direction.Right, this); - - GenerateFood(); - - DrawBackground(); - DrawWorld(); - - Stopwatch tickTimer = new Stopwatch(); - while (!gameover) - { - tickTimer.Restart(); - if (Console.KeyAvailable) - { - ConsoleKeyInfo key = Console.ReadKey(false); - snake.HandleKey(key.Key); - while (Console.KeyAvailable) - Console.ReadKey(false); - } - snake.Move(); - long delta = tickTimer.ElapsedMilliseconds; - - Console.SetCursorPosition(1, 0); - if (delta > msPerTick) - Console.ForegroundColor = ConsoleColor.Red; - Console.Write(delta); - - Thread.Sleep((int)Math.Max(0, msPerTick - delta)); - } - onStop(); - } - - /// - /// Stop game; - /// - public void stop() - { - gameover = true; - } - - private void onStop() - { - string gameOverTitle = -@" - ### ## -# ## #### # # # # # # ## -# ## # # # # # ### # # # # ### # -# # # # # # # # # # # # # - ### ## # # # ## ## # ## # -"; - Console.Clear(); - printArt(gameOverTitle, (Console.WindowWidth - 36) / 2, 4, ConsoleColor.DarkYellow, ConsoleColor.DarkGray); - - Console.ResetColor(); - - string scoreString = $"Score: {score}"; - Console.SetCursorPosition((Console.WindowWidth - scoreString.Length) / 2, 11); - Console.Write(scoreString); - Console.SetCursorPosition((Console.WindowWidth - "Press Enter to continue".Length) / 2, 14); - Console.CursorVisible = true; - } - - private void printArt(string art, int x, int y, ConsoleColor primaryColor, ConsoleColor shadowColor) - { - int row = 0; - Console.SetCursorPosition(x, y); - char shadow = ' '; - foreach (char ch in art) - { - if (ch == '\n') - { - if (shadow == '#') - { - Console.BackgroundColor = shadowColor; - Console.Write(' '); - } - Console.SetCursorPosition(x, y++ + row); - Thread.Sleep(25); - shadow = ch; - } - else if (ch == ' ') - { - if (shadow == '#') - { - Console.BackgroundColor = shadowColor; - Console.Write(' '); - } - else - Console.CursorLeft++; - shadow = ch; - } - else if (ch == '#') - { - Console.BackgroundColor = primaryColor; - Console.Write(' '); - shadow = ch; - } - - } - } - - private void addScore() - { - score += difficulty switch - { - Level.Low => 10, - Level.Medium => 50, - Level.High => 100, - _ => 1, - }; - } - - - /// - /// Generate food in random place; - /// - public void GenerateFood() - { - int x; - int y; - do - { - x = rnd.Next(size_x); - y = rnd.Next(size_y); - } while (world[x, y] != Tiles.Void); - world[x, y] = Tiles.Food; - DrawTile(x, y); - } - - private void DrawBackground() - { - for (int x = 1; x < (size_x + 1) * 2 + 1; x++) - { - Console.SetCursorPosition(x, 1); - Console.Write('#'); - Console.SetCursorPosition(x, size_y + 2); - Console.Write('#'); - } - for (int y = 1; y < size_y + 2; y++) - { - Console.SetCursorPosition(1, y); - Console.Write('#'); - - Console.SetCursorPosition(size_x * 2 + 1, y); - Console.Write('#'); - } - } - - private void DrawTile(int x, int y) - { - char symbol; - switch (world[x, y]) - { - case Tiles.Void: - symbol = ' '; - break; - case Tiles.Snake: - symbol = '*'; - Console.ForegroundColor = ConsoleColor.DarkRed; - break; - case Tiles.Food: - symbol = '@'; - Console.ForegroundColor = ConsoleColor.Red; - break; - default: - symbol = '?'; - break; - }; - //Console.BackgroundColor = ConsoleColor.DarkGreen; - Console.SetCursorPosition((x + 1) * 2, y + 2); - Console.Write(symbol); - - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.White; - } - private void DrawWorld() - { - for (int x = 0; x < size_x; x++) - { - for (int y = 0; y < size_y; y++) - { - DrawTile(x, y); - } - } - } - private enum Tiles - { - Void, - Snake, - Food - } - public enum Level - { - Low, - Medium, - High - } - private class Snake - { - private SnakeGame game; - private List body; - private Direction direction; - - public Snake(Point tail, int length, Direction initialDirection, SnakeGame game) - { - this.game = game; - body = new List(); - direction = initialDirection; - - for (int i = 0; i < length; i++) - { - Point p = new Point(tail.X, tail.Y, game); - body.Add(p); - } - } - - public void Move() - { - Point head = GetNextPoint(); - Point tail = body.First(); - - if (head.X < 0 || head.Y < 0 || head.X >= game.size_x || head.Y >= game.size_y) - { - game.stop(); - return; - } - - if (game.world[head.X, head.Y] == Tiles.Snake) - { - game.stop(); - return; - } - - - body.Add(head); - if (game.world[head.X, head.Y] != Tiles.Food) - { - body.Remove(tail); - tail.UpdateWorld(Tiles.Void); - } - else - { - game.addScore(); - game.GenerateFood(); - if (body.Count >= game.size_xy) game.stop(); - } - head.UpdateWorld(Tiles.Snake); - } - - public Point GetNextPoint() - { - Point head = body.Last(); - Point nextPoint = new Point(head.X, head.Y, game); - - switch (direction) - { - case Direction.Right: - nextPoint.X++; - break; - case Direction.Left: - nextPoint.X--; - break; - case Direction.Up: - nextPoint.Y--; - break; - case Direction.Down: - nextPoint.Y++; - break; - } - - return nextPoint; - } - - public void HandleKey(ConsoleKey key) - { - switch (key) - { - case ConsoleKey.LeftArrow: - if (direction != Direction.Right) - direction = Direction.Left; - break; - case ConsoleKey.RightArrow: - if (direction != Direction.Left) - direction = Direction.Right; - break; - case ConsoleKey.UpArrow: - if (direction != Direction.Down) - direction = Direction.Up; - break; - case ConsoleKey.DownArrow: - if (direction != Direction.Up) - direction = Direction.Down; - break; - } - } - } - - enum Direction - { - Left, - Right, - Up, - Down - } - - private class Point - { - private SnakeGame game { get; set; } - public int X { get; set; } - public int Y { get; set; } - - public Point(int x, int y, SnakeGame game) - { - this.game = game; - X = x; - Y = y; - } - - public void UpdateWorld(Tiles tile) - { - game.world[X, Y] = tile; - game.DrawTile(X, Y); - } - } - } -}