From 51bacf6060d170677a299791cfe89e538ff1a69e Mon Sep 17 00:00:00 2001 From: Floris <f.k.h.vandezande@students.uu.nl> Date: Sun, 1 Dec 2024 22:18:43 +0100 Subject: [PATCH] puzzleform update - Fixed flickering when redrawing board by using BufferedGraphics - Board is no longer marked as an optional parameter in PuzzleForm constructor - UI appearance/layout changes - GetTile method that returns board coordinates that touch a certain point (no longer static) - Key/Mouse presses made will activate certain functions, including inputs to boardState (only if mouse touching board) - Added input-handling abstract methods TileInput and TileClick to Board class / still missing solution for board not updating visually when boardState changes / solved 2 bugs by maximizing PuzzleForm window on start, removing this will make the bugs return / there is still at least one scenario where the input detection dies --- PuzzlePlayer/Binary.cs | 6 +- PuzzlePlayer/Board.cs | 7 ++ PuzzlePlayer/PuzzleForm.cs | 138 ++++++++++++++++++++++++++++--------- 3 files changed, 119 insertions(+), 32 deletions(-) diff --git a/PuzzlePlayer/Binary.cs b/PuzzlePlayer/Binary.cs index 12aa1f2..c4127af 100644 --- a/PuzzlePlayer/Binary.cs +++ b/PuzzlePlayer/Binary.cs @@ -21,7 +21,7 @@ namespace PuzzlePlayer_Namespace // create a board with the specifide size boardState = new int[boardSize,boardSize]; - description = "Binary puzzle is played on any even-numbered square grid, with some cells initially containing black or white circles. The goal of the puzzle is to fill all cells such that:\r\n- More than two circles of the same color cannot be adjacent\r\n- Each row and column must contain an equal number of black and white circles\r\n- Each row and column cannot appear multiple times on the board"; + description = "Binary puzzle is played on any even-numbered square grid, with some cells initially containing black or white circles. The goal of the puzzle is to fill all cells such that:\r\n◠More than two circles of the same color cannot be adjacent\r\n◠Each row and column must contain an equal number of black and white circles\r\n◠Each row and column cannot appear multiple times on the board"; // clear the board (fill it in with -1) Clear(); @@ -202,5 +202,9 @@ namespace PuzzlePlayer_Namespace return false; } + public override void TileInput(Point p, int x) + { + if (x==0 || x==1) boardState[p.X, p.Y] = x; + } } } \ No newline at end of file diff --git a/PuzzlePlayer/Board.cs b/PuzzlePlayer/Board.cs index d373062..01ec0d4 100644 --- a/PuzzlePlayer/Board.cs +++ b/PuzzlePlayer/Board.cs @@ -95,5 +95,12 @@ namespace PuzzlePlayer_Namespace // abstract methode for checking if a imputed boardstate is valid public abstract bool IsBoardValid(int[,] boardToCheck); + + // changes tile P to value X + public abstract void TileInput(Point p, int x); + + // performs a left/right (X) click on tile P, changing its value + public virtual void TileClick(Point p, int x) { } + } } diff --git a/PuzzlePlayer/PuzzleForm.cs b/PuzzlePlayer/PuzzleForm.cs index 8b3aaf7..6c7b6ad 100644 --- a/PuzzlePlayer/PuzzleForm.cs +++ b/PuzzlePlayer/PuzzleForm.cs @@ -1,4 +1,5 @@ using System; +using System.CodeDom; using System.Collections.Generic; using System.Drawing; using System.Drawing.Text; @@ -11,15 +12,15 @@ namespace PuzzlePlayer_Namespace { internal class PuzzleForm : Form { - private Button solvebutton; - private Button hintbutton; - private Button generatebutton; - private TextBox informationbox; - private Graphics graphics; + private readonly Button solvebutton; + private readonly Button hintbutton; + private readonly Button generatebutton; + private readonly Label titlebox; + private readonly Label informationbox; private Rectangle boardspace; - + private readonly BufferedGraphics bufferedGraphics; private Board board; - public Board Board //Updating the Board member will immediately call board.Draw method so that the board is updated visually + public Board Board //updating the Board member will immediately call board.Draw method so that the board is updated visually { get { return board; } set @@ -29,27 +30,48 @@ namespace PuzzlePlayer_Namespace } } - public PuzzleForm(Board b = null, Size s = default(Size)) //Takes Board and Size parameter and sets up the PuzzleForm window. + private readonly Button UPDATEBUTTON; + public PuzzleForm(Board b, Size s = default) //takes Board and Size parameter and sets up the PuzzleForm window. { - if (s == default(Size)) s = new Size(700, 420); + if (s == default) s = new Size(700, 420); this.Size = this.MinimumSize = s; this.WindowState = FormWindowState.Maximized; this.BackColor = Color.DarkGreen; - this.Text = "top text"; - graphics = this.CreateGraphics(); - graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + this.Text = "PuzzlePlayer"; + bufferedGraphics = BufferedGraphicsManager.Current.Allocate(this.CreateGraphics(), this.DisplayRectangle); + bufferedGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; generatebutton = new Button(); hintbutton = new Button(); solvebutton = new Button(); - informationbox = new TextBox(); + UPDATEBUTTON = new Button(); + titlebox = new Label(); + informationbox = new Label(); boardspace = new Rectangle(220, 30, 400, 400); + this.Paint += (object o, PaintEventArgs pea) => { - board.Draw(graphics, boardspace); - //graphics.FillRectangle(Brushes.LightCoral, 220, 30, this.Width - 380, this.Height - 100); - //graphics.FillRectangle(Brushes.DarkRed, boardspace); + board.Draw(bufferedGraphics.Graphics, boardspace); + //bufferedGraphics.Graphics.FillRectangle(Brushes.LightCoral, 220, 30, this.Width - 350, this.Height - 100); + //bufferedGraphics.Graphics.FillRectangle(Brushes.DarkRed, boardspace); + bufferedGraphics.Render(); }; this.Resize += (object o, EventArgs ea) => UpdateUI(); + this.Move += (object o, EventArgs ea) => this.Focus(); + this.KeyPress += (object o, KeyPressEventArgs kea) => Input(kea.KeyChar); + this.MouseClick += (object o, MouseEventArgs mea) => + { + if (mea.Button == MouseButtons.Left) + { + Input('['); + return; + } + if (mea.Button == MouseButtons.Right) + { + Input(']'); + return; + } + }; + Board = b; CreateUI(); Board.boardState[1, 1] = 1; @@ -61,58 +83,112 @@ namespace PuzzlePlayer_Namespace { Controls.Add(b); b.Size = new Size(80, 50); - b.BackColor = Color.Gainsboro; + b.FlatAppearance.BorderColor = b.BackColor = Color.Gainsboro; b.Text = "DEFAULT0"; + b.Font = new Font("Verdana", 12, FontStyle.Bold | FontStyle.Italic); + b.FlatStyle = FlatStyle.Flat; + b.GotFocus += (object o, EventArgs ea) => this.Focus(); } CreateButton(generatebutton); - generatebutton.Text = "Generate"; + generatebutton.Text = "New Game"; generatebutton.MouseClick += (object sender, MouseEventArgs mea) => { - //board = Board.Generate(); + Board.Generate(); + Board = Board; }; CreateButton(hintbutton); hintbutton.Text = "Hint"; hintbutton.MouseClick += (object sender, MouseEventArgs mea) => { MessageBox.Show("Hint: geef op"); + Board = Board; }; CreateButton(solvebutton); solvebutton.Text = "Solve"; solvebutton.MouseClick += (object sender, MouseEventArgs mea) => { - //board = board.Solve(); + Board.Solve(); + Board = Board; + }; + + CreateButton(UPDATEBUTTON); + UPDATEBUTTON.Text = "Update"; + UPDATEBUTTON.Font = new Font("Verdana", 11, FontStyle.Bold); + UPDATEBUTTON.FlatAppearance.BorderColor = UPDATEBUTTON.BackColor = Color.Pink; + UPDATEBUTTON.MouseClick += (object sender, MouseEventArgs mea) => + { Board = Board; }; + Controls.Add(titlebox); + titlebox.Location = new Point(20, 15); + titlebox.Size = new Size(180, 50); + titlebox.BackColor = this.BackColor; + titlebox.ForeColor = Color.White; + titlebox.Text = "Binary"; + titlebox.Font = new Font("Verdana", 24, FontStyle.Bold); + Controls.Add(informationbox); - informationbox.Multiline = true; - informationbox.Size = new Size(160, 300); - informationbox.BackColor = Color.LightGray; + informationbox.Location = new Point(20, 65); + informationbox.Size = new Size(180, 300); + informationbox.BackColor = this.BackColor; + informationbox.ForeColor = Color.White; informationbox.Text = board.description; informationbox.Font = new Font("Verdana", 10); UpdateUI(); } private void UpdateUI() //resizes the boardspace rectangle and updates the rest of the ui around the new boardspace size { - graphics.Clear(this.BackColor); - boardspace.Size = FitBoard(new Size(Board.boardState.GetLength(0),Board.boardState.GetLength(1)),new Size(this.Width - 380, this.Height - 100),8); + bufferedGraphics.Graphics.Clear(this.BackColor); + boardspace.Size = FitBoard(new Size(Board.boardState.GetLength(0),Board.boardState.GetLength(1)),new Size(this.Width - 350, this.Height - 100),8); generatebutton.Location = new Point(boardspace.Right + 30, 30); - hintbutton.Location = new Point(boardspace.Right + 30, 130); - solvebutton.Location = new Point(boardspace.Right + 30, 230); - informationbox.Location = new Point(40, 30); + hintbutton.Location = new Point(boardspace.Right + 30, 110); + solvebutton.Location = new Point(boardspace.Right + 30, 190); + UPDATEBUTTON.Location = new Point(boardspace.Right + 30, 270); this.Invalidate(); } public static Size FitBoard(Size gamesize, Size maxboardsize, int drawfactor) //returns the largest rectangle smaller than MaxBoardSize that fits the given GameSize well { int TileLength = Math.Min(maxboardsize.Width / gamesize.Width, maxboardsize.Height / gamesize.Height) / drawfactor * drawfactor; return new Size(gamesize.Width*TileLength, gamesize.Height*TileLength); - //After each of the divisions in this method, the value should be rounded down, + //after each of the divisions in this method, the value should be rounded down, //as the end value cannot exceed the size given by maxboardsize. //however, C# rounds divisions of Int values down by default, so this does not have to be explicitly done. } - public static Point GetTile(Point p) + private Point GetTile(Size gamesize, Rectangle r, Point p) //returns board coordinate at mouse position P of a Gamesize board drawn in R + { + Point res = this.PointToClient(p) - (Size)r.Location; + res.X /= (r.Width / gamesize.Width); + res.Y /= (r.Height / gamesize.Height); + return res; + } + public void Input(char c) //checks if a command binded to the keyboard key and runs it, affects tile that is hovered on if applicable { - return p; + if (!"nhs[]1234567890".Contains(c)) return; + switch (c) + { + case 'n': + return; + case 'h': + MessageBox.Show("Hint: geef op"); + return; + case 's': + return; + + } + Point tile = GetTile(new Size(Board.boardState.GetLength(0), Board.boardState.GetLength(1)), boardspace, Control.MousePosition); + if (!(tile.X >= 0 && tile.X < Board.boardState.GetLength(0) && tile.Y >= 0 && tile.Y < Board.boardState.GetLength(1))) return; + if (c == '[' || c == ']') // '[' = 91, ']' = 93 + { + //Board.TileClick(tile, (c - 91) / 2); + return; + } + if (char.GetNumericValue(c) != -1) + { + Board.TileInput(tile, (int)char.GetNumericValue(c)); + return; + } + MessageBox.Show("uhoh"); } } } -- GitLab