From ff23702c151b919b45ee13f16e8d105b49ddf99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kecskem=C3=A9ti=20L=C3=A1szl=C3=B3?= Date: Mon, 21 Oct 2024 14:47:19 +0200 Subject: [PATCH] changes xd --- bead1.sln | 21 +++- model/SnakeLevel.cs | 135 +++++++++++++++++++++-- persistance/SnakeLevelLoader.cs | 4 +- persistance/StoredSnakeLevel.cs | 2 + view/Form1.Designer.cs | 115 +++++++++++++++++++ view/Form1.cs | 178 ++++++++++++++++++++++++++++++ view/Form1.resx | 120 ++++++++++++++++++++ view/MapChooser.Designer.cs | 190 ++++++++++++++++++++++++++++++++ view/MapChooser.cs | 65 +++++++++++ view/MapChooser.resx | 120 ++++++++++++++++++++ view/Program.cs | 17 +++ view/levels.json | 25 +++++ view/view.csproj | 22 ++++ 13 files changed, 996 insertions(+), 18 deletions(-) create mode 100644 view/Form1.Designer.cs create mode 100644 view/Form1.cs create mode 100644 view/Form1.resx create mode 100644 view/MapChooser.Designer.cs create mode 100644 view/MapChooser.cs create mode 100644 view/MapChooser.resx create mode 100644 view/Program.cs create mode 100644 view/levels.json create mode 100644 view/view.csproj diff --git a/bead1.sln b/bead1.sln index c6ed21b..517290e 100644 --- a/bead1.sln +++ b/bead1.sln @@ -3,20 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "persistance", "persistance\persistance.csproj", "{5C804F63-B331-4F7B-9C28-1A583594C73B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "persistance", "persistance\persistance.csproj", "{5C804F63-B331-4F7B-9C28-1A583594C73B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "model", "model\model.csproj", "{41FA02D6-4257-46E6-BAF0-1D975169C05E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "model", "model\model.csproj", "{41FA02D6-4257-46E6-BAF0-1D975169C05E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{05D087EA-57EA-4A01-82B5-C36C7242EF80}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tests", "tests\tests.csproj", "{05D087EA-57EA-4A01-82B5-C36C7242EF80}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "view", "view\view.csproj", "{EFD422C5-2A8F-4E7B-8294-1EB93B3F94AA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5C804F63-B331-4F7B-9C28-1A583594C73B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5C804F63-B331-4F7B-9C28-1A583594C73B}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -30,5 +29,15 @@ Global {05D087EA-57EA-4A01-82B5-C36C7242EF80}.Debug|Any CPU.Build.0 = Debug|Any CPU {05D087EA-57EA-4A01-82B5-C36C7242EF80}.Release|Any CPU.ActiveCfg = Release|Any CPU {05D087EA-57EA-4A01-82B5-C36C7242EF80}.Release|Any CPU.Build.0 = Release|Any CPU + {EFD422C5-2A8F-4E7B-8294-1EB93B3F94AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFD422C5-2A8F-4E7B-8294-1EB93B3F94AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFD422C5-2A8F-4E7B-8294-1EB93B3F94AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFD422C5-2A8F-4E7B-8294-1EB93B3F94AA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {60431C7C-5F67-41C9-BE6E-6F4E4B7EF4AB} EndGlobalSection EndGlobal diff --git a/model/SnakeLevel.cs b/model/SnakeLevel.cs index 79e190c..c025526 100644 --- a/model/SnakeLevel.cs +++ b/model/SnakeLevel.cs @@ -1,8 +1,11 @@ using System.Collections.ObjectModel; +using System.IO.Pipes; +using System.Numerics; namespace Snake.Model; public class SnakeLevel{ + public static readonly TimeSpan TickTimeSpan = TimeSpan.FromMilliseconds(500); public int Size {get; } public enum LevelBlock{ @@ -23,6 +26,7 @@ public class SnakeLevel{ public enum GameState{ Running, + Paused, Dead } @@ -31,26 +35,74 @@ public class SnakeLevel{ public Point SnakeHead {get; private set;} private readonly List _snake; // Head is not in snake - // Last is closest to the head + // First is closest to the head public ReadOnlyCollection Snake => _snake.AsReadOnly(); public int SnakeLength => Snake.Count + 1; private readonly List _eggs; public ReadOnlyCollection Eggs => _eggs.AsReadOnly(); - public SnakeDirection SnakeHeadDirection {get; private set;} - public GameState State {get; private set;} + public int NewEggRound { get; } + public int EggLimit { get; } + private int _round; - public SnakeLevel(int size, IEnumerable obstacles, int snake_start_length){ + private PeriodicTimer _timer; + public int Score { get; private set; } + + public event EventHandler? GameUpdate; + public event EventHandler? GameStateUpdate; + private GameState _state; + public GameState State + { + get => _state; + private set + { + _state = value; + GameStateUpdate?.Invoke(this, _state); + } + } + + + private SnakeDirection LastDirection = SnakeDirection.Down; + private SnakeDirection _SnakeHeadDirection; + public SnakeDirection SnakeHeadDirection + { + get => _SnakeHeadDirection; + set + { + switch (value, LastDirection) + { + case { value: SnakeDirection.Up or SnakeDirection.Down, LastDirection: SnakeDirection.Left or SnakeDirection.Right}: + case { value: SnakeDirection.Left or SnakeDirection.Right, LastDirection: SnakeDirection.Up or SnakeDirection.Down }: + _SnakeHeadDirection = value; + break; + } + } + } + + public SnakeLevel(int size, IEnumerable obstacles, int snake_start_length, int new_egg_round, int egg_limit, TimeProvider time_provider){ this.Size = size; + this.NewEggRound = new_egg_round; + this._round = NewEggRound; + this.EggLimit = egg_limit; + _obstacles = new List(obstacles); _eggs = []; _snake = []; SnakeHead = (size / 2, snake_start_length-1); - for(int i=0; i=0; i--){ _snake.Add((size / 2, i)); } - SnakeHeadDirection = SnakeDirection.Down; + _SnakeHeadDirection = SnakeDirection.Down; + LastDirection = SnakeDirection.Down; + + _timer = new PeriodicTimer(TickTimeSpan, time_provider); + + _state = GameState.Paused; + } + + public SnakeLevel(int size, IEnumerable obstacles, int snake_start_length, int new_egg_round, int egg_limit) : this(size, obstacles, snake_start_length, new_egg_round, egg_limit, TimeProvider.System) + { } public LevelBlock this[Point p]{ @@ -93,18 +145,79 @@ public class SnakeLevel{ return; } - var first = Snake[0]; + Point last = _snake.Last(); - for(int i=_snake.Count-1; i>0; i--){ - _snake[i-1] = _snake[i]; + for (int i = Snake.Count - 1; i > 0; i--) + { + _snake[i] = _snake[i - 1]; } - _snake[^1] = SnakeHead; + _snake[0] = SnakeHead; if(this[new_snake_head] is LevelBlock.Egg){ - _snake.Insert(0, first); + _snake.Add(last); _eggs.Remove(new_snake_head); + Score++; } SnakeHead = new_snake_head; + + if (Eggs.Count < EggLimit && --_round == 0) + { + _round = NewEggRound; + int avail_pos = Size * Size - Eggs.Count - Obstacles.Count - SnakeLength; + if (avail_pos > 0) + { + int pos = Random.Shared.Next(0, avail_pos); + Point p = (0, 0); + for (int i = 0; i < pos; i++) + { + do + { + p = (p.X + 1, p.Y); + if (p.X >= Size) + { + p = (0, p.Y + 1); + } + } while (this[p] is not LevelBlock.Empty); + } + _eggs.Add(p); + } + } + + LastDirection = SnakeHeadDirection; + } + + private async Task TickerTask() + { + while(State == GameState.Running && await _timer.WaitForNextTickAsync()) + { + Tick(); + GameUpdate?.Invoke(this, EventArgs.Empty); + } + } + + public void Start() + { + if(State == GameState.Paused) + { + State = GameState.Running; + Task.Run(TickerTask); + } + else + { + throw new Exception("Game is not paused"); + } + } + + public void Pause() + { + if(State == GameState.Running) + { + State = GameState.Paused; + } + else + { + throw new Exception("Game is not running"); + } } } \ No newline at end of file diff --git a/persistance/SnakeLevelLoader.cs b/persistance/SnakeLevelLoader.cs index c697c66..d00b9b0 100644 --- a/persistance/SnakeLevelLoader.cs +++ b/persistance/SnakeLevelLoader.cs @@ -23,6 +23,8 @@ public class SnakeLevelLoader{ public SnakeLevel LoadLevel(StoredSnakeLevel level){ return new SnakeLevel(level.Size, level.Obstacles.Select(a => new Point(a[0], a[1])), - level.SnakeStartLength); + level.SnakeStartLength, + level.NewEggRound, + level.EggLimit); } } \ No newline at end of file diff --git a/persistance/StoredSnakeLevel.cs b/persistance/StoredSnakeLevel.cs index 007ac3e..e14f37e 100644 --- a/persistance/StoredSnakeLevel.cs +++ b/persistance/StoredSnakeLevel.cs @@ -4,5 +4,7 @@ public class StoredSnakeLevel{ public required string LevelName {get; init;} public required int Size {get; init;} public required int SnakeStartLength {get; init;} + public required int NewEggRound { get; init; } + public required int EggLimit { get; init; } public required int[][] Obstacles {get; init;} } \ No newline at end of file diff --git a/view/Form1.Designer.cs b/view/Form1.Designer.cs new file mode 100644 index 0000000..67b5098 --- /dev/null +++ b/view/Form1.Designer.cs @@ -0,0 +1,115 @@ +namespace view +{ + partial class Form1 + { + /// + /// 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() + { + Canvas = new Panel(); + btnStart = new Button(); + panel1 = new Panel(); + txtScore = new TextBox(); + label1 = new Label(); + Canvas.SuspendLayout(); + panel1.SuspendLayout(); + SuspendLayout(); + // + // Canvas + // + Canvas.BackColor = Color.White; + Canvas.Controls.Add(btnStart); + Canvas.Dock = DockStyle.Top; + Canvas.Location = new Point(0, 0); + Canvas.Name = "Canvas"; + Canvas.Size = new Size(480, 480); + Canvas.TabIndex = 0; + // + // btnStart + // + btnStart.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + btnStart.Location = new Point(193, 226); + btnStart.Name = "btnStart"; + btnStart.Size = new Size(94, 29); + btnStart.TabIndex = 0; + btnStart.Text = "START"; + btnStart.UseVisualStyleBackColor = true; + btnStart.Click += btnStart_Click; + // + // panel1 + // + panel1.Controls.Add(txtScore); + panel1.Controls.Add(label1); + panel1.Dock = DockStyle.Bottom; + panel1.Location = new Point(0, 486); + panel1.Name = "panel1"; + panel1.Size = new Size(480, 94); + panel1.TabIndex = 0; + // + // txtScore + // + txtScore.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + txtScore.Location = new Point(64, 9); + txtScore.Name = "txtScore"; + txtScore.ReadOnly = true; + txtScore.Size = new Size(404, 27); + txtScore.TabIndex = 1; + txtScore.TabStop = false; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(12, 12); + label1.Name = "label1"; + label1.Size = new Size(46, 20); + label1.TabIndex = 0; + label1.Text = "Score"; + // + // Form1 + // + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(480, 580); + Controls.Add(panel1); + Controls.Add(Canvas); + Name = "Form1"; + Text = "Snake"; + KeyDown += Form1_KeyDown; + PreviewKeyDown += Form1_PreviewKeyDown; + Canvas.ResumeLayout(false); + panel1.ResumeLayout(false); + panel1.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private Panel Canvas; + private Panel panel1; + private Label label1; + private TextBox txtScore; + private Button btnStart; + } +} diff --git a/view/Form1.cs b/view/Form1.cs new file mode 100644 index 0000000..11690b2 --- /dev/null +++ b/view/Form1.cs @@ -0,0 +1,178 @@ +using Snake.Model; +using Snake.Persistance; + +namespace view +{ + public partial class Form1 : Form + { + Graphics graphics; + int line_width = 2; + SnakeLevel? CurrentLevel; + SnakeLevelLoader level_loader; + + public Form1() + { + InitializeComponent(); + graphics = Canvas.CreateGraphics(); + level_loader = new SnakeLevelLoader(Path.Combine(Directory.GetCurrentDirectory(), "levels.json")); + } + + private void Form1_KeyDown(object sender, KeyEventArgs e) + { + if (CurrentLevel == null) return; + switch (e.KeyCode) + { + case Keys.Up: + CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Up; + break; + case Keys.Down: + CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Down; + break; + case Keys.Left: + CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Left; + break; + case Keys.Right: + CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Right; + break; + case Keys.Escape: + CurrentLevel.Pause(); + break; + + } + } + + private void Draw(SnakeLevel level) + { + var canvas_size = Math.Min(Canvas.Width, Canvas.Height); + + + graphics.Clear(Color.White); + double cell_size = (double)(canvas_size - (level.Size + 1) * line_width) / level.Size; + // vertical lines + for (int i = 0; i <= level.Size; i++) + { + int x = (int)(i * (cell_size + line_width)); + graphics.FillRectangle(Brushes.Black, x, 0, line_width, canvas_size); + } + // horizontal lines + for (int i = 0; i <= level.Size; i++) + { + int y = (int)(i * (cell_size + line_width)); + graphics.FillRectangle(Brushes.Black, 0, y, canvas_size, line_width); + } + // Ssnake + foreach (var pos in level.Snake) + { + int x = (int)(cell_size * pos.X + line_width * (pos.X + 1)); + int y = (int)(cell_size * pos.Y + line_width * (pos.Y + 1)); + graphics.FillRectangle(Brushes.Green, x, y, (int)cell_size, (int)cell_size); + } + // snake head + int snake_head_x = (int)(cell_size * level.SnakeHead.X + line_width * (level.SnakeHead.X + 1)); + int snake_head_y = (int)(cell_size * level.SnakeHead.Y + line_width * (level.SnakeHead.Y + 1)); + graphics.FillRectangle(Brushes.Red, snake_head_x, snake_head_y, (int)cell_size, (int)cell_size); + switch (level.SnakeHeadDirection) + { + case SnakeLevel.SnakeDirection.Up: + graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size / 2, snake_head_y + (int)cell_size); + graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x, snake_head_y + (int)cell_size / 2); + graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); + break; + case SnakeLevel.SnakeDirection.Down: + graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size / 2, snake_head_y + (int)cell_size); + graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x, snake_head_y + (int)cell_size / 2); + graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); + break; + case SnakeLevel.SnakeDirection.Left: + graphics.DrawLine(Pens.Black, snake_head_x, snake_head_y + (int)cell_size / 2, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); + break; + case SnakeLevel.SnakeDirection.Right: + graphics.DrawLine(Pens.Black, snake_head_x, snake_head_y + (int)cell_size / 2, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); + break; + + } + + // obstacles + foreach (var pos in level.Obstacles) + { + int x = (int)(cell_size * pos.X + line_width * (pos.X + 1)); + int y = (int)(cell_size * pos.Y + line_width * (pos.Y + 1)); + graphics.FillRectangle(Brushes.Black, x, y, (int)cell_size, (int)cell_size); + } + + //eggs + foreach (var pos in level.Eggs) + { + int x = (int)(cell_size * pos.X + line_width * (pos.X + 1)); + int y = (int)(cell_size * pos.Y + line_width * (pos.Y + 1)); + graphics.FillRectangle(Brushes.Pink, x, y, (int)cell_size, (int)cell_size); + } + } + + private void btnStart_Click(object sender, EventArgs e) + { + if (CurrentLevel is null || CurrentLevel.State != SnakeLevel.GameState.Running) + { + var MapChooser = new MapChooser(this.level_loader); + MapChooser.ShowDialog(); + if (MapChooser.SelectedLevel != null) + { + CurrentLevel = level_loader.LoadLevel(MapChooser.SelectedLevel); + CurrentLevel.GameStateUpdate += CurrentLevel_GameStateUpdate; + CurrentLevel.GameUpdate += CurrentLevel_GameUpdate; + } + else + { + CurrentLevel = null; + } + } + if (CurrentLevel != null) + { + CurrentLevel.Start(); + this.Focus(); + } + } + + private void CurrentLevel_GameUpdate(object? sender, EventArgs e) + { + this.Invoke(() => + { + if (CurrentLevel != null) + { + Draw(CurrentLevel); + txtScore.Text = CurrentLevel.Score.ToString(); + } + }); + } + + private void CurrentLevel_GameStateUpdate(object? sender, SnakeLevel.GameState e) + { + this.Invoke(() => + { + if (CurrentLevel == null) return; + switch (e) + { + case SnakeLevel.GameState.Running: + btnStart.Visible = false; + Draw(CurrentLevel); + break; + case SnakeLevel.GameState.Paused: + btnStart.Visible = true; + break; + case SnakeLevel.GameState.Dead: + btnStart.Visible = true; + MessageBox.Show($"Skill issue.\nScore: {CurrentLevel.Score}", "Snake", MessageBoxButtons.OK, MessageBoxIcon.Information); + break; + } + }); + } + + private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + if(CurrentLevel?.State is SnakeLevel.GameState.Running) + { + e.IsInputKey = true; + } + } + } +} diff --git a/view/Form1.resx b/view/Form1.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/view/Form1.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/view/MapChooser.Designer.cs b/view/MapChooser.Designer.cs new file mode 100644 index 0000000..f3a081e --- /dev/null +++ b/view/MapChooser.Designer.cs @@ -0,0 +1,190 @@ +namespace view +{ + partial class MapChooser + { + /// + /// 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() + { + lstLevels = new ListBox(); + groupBox1 = new GroupBox(); + txtObstacleCount = new TextBox(); + label4 = new Label(); + txtEggRounds = new TextBox(); + label3 = new Label(); + txtSnakeLength = new TextBox(); + label2 = new Label(); + txtSize = new TextBox(); + label1 = new Label(); + button1 = new Button(); + groupBox1.SuspendLayout(); + SuspendLayout(); + // + // lstLevels + // + lstLevels.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + lstLevels.FormattingEnabled = true; + lstLevels.Location = new Point(12, 12); + lstLevels.Name = "lstLevels"; + lstLevels.Size = new Size(270, 384); + lstLevels.TabIndex = 0; + lstLevels.SelectedIndexChanged += listBox1_SelectedIndexChanged; + lstLevels.KeyUp += lstLevels_KeyUp; + // + // groupBox1 + // + groupBox1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + groupBox1.Controls.Add(txtObstacleCount); + groupBox1.Controls.Add(label4); + groupBox1.Controls.Add(txtEggRounds); + groupBox1.Controls.Add(label3); + groupBox1.Controls.Add(txtSnakeLength); + groupBox1.Controls.Add(label2); + groupBox1.Controls.Add(txtSize); + groupBox1.Controls.Add(label1); + groupBox1.Location = new Point(288, 12); + groupBox1.Name = "groupBox1"; + groupBox1.Size = new Size(309, 163); + groupBox1.TabIndex = 1; + groupBox1.TabStop = false; + groupBox1.Text = "Map details"; + // + // txtObstacleCount + // + txtObstacleCount.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + txtObstacleCount.Location = new Point(133, 119); + txtObstacleCount.Name = "txtObstacleCount"; + txtObstacleCount.ReadOnly = true; + txtObstacleCount.Size = new Size(170, 27); + txtObstacleCount.TabIndex = 7; + txtObstacleCount.TabStop = false; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(6, 122); + label4.Name = "label4"; + label4.Size = new Size(111, 20); + label4.TabIndex = 6; + label4.Text = "Obstacle count:"; + // + // txtEggRounds + // + txtEggRounds.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + txtEggRounds.Location = new Point(133, 85); + txtEggRounds.Name = "txtEggRounds"; + txtEggRounds.ReadOnly = true; + txtEggRounds.Size = new Size(170, 27); + txtEggRounds.TabIndex = 5; + txtEggRounds.TabStop = false; + // + // label3 + // + label3.AutoSize = true; + label3.Location = new Point(6, 88); + label3.Name = "label3"; + label3.Size = new Size(121, 20); + label3.TabIndex = 4; + label3.Text = "New egg rounds:"; + // + // txtSnakeLength + // + txtSnakeLength.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + txtSnakeLength.Location = new Point(139, 52); + txtSnakeLength.Name = "txtSnakeLength"; + txtSnakeLength.ReadOnly = true; + txtSnakeLength.Size = new Size(164, 27); + txtSnakeLength.TabIndex = 3; + txtSnakeLength.TabStop = false; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new Point(6, 55); + label2.Name = "label2"; + label2.Size = new Size(130, 20); + label2.TabIndex = 2; + label2.Text = "Snake start length:"; + // + // txtSize + // + txtSize.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + txtSize.Location = new Point(62, 20); + txtSize.Name = "txtSize"; + txtSize.ReadOnly = true; + txtSize.Size = new Size(241, 27); + txtSize.TabIndex = 1; + txtSize.TabStop = false; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(6, 23); + label1.Name = "label1"; + label1.Size = new Size(39, 20); + label1.TabIndex = 0; + label1.Text = "Size:"; + // + // button1 + // + button1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + button1.Location = new Point(294, 345); + button1.Name = "button1"; + button1.Size = new Size(303, 51); + button1.TabIndex = 2; + button1.Text = "Select"; + button1.UseVisualStyleBackColor = true; + button1.Click += button1_Click; + // + // MapChooser + // + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(609, 404); + Controls.Add(button1); + Controls.Add(groupBox1); + Controls.Add(lstLevels); + Name = "MapChooser"; + Text = "MapChooser"; + groupBox1.ResumeLayout(false); + groupBox1.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private ListBox lstLevels; + private GroupBox groupBox1; + private TextBox txtSize; + private Label label1; + private TextBox txtSnakeLength; + private Label label2; + private TextBox txtEggRounds; + private Label label3; + private TextBox txtObstacleCount; + private Label label4; + private Button button1; + } +} \ No newline at end of file diff --git a/view/MapChooser.cs b/view/MapChooser.cs new file mode 100644 index 0000000..93393e9 --- /dev/null +++ b/view/MapChooser.cs @@ -0,0 +1,65 @@ +using Snake.Persistance; + +namespace view +{ + public partial class MapChooser : Form + { + private SnakeLevelLoader _level_loader; + public StoredSnakeLevel? SelectedLevel { get; private set; } + public MapChooser(SnakeLevelLoader level_loader) + { + this._level_loader = level_loader; + InitializeComponent(); + + foreach (var level in _level_loader.StoredLevels) + { + lstLevels.Items.Add(level.LevelName); + } + } + + private void listBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (lstLevels.SelectedIndex == -1) + { + txtEggRounds.Text = ""; + txtObstacleCount.Text = ""; + txtSize.Text = ""; + txtSnakeLength.Text = ""; + } + else + { + var level = _level_loader.StoredLevels[lstLevels.SelectedIndex]; + txtEggRounds.Text = level.NewEggRound.ToString(); + txtObstacleCount.Text = level.Obstacles.Length.ToString(); + txtSize.Text = $"{level.Size}x{level.Size}"; + txtSnakeLength.Text = level.SnakeStartLength.ToString(); + } + } + + private void button1_Click(object sender, EventArgs e) + { + ChooseLevel(); + } + + private void lstLevels_KeyUp(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + ChooseLevel(); + } + } + + void ChooseLevel() + { + if (lstLevels.SelectedIndex == -1) + { + SelectedLevel = null; + } + else + { + SelectedLevel = _level_loader.StoredLevels[lstLevels.SelectedIndex]; + Close(); + } + } + } +} diff --git a/view/MapChooser.resx b/view/MapChooser.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/view/MapChooser.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/view/Program.cs b/view/Program.cs new file mode 100644 index 0000000..1c391ea --- /dev/null +++ b/view/Program.cs @@ -0,0 +1,17 @@ +namespace view +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/view/levels.json b/view/levels.json new file mode 100644 index 0000000..605eb67 --- /dev/null +++ b/view/levels.json @@ -0,0 +1,25 @@ +[ + { + "level_name": "Test level", + "size": 10, + "snake_start_length": 5, + "new_egg_round": 3, + "egg_limit": 2, + "obstacles": [ + [ 1, 1 ], + [ 4, 2 ], + [ 6, 9 ] + ] + }, + { + "level_name": "Cool snake map", + "size": 12, + "snake_start_length": 3, + "new_egg_round": 5, + "egg_limit": 3, + "obstacles": [ + [ 2, 3 ], + [ 1, 2 ] + ] + } +] \ No newline at end of file diff --git a/view/view.csproj b/view/view.csproj new file mode 100644 index 0000000..d2f5f75 --- /dev/null +++ b/view/view.csproj @@ -0,0 +1,22 @@ + + + + WinExe + net8.0-windows + enable + true + enable + + + + + + + + + + PreserveNewest + + + + \ No newline at end of file