Uproszczenie kodu w grze przesuwanka

0

Cześć piszę mini grę w przesuwanie klocków aby ułożyć je w kolejności.
Gra działa ale zastanawiam się jak bym mógł usprawnić kod? Bo o ile dla planszy 3x3 kod zajmuje 300 linijek to gdybym chciał zrobić kod dla planszy 4x4 to długość kodu to już byłaby masakra.
Przypisanie liczb do przycisków mógłbym wrzucić w tablicę i pętlę foreach no i parę linijek kodu zaoszczędzę Zrzut ekranu 2022-12-27 114554.pngale jak ogarnąć te wszystkie warunki dla każdego kliknięcia przycisku?Da się to zrobić jakoś krócej?
Tak żeby wrzucić to do jednej metody która działa na kliknięcie jakiegokolwiek przycisku?

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;

namespace ukladanka
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            NewGame();
        }

        private void NewGame()
        {
            int index;
            int i = 0;
            Random rand = new Random();

            
            List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };//lista liczb na przyciskach

            
            string[] randomNumbers = new string[8];//tu będą wymieszane przyciski

            foreach (string b in randomNumbers) //pętla mieszająca tablicę liczb
            {
               
                index = rand.Next(0, numbers.Count);
                
                randomNumbers[i] = numbers[index].ToString();
               
                numbers.RemoveAt(index);
                i++;
            }
            //Przypisanie cyfr do przycisków
            button1.Text = randomNumbers[0];
            button2.Text = randomNumbers[1];
            button3.Text = randomNumbers[2];
            button4.Text = randomNumbers[3];
            button5.Text = randomNumbers[4];
            button6.Text = randomNumbers[5];
            button7.Text = randomNumbers[6];
            button8.Text = randomNumbers[7];
            


        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!button2.Visible)//Jeśli przycisk obok jest niewidoczny
            {
                button2.Visible = true;//to zmieniamy go na widoczny
                button2.Text = button1.Text;//przypisujemy mu tekst z wciśniętego przyciski
                button1.Text = "";//wciśnięty przycisk dostaje pusty tekst
                button1.Visible= false;//i staje się niewidoczny
                CheckWin();

            }
            if (!button4.Visible)
            {
                button4.Visible = true;
                button4.Text = button1.Text;
                button1.Text = "";
                button1.Visible= false;
                CheckWin();
            }
        }

        

        private void button2_Click(object sender, EventArgs e)
        {
            if (!button1.Visible)
            {
                button1.Text = button2.Text;
                button1.Visible = true;
                button2.Text = "";
                button2.Visible = false;
                CheckWin();

            }
            if (!button5.Visible)
            {
                button5.Visible = true;
                button5.Text = button2.Text;
                button2.Text = "";
                button2.Visible = false;
                CheckWin();
            }
            if (!button3.Visible)
            {
                button3.Visible = true;
                button3.Text = button2.Text;
                button2.Text = "";
                button2.Visible = false;
                CheckWin();
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (!button2.Visible)
            {
                button2.Text = button3.Text;
                button2.Visible = true;
                button3.Text = "";
                button3.Visible = false;
                CheckWin();

            }
            if (!button6.Visible)
            {
                button6.Visible = true;
                button6.Text = button3.Text;
                button3.Text = "";
                button3.Visible = false;
                CheckWin();
            }
          
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (!button1.Visible)
            {
                button1.Text = button4.Text;
                button1.Visible = true;
                button4.Text = "";
                button4.Visible = false;
                CheckWin();

            }
            if (!button5.Visible)
            {
                button5.Visible = true;
                button5.Text = button4.Text;
                button4.Text = "";
                button4.Visible = false;
                CheckWin();
            }
            if (!button7.Visible)
            {
                button7.Visible = true;
                button7.Text = button4.Text;
                button4.Text = "";
                button4.Visible = false;
                CheckWin();
            }
        }

       

        private void button5_Click(object sender, EventArgs e)
        {
            if (!button2.Visible)
            {
                button2.Text = button5.Text;
                button2.Visible = true;
                button5.Text = "";
                button5.Visible = false;
                CheckWin();

            }
            if (!button4.Visible)
            {
                button4.Visible = true;
                button4.Text = button5.Text;
                button5.Text = "";
                button5.Visible = false;
                CheckWin();
            }
            if (!button6.Visible)
            {
                button6.Visible = true;
                button6.Text = button5.Text;
                button5.Text = "";
                button5.Visible = false;
                CheckWin();
            }
            if (!button8.Visible)
            {
                button8.Visible = true;
                button8.Text = button5.Text;
                button5.Text = "";
                button5.Visible = false;
                CheckWin();
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            if (!button3.Visible)
            {
                button3.Text = button6.Text;
                button3.Visible = true;
                button6.Text = "";
                button6.Visible = false;
                CheckWin();

            }
            if (!button5.Visible)
            {
                button5.Visible = true;
                button5.Text = button6.Text;
                button6.Text = "";
                button6.Visible = false;
                CheckWin();
            }
            if (!button9.Visible)
            {
                button9.Visible = true;
                button9.Text = button6.Text;
                button6.Text = "";
                button6.Visible = false;
                CheckWin();
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            if (!button4.Visible)
            {
                button4.Text = button7.Text;
                button4.Visible = true;
                button7.Text = "";
                button7.Visible = false;
                CheckWin();

            }
            if (!button8.Visible)
            {
                button8.Visible = true;
                button8.Text = button7.Text;
                button7.Text = "";
                button7.Visible = false;
                CheckWin();
            }
           
        }

        private void button8_Click(object sender, EventArgs e)
        {
            if (!button5.Visible)
            {
                button5.Text = button8.Text;
                button5.Visible = true;
                button8.Text = "";
                button8.Visible = false;
                CheckWin();

            }
            if (!button7.Visible)
            {
                button7.Visible = true;
                button7.Text = button8.Text;
                button8.Text = "";
                button8.Visible = false;
                CheckWin();
            }
            if (!button9.Visible)
            {
                button9.Visible = true;
                button9.Text = button8.Text;
                button8.Text = "";
                button8.Visible = false;
                CheckWin();
            }
        }

        private void button9_Click(object sender, EventArgs e)
        {
            if (!button8.Visible)
            {
                button8.Text = button9.Text;
                button8.Visible = true;
                button9.Text = "";
                button9.Visible = false;
                CheckWin();

            }
            if (!button6.Visible)
            {
                button6.Visible = true;
                button6.Text = button9.Text;
                button9.Text = "";
                button9.Visible = false;
                CheckWin();
            }
         
        }
        private void CheckWin()
        {
            //Jeśli przyciski są ułożone po kolei to wygrywasz
            if (button1.Text == "1" & button2.Text == "2" & button3.Text == "3" &
               button4.Text == "4" & button5.Text == "5" & button6.Text == "6" &
               button7.Text == "7" & button8.Text == "8")
                label1.Text = "Wygrana";
        }

        private void button10_Click(object sender, EventArgs e)
        {
            NewGame();
        }
    }
}


Zrzut ekranu 2022-12-27 114554.png

5

przed konstruktorem:

private Button[,] buttons;
private static Random rnd=new Random();

w konstruktorze:

buttons=new Button[3,3] {{button1,button2,button3},{button4,button5,button6},{button7,button8,button9}};
for(int y=0;y<3;++y) for(int x=0;x<3;++x) buttons[y,x].Tag=new Point(y,x);
var shuffled= "12345678 ".ToCharArray().OrderBy(num => rnd.Next()).ToArray();
for(int y=0,i=0;y<3;++y) for(int x=0;x<3;++x,++i) buttons[y,x].Text=(""+shuffled[i]).Trim();

Wszystkie klicki prowadzą do jednej metody, w której:

private void buttonAll_Click(object sender, EventArgs e)
{
  Point p=(Point)((Control)sender).Tag);
  //p.x,p.y współrzędne przycisku
  
}
0

Troche rozbudowując powyższe, lepiej to sobie zrobic dynamicznie dodając kontrolki. Na designera przeciagnij sobie tylko tableLayoutPanel1;

public Form1()
        {
            InitializeComponent();

            int width = 6;
            int height = 5;
            tableLayoutPanel1.ColumnCount = width;
            tableLayoutPanel1.RowCount = height;

            tableLayoutPanel1.ColumnStyles.Clear();
            tableLayoutPanel1.RowStyles.Clear();
            tableLayoutPanel1.Controls.Clear();

            var labels = Enumerable.Range(1, width * height)
                            .Select(o => o.ToString())
                            .OrderBy(o => random.Next())
                            .ToArray();

            var labelsIndex = 0;
            for (int x = 0; x < height; x++)
            {
                for (int y = 0; y < width; y++, labelsIndex++)
                {
                    var button = new Button { Tag = new Point(x, y), Text = labels[labelsIndex] };
                    button.Click += new System.EventHandler(this.button1_Click);
                    tableLayoutPanel1.Controls.Add(button, y, x);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var p = ((Point)((sender as Button).Tag));
            MessageBox.Show("x: " + p.X.ToString() + " y: " + p.Y.ToString());
        }

i nic nie musisz grzebać w formatce przy zmianie rozmiaru.

edit: zapomnialem o tym pustym polu.

2

Z ciekawości zobaczyłem jak chatgpt sobie z tym poradzi i dało radę ale po drodze stworzyło kilka bugów:

implement a sliding tiles puzzle in c# winforms

Sure! Here is an implementation of the sliding tiles puzzle in C# using Windows Forms:

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;

namespace TilePuzzle
{
    public partial class Form1 : Form
    {
        private const int NumTiles = 8;
        private const int GridSize = 3;
        private Button[,] buttons;
        private int[,] values;
        private Point emptyTile;

        public Form1()
        {
            InitializeComponent();

            // Create the grid of buttons
            buttons = new Button[GridSize, GridSize];
            values = new int[GridSize, GridSize];
            for (int row = 0; row < GridSize; row++)
            {
                for (int col = 0; col < GridSize; col++)
                {
                    buttons[row, col] = new Button
                    {
                        Width = 50,
                        Height = 50,
                        Left = col * 50,
                        Top = row * 50,
                        Font = new Font(FontFamily.GenericSansSerif, 20)
                    };
                    buttons[row, col].Click += new EventHandler(ButtonClick);
                    this.Controls.Add(buttons[row, col]);
                }
            }

            // Initialize the values and shuffle the tiles
            ResetGame();
        }

        // Resets the game to the initial state with tiles in order
        private void ResetGame()
        {
            for (int row = 0; row < GridSize; row++)
            {
                for (int col = 0; col < GridSize; col++)
                {
                    values[row, col] = (row * GridSize) + col + 1;
                    buttons[row, col].Text = values[row, col].ToString();
                }
            }
            values[GridSize - 1, GridSize - 1] = 0;
            buttons[GridSize - 1, GridSize - 1].Text = "";
            emptyTile = new Point(GridSize - 1, GridSize - 1);

            // Shuffle the tiles
            Random rnd = new Random();
            for (int i = 0; i < NumTiles * NumTiles; i++)
            {
                int row = rnd.Next(GridSize);
                int col = rnd.Next(GridSize);
                if (row == emptyTile.X && col == emptyTile.Y) continue;
                SwapTiles(row, col);
            }
        }

        // Swaps the tile at the specified position with the empty tile
        private void SwapTiles(int row, int col)
        {
            int temp = values[row, col];
            values[row, col] = values[emptyTile.X, emptyTile.Y];
            values[emptyTile.X, emptyTile.Y] = temp;
            buttons[row, col].Text = values[row, col].ToString();
            buttons[emptyTile.X, emptyTile.Y].Text = "";
            emptyTile = new Point(row, col);
        }

        // Event handler for button clicks
        private void ButtonClick(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            for (int row = 0; row < GridSize; row++)
            {
                for (int col = 0; col < GridSize; col++)
                {
                    if (buttons[row, col] == btn)
                    {
                        if (Math.Abs(row - emptyTile.X) + Math.Abs(col - emptyTile.Y) == 1)
                        {
                            SwapTiles(row, col);
                            CheckForWin();
                        }
                        return;
                    }
                }
            }
        }

        // Checks if the tiles are in the correct order
        private void CheckForWin()
        {
            for (int row = 0; row < GridSize; row++)
            {
                for (int col = 0; col < GridSize; col++)
                {
                    if (values[row, col] != (row * GridSize) + col + 1 && values[row, col] != 0)
                    {
                        return;
                    }
                }
            }
            MessageBox.Show("You won!");
            ResetGame();
        }
    }
}

This code should create a 3x3 grid of buttons, with 8 of the buttons having a unique number from 1 to 8 on them, and one button being empty. The tiles can be shuffled and moved by clicking on them, and the objective of the game is to arrange the tiles in ascending order from left to right and top to bottom, with the empty tile at the bottom right. The CheckForWin method checks if the tiles are in the correct order, and if they are, it displays a message and starts a new game by calling ResetGame.

I hope this helps! Let me know if you have any questions.

there's a bug in line 82 - it should be buttons[emptyTile.X, emptyTile.Y].Text = values[emptyTile.X, emptyTile.Y].ToString();

You're right, I apologize for the mistake. Here is the corrected code:

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;

namespace TilePuzzle
{
    public partial class Form1 : Form
    {
        private const int NumTiles = 8;
        private const int GridSize = 3;
        private Button[,] buttons;
        private int[,] values;
        private Point emptyTile;

        public Form1()
        {
            InitializeComponent();

            // Create the grid of buttons
            buttons = new Button[GridSize, GridSize];
            values = new int[GridSize, GridSize];
            for (int row = 0; row < GridSize; row++)
            {
                for (int col = 0; col < GridSize; col++)
                {
                    buttons[row, col] = new Button
                    {
                        Width = 50,
                        Height = 50,
                        Left = col * 50,
                        Top = row * 50,
                        Font = new Font(FontFamily.GenericSansSerif, 20)
                    };
                    buttons[row, col].Click += new EventHandler(ButtonClick);
                    this.Controls.Add(buttons[row, col]);
                }
            }

            // Initialize the values and shuffle the tiles
            ResetGame();
        }

        // Resets the game to the initial state with tiles in order
        private void ResetGame()
        {
            for (int row = 0; row < GridSize; row++)
            {
                for (int col = 0; col < GridSize; col++)
                {
                    values[row, col] = (row * GridSize) + col + 1;
                    buttons[row, col].Text = values[row, col].ToString();
                }
            }
            values[GridSize - 1, GridSize - 1] = 0;
            buttons[GridSize - 1, GridSize - 1].Text = "";
            emptyTile = new Point(GridSize - 1, GridSize - 1);

            // Shuffle the tiles
            Random rnd = new Random();
            for (int i = 0; i < NumTiles * NumTiles; i++)
            {
                int row = rnd.Next(GridSize);
                int col = rnd.Next(GridSize);
                if (row == emptyTile.X && col == emptyTile.Y) continue;
                SwapTiles(row, col);
            }
        }

        // Swaps the tile at the specified position with the empty tile
        private void SwapTiles(int row, int col)
        {
            int temp = values[row, col];
            values[row, col] = values[emptyTile.X, emptyTile.Y];
            values[emptyTile.X, emptyTile.Y] = temp;
            buttons[row, col].Text = values[row, col].ToString();
            buttons[emptyTile.X, emptyTile.Y].Text = values[emptyTile.X, emptyTile.Y].ToString();
            emptyTile = new Point(row, col);

make the empty tile invisible

To make the empty tile invisible, you can set the Visible property of the button to false when the empty tile is at a specific position. You can do this by adding the following code to the SwapTiles method:

buttons[row, col].Visible = true;
buttons[emptyTile.X, emptyTile.Y].Visible = false;

This will make the button at the position of the empty tile invisible, and make the button that was clicked visible.

Here is the updated SwapTiles method:

// Swaps the tile at the specified position with the empty tile
private void SwapTiles(int row, int col)
{
    int temp = values[row, col];
    values[row, col] = values[emptyTile.X, emptyTile.Y];
    values[emptyTile.X, emptyTile.Y] = temp;
    buttons[row, col].Text = values[row, col].ToString();
    buttons[emptyTile.X, emptyTile.Y].Text = values[emptyTile.X, emptyTile.Y].ToString();
    buttons[row, col].Visible = true;
    buttons[emptyTile.X, emptyTile.Y].Visible = false;
    emptyTile = new Point(row, col);
}

This should make the empty tile invisible when it is moved to a new position. Let me know if you have any questions.

you introduced two new bugs, it should be Visible = false for "row, col" and Visible = false" for "emptyTile.x, emptyTile.Y"

You're right, I apologize for the mistake. Here is the corrected code:

// Swaps the tile at the specified position with the empty tile
private void SwapTiles(int row, int col)
{
    int temp = values[row, col];
    values[row, col] = values[emptyTile.X, emptyTile.Y];
    values[emptyTile.X, emptyTile.Y] = temp;
    buttons[row, col].Text = values[row, col].ToString();
    buttons[emptyTile.X, emptyTile.Y].Text = values[emptyTile.X, emptyTile.Y].ToString();
    buttons[row, col].Visible = false;
    buttons[emptyTile.X, emptyTile.Y].Visible = true;
    emptyTile = new Point(row, col);
}

This should make the empty tile invisible when it is moved to a new position. Let me know if you have any questions.

0

Cześć. Tak jak pisałem wcześniej dla planszy 3x3 w miarę miałem to ogarnięte. Teraz postanowiłem ulepszyć kod o możliwość wyboru wielkości planszy. Trochę popisałem i wyszedł mi taki kod.

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.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar;

namespace przyciski1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            
        }
        static int bok1 = 4, bok2 = 4;//szerkość i wysokość planszy
        System.Windows.Forms.Button[,] buttons = new System.Windows.Forms.Button[bok1, bok2];//utworzenie tablicy z buttonami

        private void btnNewGame_Click(object sender, EventArgs e)
        {
            NewGame();
            
        }

        private void NewGame()//tworzenie nowej gry.
        {
           
            int i = 0;//pomocnicza zmienna służąca do wpisywania kolejnej liczby w polu text buttona
           
            
            for (int l = 0; l < bok2; l++)
            {

                for (int k = 0; k < bok1; k++)
                {
                    if (l == bok2 - 1 & k == bok1 - 1)//Sprawdzamy czy właśnie dodajemy przycisk o końcowych indeksach
                    {
                        //tworzymy nową kontrolkę -  button
                        System.Windows.Forms.Button nbutton = new System.Windows.Forms.Button();

                        //umieszczanie na ekranie danej kontrolki
                        nbutton.Location = new System.Drawing.Point(12 + 106 * k, 58 + 106 * l);
                        
                        //określenie rozmiarów kontrolki
                        nbutton.Size = new System.Drawing.Size(100, 100);

                        //przypisanie nazwy danej kontrolce

                        nbutton.Name = "btn" + l.ToString()+" "+k.ToString();


                        
                        nbutton.Text = "";   //wyświetlany tekst
                                                             

                        //ustawienie zdarzenia dla przycisków
                        nbutton.Click += new System.EventHandler(Nbutton_Click);

                        //dodanie kontrolek do formularza (do kolekcji - tablicy)

                        Controls.Add(nbutton);
                        nbutton.Visible= false;
                        buttons[l, k] = nbutton;
                        i++;
                    }
                    else//tworzenie przycisków dla indeksów innych niż końcowe
                    {
                        //tworzymy nową kontrolkę - textbox, button, oraz label
                        System.Windows.Forms.Button nbutton = new System.Windows.Forms.Button();

                        //umieszczanie na ekranie danej kontrolki
                        nbutton.Location = new System.Drawing.Point(12 + 106 * k, 58 + 106 * l);

                        //określenie rozmiarów kontrolki
                        nbutton.Size = new System.Drawing.Size(100, 100);

                        //przypisanie nazwy danej kontrolce

                        nbutton.Name = "btn" + l.ToString()+" "+k.ToString();


                        //konfiguracja danej kontrolki - wyswietlany tekst, ewentualne ustawienia
                        nbutton.Text = (i+1).ToString();   //nazwa przycisku
                                                             //ustawienie automatycznego dopasowania szerokości

                        //ustawienie zdarzenia dla przycisków
                        nbutton.Click += new System.EventHandler(Nbutton_Click);

                        //dodanie kontrolek do formularza (do kolekcji - tablicy)

                        Controls.Add(nbutton);
                        buttons[l, k] = nbutton;
                        i++;
                    }



                }
            }
        }

        private void Nbutton_Click(object sender, EventArgs e)
        {
            //odczytanie numeru przycisku który spowodował wywołanie tego zdarzenia
            string nrBtn = (sender as System.Windows.Forms.Button).Name.Remove(0, 3);

            int a = int.Parse(nrBtn.Split(' ')[0]);//pierwszy indeks tablicy z przyciskami
            int b = int.Parse(nrBtn.Split(' ')[1]);//drugi index tablicy z przyciskami

            if (b > 0)
            {
                if (!buttons[a, b - 1].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a, b - 1].Visible = true;//to zmieniamy go na widoczny
                    buttons[a, b - 1].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    buttons[a, b].Text = "";//wciśnięty przycisk dostaje pusty tekst
                    buttons[a, b].Visible = false;//i staje się niewidoczny
                    CheckWin();
                }
            }

            if (b < bok2-1)
            {
                if (!buttons[a, b + 1].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a, b + 1].Visible = true;//to zmieniamy go na widoczny
                    buttons[a, b + 1].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    buttons[a, b].Text = "";//wciśnięty przycisk dostaje pusty tekst
                    buttons[a, b].Visible = false;//i staje się niewidoczny
                    CheckWin();
                }
            }

            if (a > 0)
            {
                if (!buttons[a - 1, b].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a - 1, b].Visible = true;//to zmieniamy go na widoczny
                    buttons[a - 1, b].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    buttons[a, b].Text = "";//wciśnięty przycisk dostaje pusty tekst
                    buttons[a, b].Visible = false;//i staje się niewidoczny
                    CheckWin();
                }
            }

            if (a < bok1-1)
            {
                if (!buttons[a + 1, b].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a + 1, b].Visible = true;//to zmieniamy go na widoczny
                    buttons[a + 1, b].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    buttons[a, b].Text = "";//wciśnięty przycisk dostaje pusty tekst
                    buttons[a, b].Visible = false;//i staje się niewidoczny
                    CheckWin();
                }
            }







        }

        private void CheckWin()
        {
            bool win = true;
            string[] visibleText=new string[bok1*bok2];//tablica która przechowuje wyświetlany teks przycisków
            int z=0;//pomocniczy licznik 

            //w tej pętli przypisuje do tablicy visibleText poszczególne teksty z kolejnych buttonów
            for (int i = 0; i < bok1; i++)
            {
                for (int j = 0; j < bok2; j++)
                {
                    
                        visibleText[z] = buttons[i, j].Text;
                        z++;
                   

                }

            }


            //sprawdzenie czy nastąpiła wygrana
            for (int i = 0; i < bok1*bok2-1; i++)
            {
                if (visibleText[i] != (i + 1).ToString())
                    win = false;
                
            }
            if (win)
                label1.Text = "wygrana";


        }
    }
}


W porównaniu do mojego poprzedniego kodu dla planszy 3x3 gdzie dla każdego przycisku z osobna sprawdzałem czy przycisk można przesunąć tutaj zrobiłem to ogólnie dla każdego.
Przesuwanie przycisków działa, sprawdzanie wygranej również. Pozostało mi do zrobienia wymieszanie tekstu bo teraz przyciski są opisane po kolei.
Mam jeszcze problem gdy wywołam kolejny raz metodę NewGame() to przyciski się dublują...Przed rozpoczęciem nowej gry powinienem je usunąć czy można jakoś na szybko załadować pusty Form który "zapomni" o przyciskach utworzonych w poprzedniej grze?

1

@specjal1990 mam pytanie, ty w ogóle czytasz odpowiedzi?

0

Tak czytam. Ale zamiast metody kopiuj wklej z Waszych kodów postanowiłem napisać to bardziej po "swojemu". Mieszanie liczb tez już mam ogarnięte i działa dla dowolnej wielkości planszy. Nie chodziło mi o to żeby dostać od Was gotowy kod do całego programu a właśnie wskazówki jak go wykonać I myślę że się chyba udało. Czy mój kod jest jakiś tragiczny? Bo robi to co powinien ogólnie.

1

Da się sporo skrócić.

1
specjal1990 napisał(a):

. Czy mój kod jest jakiś tragiczny? Bo robi to co powinien ogólnie.

W żołnierskich słowach. Tak.
Odpowiadając żeby nie urazić, nie zrobiłeś kopiuj w klej od kolegów za to zrobiłeś kopiuj w klej samego siebie. Jest to tragiczna praktyka, jak sam zauważyłeś prosty program ma setki linii -szukałeś metody by coś z tym zrobić. W jakimkolwiek poważniejszym projekcie na setki czy tysiące plików, taka praktyka spowoduję ze zamiast nowy pisać kod, będziesz w kółko scrollował pliki poprawiając każde miejsce gdzie jest wklejka. A jeśli trafi się kilku takich agentów naraz w projekcie, to programowanie z ciekawej i przyjemnej pracy zmienia się w grupowy sado-masochizm. A że każdy średnio doświadczony programista, zmarnował tygodnie życia, na poprawianie tego typu kwiatów. To rozwiązania, kiepskie ale działające aprobaty nie zyskają.

Metodą na poprawę sytuacji jest, zamienienie wszystkich duplikacji na metody(prywatne lub lokalne) a to co się zmienia przekazać jako parametr. Prawie wszystkie miejsca gdzie masz komentarz zasługują na metodę.

Na Twoim miejscu spróbował bym tego w ramach treningu.

1

Ok może faktycznie w ramach treningu spróbuję dopieścić ten kod.
Jeszcze mam pytanie. Gdzie powinno być umieszcone wywołanie metody NewGame? Bo w tym momencie gdy kolejny raz klikne przycisk nowa gra to przyciski się duplikują.po prostu są z poprzedniej gry i dodatkowo kolejne z nowej.

0

Trochę poprawiłem kod. Jest teraz mniej powtórzeń. Nie wiem czy można jeszcze uprościć te 4 if-y? Ale w dalszym ciągu nie wiem co zrobić z dublowaniem się przycisków po kolejnym wywołaniu metody NewGame? Czy powinienem usunąć jakoś najpierw przyciski z poprzedniej gry czy jest na to inny sposób?

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.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar;

namespace przyciski1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            
        }
        static int bok1 = 3, bok2 = 3;//szerkość i wysokość planszy
        string[] randomNumbers = new string[bok1 * bok2 - 1];//tu będą wymieszane przyciski
        System.Windows.Forms.Button[,] buttons = new System.Windows.Forms.Button[bok1, bok2];//utworzenie tablicy z buttonami

        private void btnNewGame_Click(object sender, EventArgs e)
        {
            
            NewGame();
            
        }

        private void NewGame()//tworzenie nowej gry.
        {
           
            int i = 0;//pomocnicza zmienna służąca do wpisywania kolejnej liczby w polu text buttona
           
            ShuffleButtons();
           
           for (int l = 0; l < bok2; l++)
            {

                for (int k = 0; k < bok1; k++)
                {
                    

                        System.Windows.Forms.Button nbutton = new System.Windows.Forms.Button(); //tworzymy nową kontrolkę -  button

                    nbutton.Location = new System.Drawing.Point(12 + 106 * k, 58 + 106 * l);//umieszczanie na ekranie danej kontrolki

                    nbutton.Size = new System.Drawing.Size(100, 100); //określenie rozmiarów kontrolki

                    nbutton.Name = "btn" + l.ToString()+" "+k.ToString();//przypisanie nazwy danej kontrolce

                    nbutton.Click += new System.EventHandler(Nbutton_Click);//ustawienie zdarzenia dla przycisków

                    //dodanie kontrolek do formularza (do kolekcji - tablicy)

                    Controls.Add(nbutton);
                          if (l == bok2 - 1 & k == bok1 - 1)//sprawdzenie czy dodajemy ostatni przycisk
                            {
                                 nbutton.Visible = false;
                                 nbutton.Text = "";

                            }
                         else
                                 nbutton.Text = randomNumbers[i];//dla przycisków innych niż ostatni

                         buttons[l, k] = nbutton;
                        i++;                                
                }
            }
        }

        private void ShuffleButtons()
        {
            int index;
            int z = 0;
            Random rand = new Random();

            List<int> numbers = new List<int>() ;//lista liczb na przyciskach
            for (int j = 0; j < bok1*bok2-1; j++)
            {
                numbers.Add(j+1);
            }                      

            foreach (string b in randomNumbers) //pętla mieszająca tablicę liczb
            {
                index = rand.Next(0, numbers.Count);
                randomNumbers[z] = numbers[index].ToString();
                numbers.RemoveAt(index);
                z++;
            }
        }

        private void Nbutton_Click(object sender, EventArgs e)
        {
            //odczytanie numeru przycisku który spowodował wywołanie tego zdarzenia
            string nrBtn = (sender as System.Windows.Forms.Button).Name.Remove(0, 3);

            int a = int.Parse(nrBtn.Split(' ')[0]);//pierwszy indeks tablicy z przyciskami
            int b = int.Parse(nrBtn.Split(' ')[1]);//drugi index tablicy z przyciskami

            if (b > 0)
            {
                if (!buttons[a, b - 1].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a, b - 1].Visible = true;//to zmieniamy go na widoczny
                    buttons[a, b - 1].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    ChangeButtonClicked(a,b);                   
                }
            }

            if (b < bok2-1)
            {
                if (!buttons[a, b + 1].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a, b + 1].Visible = true;//to zmieniamy go na widoczny
                    buttons[a, b + 1].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    ChangeButtonClicked(a,b);
                }
            }

            if (a > 0)
            {
                if (!buttons[a - 1, b].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a - 1, b].Visible = true;//to zmieniamy go na widoczny
                    buttons[a - 1, b].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    ChangeButtonClicked(a,b);
                }
            }

            if (a < bok1-1)
            {
                if (!buttons[a + 1, b].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a + 1, b].Visible = true;//to zmieniamy go na widoczny
                    buttons[a + 1, b].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    ChangeButtonClicked(a, b);
                }
            }
        }

        private void ChangeButtonClicked(int a, int b)
        {
            buttons[a, b].Text = "";//wciśnięty przycisk dostaje pusty tekst
            buttons[a, b].Visible = false;//i staje się niewidoczny
            CheckWin();
        }

        private void CheckWin()
        {
            bool win = true;
            string[] visibleText=new string[bok1*bok2];//tablica która przechowuje wyświetlany teks przycisków
            int z=0;//pomocniczy licznik 

            //w tej pętli przypisuje do tablicy visibleText poszczególne teksty z kolejnych buttonów
            for (int i = 0; i < bok1; i++)
            {
                for (int j = 0; j < bok2; j++)
                {                    
                        visibleText[z] = buttons[i, j].Text;
                        z++;                

                }

            }


            //sprawdzenie czy nastąpiła wygrana
            for (int i = 0; i < bok1*bok2-1; i++)
            {
                if (visibleText[i] != (i + 1).ToString())
                    win = false;                
            }
            if (win)
                label1.Text = "wygrana";

        }
    }
}


0

4 razy powtórzono:

                if (!buttons[a, b - 1].Visible)//Jeśli przycisk obok jest niewidoczny
                {
                    buttons[a, b - 1].Visible = true;//to zmieniamy go na widoczny
                    buttons[a, b - 1].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                    ChangeButtonClicked(a,b);                   
                }

Zasada DRY (sprawdź w google)

Przeanalizuj to:

foreach(Size s in new Size[] { new Size(0, -1), new Size(0, +1), new Size(-1, 0), new Size(+1, 0), })
{
    Console.WriteLine(String.Format("({0},{1}) ",s.Width,s.Height));
}
0

No powtórzyłem to 4 razy ale w kazdym ifie jest inny warunek i dla kazdego inne instrukcje. Co prawda różnią sie kilkoma znakami ale jak to inaczej ugryźć?

0

Przecież dalej pokazałem jak

0

Sorry jakoś pominąłem drugą część odpowiedzi.

0

Czy powinienem usunąć jakoś najpierw przyciski z poprzedniej gry czy jest na to inny sposób?

Musisz przywrócić stan zerowy, przed każdym new game. Najcześciej robi się to w jeden z trzech sposobów.
A) brutalalnie usuwasz wszystkie obiekty, i wymuszasz oryginalny stan.
B) ładnie czyscisz istniejące obiekty i ich reuzywasz
C) Gre i UI trzymasz w klasach. Zeby ropoczac nowa gre, tworzysz nową klase UI i nową Klase Gry z czystym stanem, przypisujesz nowe obiekty w odpowiednie miejsce i zapominasz o starych.

           if (!buttons[a, b - 1].Visible)//Jeśli przycisk obok jest niewidoczny
            {
                buttons[a, b - 1].Visible = true;//to zmieniamy go na widoczny
                buttons[a, b - 1].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
                ChangeButtonClicked(a,b);      
                }

Te 4 ify robią to samo. Zawsze ustawiasz Visible, zawsze ustawiasz text zawsze wywowłujesz change. Zmienia sie tylko a,b, +/- 1 Wiec ify zostaw a ich wnetrze zamian metodami które przyjmują za paramtr a,b, oraz +/- 1.

1

Nie, jedynie użyć [a+s.y,b+s.x] oczywiście wypadało by zaprzestać autosabotażu z tymi a i b
czyli [y+s.y,x+s.x]

1

Cześć. Zmieniłem te 4 ify na coś takiego:

    if (b > 0 && !buttons[a, b - 1].Visible)
            {
                    ChangeButton(a, b, -1,0);
                
            }

            if (b < bok2 - 1 && !buttons[a, b + 1].Visible)
            {
                    ChangeButton(a, b, 1,0);               
            }

            if (a > 0 && !buttons[a - 1, b].Visible)
            {
                     ChangeButton(a, b, 0, -1);                               
            }

            if (a < (bok1 - 1) && !buttons[a + 1, b].Visible)
            {
                    ChangeButton(a, b, 0, 1);
            }
        }

        private void ChangeButton(int a, int b, int x, int y)
        {
            buttons[a+y, b + x].Visible = true;//to zmieniamy go na widoczny
            buttons[a+y, b + x].Text = buttons[a, b].Text;//przypisujemy mu tekst z wciśniętego przyciski
            buttons[a, b].Text = "";//wciśnięty przycisk dostaje pusty tekst
            buttons[a, b].Visible = false;//i staje się niewidoczny
            CheckWin();

        }

Czy mniej więcej o to chodziło? Ogólnie dzięki za wszelkie podpowiedzi i pomoc.

Czy to jest prawidłowa instrukcja aby usunąć przyciski z poprzedniej gry?

    if(buttons.Length > 0)
            {
                foreach (var item in buttons)
                {
                    Controls.Remove(item);
                }
            }

0
specjal1990 napisał(a):

Cześć. Zmieniłem te 4 ify na coś takiego:

Podałem wcześniej jak to jeszcze zmniejszyć ...

specjal1990 napisał(a):

Czy to jest prawidłowa instrukcja aby usunąć przyciski z poprzedniej gry?

A po kiego chcesz je wywalać?
Zwyczajnie wpisz inne teksty i zrób niewidocznym ten co ma ma pusty tekst.

0

Bo założenie jest takie że uzytkownik wybiera wielkość planszy.czyli np najpierw uruchamia plansze 3x3 a potem 4x4 i chyba latwiej zrobic nową plansze? Bo jeśli by wybrał nową gre z tą samą wielkością planszy to faktycznie szybciej zmienic tylko tekst.

0

Co potrzebujesz:

  1. Sprawdzić czy ułożono dobrze (wygrana) potrzebujesz prostą listę przycisków wierszami potem kolumnami.
  2. Sprawdzić czy {lewy, prawy, górny, dolny} są przyciskami pustymi
  3. Usunąć wszystkie przyciski aby zastąpić przy nowej grze oraz przy starcie.

Najbardziej do tego wszystkiego nadaje się:

  1. Zwykła tablica przycisków (ewentualnie lista) + funkcja wyszukując w tej tablice podany przycisk (foreach albo contains)
  2. Zwykła tablica przycisków (ewentualnie lista) + Tag z numerem przycisku wtedy wyliczamy Y=Tag/Size, Y=Tag%Size
  3. Zwykła tablica przycisków (ewentualnie lista) + Tag ze współrzędnymi wtedy indeks wyliczmy jako Index=Y*Size+X
0

Ogolnie jest lepiej, zastosował bym kometarz od @_13th_Dragon by nie stosowąć autosabotazu i nazwać x i y jako x i y a nie a i b, a przesunie offset albo deltaX deltaY, albo dX, dY.

Gdyby teraz przenalizować ten kod, to mamy 4 bardzo podbne if'y, i 4 bardzo podobne wywołania metod. Jedyne co się zmienia to (+/-1, +/- 1) wiec można sie pokusić o to żeby wydzielić kolejną metodę(lokalną żeby nie przekazywać a i b) , w której zmienną bedzie to (+/-1, +/- 1) i wywołać ją 4 razy dla (0, 1 ), (0, -1), (1,0) i (0,1).
Takie rozwiazanie było by tak dobre że nikt by nie narzekał.

Jeden krok dalej jest rozwiazanie sugerowane @_13th_Dragon czyi wywołujesz metode jeden raz a nie 4, a parametry przekazujesz w pętli.

Jeśli remove działa to jest dobry.

1 użytkowników online, w tym zalogowanych: 0, gości: 1