/*****************************************************************************************************

 * Назив програма   : Слагалица                                                                      *

 * Верзија програма : 2.0                                                                            *

 * Креиран помоћу   : SharpDevelop                                                                   *

 * Аутор програма   : Перић Жељко                                                                    *

 * Програмски језик : C#                                                                             *

 * Датум            : 25.04.2012                                                                     *

 * Време            : 13:32                                                                          *

 *                                                                                                   *

 * Опис програма : Програм 'Слагалица' је проста логичка игра уклапања дводимензионалних елемената.  *

 *                 На квадратној табли је нацртана слика, а затим је табла исечена на девет једнаких *

 *                 плочица које су насумично поређане у квадратној мрежи димензија 3х3 поља.         *

 *                 Циљ је да се слагалица реши и оригинална слика поново склопи премештањем плочица. *

 *                 Oво може да се уради на два начина.                                               *

 *                                                                                                   *

 *                 Заменом места плочицама одабиром парова плочица које замењују места.              *

 *                 Слагалица с овим начином решавања се зове 'Преметаљка'                            *

 *                                                                                                   *

 *                 Померањем плочица тзв. клизањем лево, десно, горе или доле употребом              *

 *                 слободног поља на табли.Слагалица с овим начином решавања се зове 'Клизаљка'.     *

 *                 За овај начин решавања јако је битан почетни распоред плочица, јер Слагалица      *

 *                 није решива за сваки почетни распоред. Објашњење погледајте у оквиру програма     *

 *                 у делу  'Пронађи све могуће пермутације индекса плочица'.                         *

 *                                                                                                   *

 *                                                                                                   *

 *                                                                              Све најбоље,         *

 *                                                                              Аутор                *

 *                                                                                                   *

 *****************************************************************************************************/

using System;

using System.ComponentModel;

using System.Diagnostics;

using System.Drawing;

using System.Drawing.Imaging;

using System.Windows.Forms;


namespace Слагалица

{

    public partial class MainForm : Form

    {

        #region-   Глобалне променљиве   -

        //

        // Променљива за приступ сликама смештеним у локалној датотеци унутар програма

        //

        ComponentResourceManager Слике = new ComponentResourceManager(typeof(MainForm));

        

        //

        // Бројач слика у локалној датотеци унутар програма

        //

        int Следећа_Слика_Бројач = 65;

        

        // Табела 'Плочице' садржи

        // сличице исечене из оригиналне слике

        PictureBox [] Плочице;

        

        // Табела 'Табла' садржи индексе плочица

        // и представља тренутни распоред плочица на табли

        // 

        //      1 2 3

        //

        //   1  2 3 4

        //   2  8 7 6

        //   3  5 1 9

        //

        //

        int [,] Табла;

        

        // Табела 'Почетни_Распореди_Плочица' садржи

        // све могуће пермутације индекса плочица

        string [] Почетни_Распореди_Плочица;

        

        // Једна од многобројних могућих пермутација

        //

        // Почетни распоред плочица на табли

        //

        const string Почетни_Распоред_Плочица = "123456789";

        

        // Једна од многобројних могућих пермутација

        //

        // Крајњи распоред плочица на табли

        //

        const string Крајњи_Распоред_Плочица = "123456789";

        

        // Индекс плочице која ће на табли бити замењена празном плочицом

        // и представљати празно поље на табли

        //

        // Ово је битно само у случају када играч решава Слагалицу - Клизаљку

        //

        int Индекс_Празног_Поља = 9;

        

        // Променљиве за смештање потребних

        // вредности приликом премештања плочица

        // с једне на другу позицију на табли

        //

        int Индекс_Плочице = 0;

        int Позиција_Плочице_X = 0;

        int Позиција_Плочице_Y = 0;

        

        bool Премести = false;

        #endregion

        

        public MainForm()

        {

            InitializeComponent();

            

            Иницијализуј_Табеле();

            

            Иницијализуј_Плочице();

            

            Иницијализуј_Мени();

            

            Пронађи_Све_Распореде_Плочица();

        }

        

        #region-   Иницијализација   -

        void Подеси_Видљивост_Поља(bool Видљиво, int Милисекунди)

        {

            Поље1.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље2.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље3.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље4.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље5.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље6.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље7.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље8.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

            Поље9.Visible = Видљиво;

            Refresh();

            Пауза(Милисекунди);

        }

        

        void Подеси_Видљивост_Индекса_Плочица(bool Видљиво, int Милисекунди)

        {

            Индекс1.Visible = Видљиво;

            Индекс1.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс2.Visible = Видљиво;

            Индекс2.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс3.Visible = Видљиво;

            Индекс3.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс4.Visible = Видљиво;

            Индекс4.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс5.Visible = Видљиво;

            Индекс5.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс6.Visible = Видљиво;

            Индекс6.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс7.Visible = Видљиво;

            Индекс7.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс8.Visible = Видљиво;

            Индекс8.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            Индекс9.Visible = Видљиво;

            Индекс9.BringToFront();

            Refresh();

            Пауза(Милисекунди);

            

            Refresh();

        }

        

        void Иницијализуј_Табеле()

        {

            int и;

            int ј;


            int позиција;

            

            // Табела 'Плочице' садржи

            // сличице исечене из оригиналне слике

            Плочице = new PictureBox[10];

            Плочице.Initialize();

            

            // Додели иницијалне вредности елементима у табели

            позиција = 0;

            for(позиција=0;позиција<10;позиција++)

            {

                Плочице[позиција] = new PictureBox();

                Плочице[позиција].Image = null;

            }

            

            // Табела 'Табла' садржи индексе плочица

            // и представља тренутни распоред плочица на табли

            Табла = new int [5,5];

            Табла.Initialize();

            

            // Додели иницијалне вредности елементима у табели

            и = 0;

            ј = 0;

            for(и=0;и<5;и++)

            {

                for(ј=0;ј<5;ј++)

                {

                    Табла[и,ј] = -1;

                }

            }

            

            // Табела 'Почетни_Распореди_Плочица' садржи

            // све могуће пермутације индекса плочица

            Почетни_Распореди_Плочица = new string[362880];

            Почетни_Распореди_Плочица.Initialize();

            

            // Додели иницијалне вредности елементима у табели

            и = 0;

            for(и=0;и<362880;и++)

            {

                Почетни_Распореди_Плочица[и] = null;

            }

        }

        

        void Иницијализуј_Плочице()

        {

            //

            // Исеци оригиналну слику на девет једнаких правоугаоних сличица,

            // које имају идентичне димензије и додели их елементима у табели 'Плочице'

            // Елементи табеле са својом вредношћу ће представљати Плочице

            // 

            // Поређани елементи табеле на основу индекса,

            // у доле приказаном распореду, сачињавају оригиналну слику

            // 

            //               1 2 3

            //               4 5 6

            //               7 8 9

            //

            

            // променљива за смештање оригиналне слике

            Bitmap Оригинална_Слика;

            

            // формат пиксела оригиналне слике

            PixelFormat Формат;

            

            // правоугаоник дефинисан висином, ширином и координатама једног угла

            RectangleF Плочица;

            

            int Висина_Плочице;// висина плочице у пикселима

            int Ширина_Плочице;// ширина плочице у пикселима

            

            // 

            Оригинална_Слика = new Bitmap(BackgroundImage);

            Формат = Оригинална_Слика.PixelFormat;

            

            Висина_Плочице = Оригинална_Слика.Height/3;

            Ширина_Плочице = Оригинална_Слика.Width/3;


            Плочица = new RectangleF();

            

            Плочица.Width  = Ширина_Плочице;

            Плочица.Height = Висина_Плочице;

            

            // 0. плочица, празна плочица

            Плочице[0].Image = null;

            

            // 1. плочица

            Плочица.X = 0;

            Плочица.Y = 0;

            Плочице[1].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 2. плочица

            Плочица.X = Ширина_Плочице;

            Плочица.Y = 0;

            Плочице[2].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 3. плочица

            Плочица.X = 2*Ширина_Плочице;

            Плочица.Y = 0;

            Плочице[3].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 4. плочица

            Плочица.X = 0;

            Плочица.Y = Висина_Плочице;

            Плочице[4].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 5. плочица

            Плочица.X = Ширина_Плочице;

            Плочица.Y = Висина_Плочице;

            Плочице[5].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 6. плочица

            Плочица.X = 2*Ширина_Плочице;

            Плочица.Y = Висина_Плочице;

            Плочице[6].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 7. плочица

            Плочица.X = 0;

            Плочица.Y = 2*Висина_Плочице;

            Плочице[7].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 8. плочица

            Плочица.X = Ширина_Плочице;

            Плочица.Y = 2*Висина_Плочице;

            Плочице[8].Image = Оригинална_Слика.Clone(Плочица,Формат);

            

            // 9. плочица

            Плочица.X = 2*Ширина_Плочице;

            Плочица.Y = 2*Висина_Плочице;

            Плочице[9].Image = Оригинална_Слика.Clone(Плочица,Формат);

        }

        

        void Иницијализуј_Мени()

        {

            //

            // Постави доступност опција Менија на почетну вредност

            //

            Сепаратор1.Visible = true;

            СлагалицаКлизаљка.Visible = true;

            СлагалицаПреметаљка.Visible = true;

            

            Сепаратор2.Visible = true;

            СледећаСлика.Visible = true;

            УчитајСлику.Visible = true;

            

            Сепаратор3.Visible = true;

            НоваСлагалица.Text = "Нова слагалица";

            НоваСлагалица.Visible = true;

            

            Сепаратор4.Visible = false;

            РешењеСлагалице.Visible = false;

            

            Сепаратор5.Visible = false;

            ПомоћСлагалице.Checked = false;

            ПомоћСлагалице.Visible = false;

            

            if(СлагалицаКлизаљка.Checked)

            {

                СлучајнаПозицијаПразногПоља.Visible = true;

                Сепаратор6.Visible = true;

            }

            else

            {

                СлучајнаПозицијаПразногПоља.Visible = false;

                Сепаратор6.Visible = false;

            }

            ОпцијеСлагалице.Refresh();

        }

        #endregion

        

        #region-   Пронађи све могуће пермутације индекса плочица   -

        #region-   Правила за утврђивање решивости слагалице   -

        //

        // !!! ВАЖНО !!!

        //

        // Слагалица - Клизаљка због начина решавања,

        // није решива за сваки почетни распоред плочица

        // Број инверзија унутар распореда индекса плочица омогућава да се утврди да

        // ли је слагалица овог типа решива за тај распоред или није

        //

        // Објашњење :

        // Предпоставимо да је жељени коначни распоред плочица

        //

        //                1 2 3

        //                4 5 6

        //                7 8 0

        //

        // где 0 представља празно поље које омогућава премештање плочица

        //

        // Сада, посматрамо следећи почетни распоред плочица

        //

        //                1 2 3

        //                4 5 7

        //                6 8 0

        //

        // Распоред плочица у првом реду је онако како би требало да буде

        // Други ред је добар све до броја 7 који треба да буде после броја 6

        // Ово се зове 'ИНВЕРЗИЈА' унутар распореда

        //

        // Ако је број инверзија унутар распореда плочица ПАРАН,

        // слагалица је решива за посматрани почетни распоред плочица

        //

        // Ако је број инверзија унутар распореда плочица НЕПАРАН,

        // слагалица није решива за посматрани почетни распоред плочица

        //

        // Следећи пример:

        // Посматрајмо следећи почетни распоред плочица

        //

        //                2 4 3

        //                1 0 6

        //                7 5 8

        //

        // Уочавамо следеће инверзије

        //

        //              2 долази пре 1

        //              4 долази пре 3 и 1

        //              3 долази пре 1

        //              6 долази пре 5

        //              7 долази пре 5

        //

        // Укупно 6 инверзија.Слагалица је решива за овакав почетни распоред плочица

        // приликом бројања инверзија не узима се у обзир празно поље које има број 0

        //

        //

        #endregion

        

        void Пронађи_Све_Распореде_Плочица()

        {

            //

            // Промени сличицу показивача на 'Чекај'

            //

            Cursor = Cursors.WaitCursor;

            

            //

            // Пронађи све пермутације индекса плочица

            // за девет плочица укупно 362880 пермутација

            

            // елементи прве пермутације

            const string прва_пермутација = "123456789";

            

            // елементи последње пермутације

            const string последња_пермутација = "987654321";

            

            char [] елементи;// табела за памћење нових пермутација

            int број_елемената;// број елемената унутар пермутације

            

            string пермутација = string.Empty;// нова пермутација

            

            int н = 0;// бројач пермутација унутар табеле

            int к = 0;// бројач унутар петље


            елементи = прва_пермутација.ToCharArray();

            број_елемената = прва_пермутација.Length;

            

            Почетни_Распореди_Плочица[н] = прва_пермутација; // прва пермутација

            

            do

            {

                //

                // Пронађи следећу пермутацију индекса

                //

                н++;

                к = 0;

                while (к==0)

                {

                    к = Следећа_Пермутација(ref елементи,број_елемената);

                }

                пермутација = new string(елементи);

                

                Почетни_Распореди_Плочица[н] = пермутација;

            }

            while(пермутација!=последња_пермутација);

            

            //

            // Промени сличицу показивача на 'Рука'

            //

            Cursor = Cursors.Hand;

        }


        int Следећа_Пермутација(ref char [] елементи, int број_елемената)

        {

            //

            // Оригинални алгоритам и програм за проналажење пермутација

            // Jeffrey A. Johnson, Brigham Young University-Hawaii Campus

            // http://www.freewebs.com/permute/soda_submit.html

            //

            int н = број_елемената - 1;

            int м = број_елемената - 1;

            char с = ' ';

            

            while( (н > 0) & (елементи[н] <= елементи[н-1]) )

            {

                н--;

            }

            

            н--;

            if( н < 0 )

            {

                return 0;

            }

            

            м = број_елемената - 1;

            while( (м > н) & (елементи[м] <= елементи[н]) )

            {

                м--;

            }

            

            с = елементи[н];

            елементи[н] = елементи[м];

            елементи[м] = с;

            

            број_елемената--;

            н++;

            while(број_елемената>н)

            {

                

                с = елементи[број_елемената];

                елементи[број_елемената] = елементи[н];

                елементи[н] = с;


                н++;

                број_елемената--;

            }

            return 1;

        }

        

        string Следећи_Решив_Распоред_Плочица(int индекс_празног_поља)

        {

            //

            // Пронађи следећу пермутацију индекса плочица,

            // односно почетни распоред плочица

            // 

            // Почетни распоред индекса плочица:

            //

            //  Распоред индекса        Пермутација

            //  плочица на табли

            //

            //       1 2 3               123456789

            //       4 5 6

            //       7 8 9

            //

            

            int и = 0;// бројач унутар петље

            int ј = 0;// бројач унутар петље

            int н = 0;// бројач унутар петље

            

            int број_инверзија = 0;// бројач инверзија !!!

            

            string следећи_распоред_плочица = string.Empty;

            

            bool слагалица_није_решива = true;

            

            н = Одабери_Индекс_Почетног_Распореда_Плочица();

            while(слагалица_није_решива)

            {

                н++;

                if(н==362880){н=1;}

                

                следећи_распоред_плочица = Почетни_Распореди_Плочица[н];

                //

                // Провери да ли је Слагалица - Клизаљка решива

                // за следећи_распоред_плочица

                // Преброј инверзије унутар распореда

                //

                број_инверзија = 0;

                for(и=0;и<8;и++)

                {

                    if(следећи_распоред_плочица[и].ToString()!=индекс_празног_поља.ToString())

                    {

                        for(ј=и+1;ј<9;ј++)

                        {

                            if(следећи_распоред_плочица[ј].ToString()!=индекс_празног_поља.ToString())

                            {

                                if(следећи_распоред_плочица[и]>следећи_распоред_плочица[ј])

                                {

                                    број_инверзија++;

                                }

                            }

                        }

                    }

                }

                // Паран број инверзија значи да је Слагалица решива

                if(број_инверзија%2==0)

                {

                    слагалица_није_решива = false;

                }

            }

            //

            //

            //

            return следећи_распоред_плочица;

        }

        #endregion

        

        #region- Главне методе   -

        void Промешај_Плочице()

        {

            //

            // Измешај плочице на табли 33 пута

            //

            int Бројач = 0;

            int Милисекунде = 0;

            int Индекс_Почетног_Распореда = 0;

            

            string Одабрани_Распоред = string.Empty;

            

            for(Бројач=0;Бројач<33;Бројач++)

            {

                Индекс_Почетног_Распореда = Одабери_Индекс_Почетног_Распореда_Плочица();

                Одабрани_Распоред = Почетни_Распореди_Плочица[Индекс_Почетног_Распореда];

                Додели_Индекс_Плочице_Тренутној_Позицији_На_Табли(Одабрани_Распоред);

                Постави_Плочице_На_Таблу();

                Додели_Индекс_Плочице_Пољима_За_Помоћ();

                Милисекунде = 100;

                Пауза(Милисекунде);

            }

        }

        

        int Одабери_Индекс_Празног_Поља()

        {

            //

            // Насумично, изабери индекс плочице која ће бити невидљива

            // То ће бити празно поље у оквиру Слагалице - Клизаљке

            //

            Random Генератор_Случајних_Бројева = new Random();

            

            int Индекс_Празног_Поља = 0;

            

            int Случајан_Број = 0;

            

            Случајан_Број = Генератор_Случајних_Бројева.Next(1,10);

            

            Индекс_Празног_Поља = Случајан_Број;

            

            return Индекс_Празног_Поља;

        }

        

        int Одабери_Индекс_Почетног_Распореда_Плочица()

        {

            //

            // Насумично, изабери један од могућих почетних распореда плочица

            //

            Random Генератор_Случајних_Бројева = new Random();

            

            int Индекс_Почетног_Распореда = 0;

            

            int Случајан_Број = 0;

            

            Случајан_Број = Генератор_Случајних_Бројева.Next(1,362880);

            

            Индекс_Почетног_Распореда = Случајан_Број;

            

            return Индекс_Почетног_Распореда;

        }

        

        void Додели_Индекс_Плочице_Тренутној_Позицији_На_Табли(string Пермутација)

        {

            Табла[1,1] = int.Parse(Пермутација.Substring(0,1));

            Табла[1,2] = int.Parse(Пермутација.Substring(1,1));

            Табла[1,3] = int.Parse(Пермутација.Substring(2,1));

            Табла[2,1] = int.Parse(Пермутација.Substring(3,1));

            Табла[2,2] = int.Parse(Пермутација.Substring(4,1));

            Табла[2,3] = int.Parse(Пермутација.Substring(5,1));

            Табла[3,1] = int.Parse(Пермутација.Substring(6,1));

            Табла[3,2] = int.Parse(Пермутација.Substring(7,1));

            Табла[3,3] = int.Parse(Пермутација.Substring(8,1));

        }

        

        void Додели_Индекс_Плочице_Пољима_За_Помоћ()

        {

            // 

            // Одреди тренутни распоред индекса плочица

            //

            string Тренутни_Распоред_Индекса = string.Empty;

            

            Тренутни_Распоред_Индекса =

                Табла[1,1].ToString() +

                Табла[1,2].ToString() +

                Табла[1,3].ToString() +

                Табла[2,1].ToString() +

                Табла[2,2].ToString() +

                Табла[2,3].ToString() +

                Табла[3,1].ToString() +

                Табла[3,2].ToString() +

                Табла[3,3].ToString();

            

            //

            // Промени индекс празне плочице с одабраним индексом празног поља

            // 

            if(СлагалицаКлизаљка.Checked)

            {

                Тренутни_Распоред_Индекса =

                    Тренутни_Распоред_Индекса.Replace("0",Индекс_Празног_Поља.ToString());

            }

            

            //

            // Додели тренутни индекс плочица пољима за помоћ

            //

            Индекс1.Text = Тренутни_Распоред_Индекса.Substring(0,1);

            Индекс2.Text = Тренутни_Распоред_Индекса.Substring(1,1);

            Индекс3.Text = Тренутни_Распоред_Индекса.Substring(2,1);

            Индекс4.Text = Тренутни_Распоред_Индекса.Substring(3,1);

            Индекс5.Text = Тренутни_Распоред_Индекса.Substring(4,1);

            Индекс6.Text = Тренутни_Распоред_Индекса.Substring(5,1);

            Индекс7.Text = Тренутни_Распоред_Индекса.Substring(6,1);

            Индекс8.Text = Тренутни_Распоред_Индекса.Substring(7,1);

            Индекс9.Text = Тренутни_Распоред_Индекса.Substring(8,1);

            

            Refresh();

        }


        void Постави_Плочице_На_Таблу()

        {

            //

            // На основу индекса плочице, додељеног позицији на табли

            // додели адекватну сличицу плочице

            //

            Поље1.Image = Плочице[Табла[1,1]].Image;

            Поље2.Image = Плочице[Табла[1,2]].Image;

            Поље3.Image = Плочице[Табла[1,3]].Image;

            Поље4.Image = Плочице[Табла[2,1]].Image;

            Поље5.Image = Плочице[Табла[2,2]].Image;

            Поље6.Image = Плочице[Табла[2,3]].Image;

            Поље7.Image = Плочице[Табла[3,1]].Image;

            Поље8.Image = Плочице[Табла[3,2]].Image;

            Поље9.Image = Плочице[Табла[3,3]].Image;

            

            Refresh();

        }


        void Провери_Решење()

        {

            //

            // Провери да ли је играч решио слагалицу.

            //

            string Тренутни_Распоред = string.Empty;

            

            Тренутни_Распоред =

                Табла[1,1].ToString() +

                Табла[1,2].ToString() +

                Табла[1,3].ToString() +

                Табла[2,1].ToString() +

                Табла[2,2].ToString() +

                Табла[2,3].ToString() +

                Табла[3,1].ToString() +

                Табла[3,2].ToString() +

                Табла[3,3].ToString();

            

            //

            // Промени индекс празне плочице с одабраним индексом празног поља

            // 

            if(СлагалицаКлизаљка.Checked)

            {

                Тренутни_Распоред =

                    Тренутни_Распоред.Replace("0",Индекс_Празног_Поља.ToString());

            }

            

            if(Тренутни_Распоред==Крајњи_Распоред_Плочица)

            {

                Додели_Индекс_Плочице_Тренутној_Позицији_На_Табли(Тренутни_Распоред);

                Постави_Плочице_На_Таблу();

                Refresh();

                MessageBox.Show(" Решили сте СЛАГАЛИЦУ.   ", " Браво !!!",

                                MessageBoxButtons.OK,

                                MessageBoxIcon.Information);

                

                Refresh();

                Слагалица_Је_Решена();

            }

        }

        

        void Слагалица_Је_Решена()

        {

            Cursor = Cursors.WaitCursor;

            Refresh();

            

            int Милисекунде = 0;

            

            Милисекунде = 10;

            Подеси_Видљивост_Индекса_Плочица(false, Милисекунде);

            

            Милисекунде = 150;

            Подеси_Видљивост_Поља(false, Милисекунде);

            

            Иницијализуј_Мени();

            

            Cursor = Cursors.Hand;

            Refresh();

        }

        

        void Пауза(int Милисекунде)

        {

            // Програм прави паузу за жељени број милисекунду

            Stopwatch Штоперица = new Stopwatch();

            Штоперица.Start();

            while(Штоперица.ElapsedMilliseconds<Милисекунде)

            {

                // Празна петља

            }

            Штоперица.Stop();

            Штоперица.Reset();

        }

        #endregion

        

        #region-   Прикажи могући смер померања плочице   -

        void ПољеMouseLeave(object sender, EventArgs e)

        {

            if(СлагалицаКлизаљка.Checked)

            {

                Cursor = Cursors.Hand;

            }

        }

        

        void Поље1MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(1,1);

        }


        void Поље2MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(1,2);

        }


        void Поље3MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(1,3);

        }


        void Поље4MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(2,1);

        }


        void Поље5MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(2,2);

        }


        void Поље6MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(2,3);

        }


        void Поље7MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(3,1);

        }


        void Поље8MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(3,2);

        }


        void Поље9MouseEnter(object sender, EventArgs e)

        {

            Прикажи_Смер(3,3);

        }

        

        void Прикажи_Смер(int Табла_X, int Табла_Y)

        {

            if(Табла[Табла_X,Табла_Y]!=0 && СлагалицаКлизаљка.Checked)

            {

                if(Табла[Табла_X,Табла_Y-1]==0)

                {

                    Cursor = Cursors.PanWest;

                    Refresh();

                }

                else if(Табла[Табла_X-1,Табла_Y]==0)

                {

                    Cursor = Cursors.PanNorth;

                    Refresh();

                }

                else if(Табла[Табла_X+1,Табла_Y]==0)

                {

                    Cursor = Cursors.PanSouth;

                    Refresh();

                }

                else if(Табла[Табла_X,Табла_Y+1]==0)

                {

                    Cursor = Cursors.PanEast;

                    Refresh();

                }

            }

            else if(Табла[Табла_X,Табла_Y]==0 && СлагалицаКлизаљка.Checked)

            {

                Cursor = Cursors.Hand;

                Refresh();

            }

        }

        #endregion


        #region-   Замени места плочицама   -

        void Поље1Click(object sender, EventArgs e)

        {

            Премести_Плочицу(1,1);

        }


        void Поље2Click(object sender, EventArgs e)

        {

            Премести_Плочицу(1,2);

        }


        void Поље3Click(object sender, EventArgs e)

        {

            Премести_Плочицу(1,3);

        }


        void Поље4Click(object sender, EventArgs e)

        {

            Премести_Плочицу(2,1);

        }


        void Поље5Click(object sender, EventArgs e)

        {

            Премести_Плочицу(2,2);

        }


        void Поље6Click(object sender, EventArgs e)

        {

            Премести_Плочицу(2,3);

        }


        void Поље7Click(object sender, EventArgs e)

        {

            Премести_Плочицу(3,1);

        }


        void Поље8Click(object sender, EventArgs e)

        {

            Премести_Плочицу(3,2);

        }


        void Поље9Click(object sender, EventArgs e)

        {

            Премести_Плочицу(3,3);

        }

        

        void Премести_Плочицу(int Табла_X, int Табла_Y)

        {

            if(Табла[Табла_X,Табла_Y]!=0 && СлагалицаКлизаљка.Checked)

            {

                if(Табла[Табла_X,Табла_Y-1]==0)

                {

                    Табла[Табла_X,Табла_Y-1] = Табла[Табла_X,Табла_Y];

                    Табла[Табла_X,Табла_Y] = 0;

                    Постави_Плочице_На_Таблу();

                    Додели_Индекс_Плочице_Пољима_За_Помоћ();

                    Прикажи_Смер(Табла_X,Табла_Y);

                }

                else if(Табла[Табла_X-1,Табла_Y]==0)

                {

                    Табла[Табла_X-1,Табла_Y] = Табла[Табла_X,Табла_Y];

                    Табла[Табла_X,Табла_Y] = 0;

                    Постави_Плочице_На_Таблу();

                    Додели_Индекс_Плочице_Пољима_За_Помоћ();

                    Прикажи_Смер(Табла_X,Табла_Y);

                }

                else if(Табла[Табла_X+1,Табла_Y]==0)

                {

                    Табла[Табла_X+1,Табла_Y] = Табла[Табла_X,Табла_Y];

                    Табла[Табла_X,Табла_Y] = 0;

                    Постави_Плочице_На_Таблу();

                    Додели_Индекс_Плочице_Пољима_За_Помоћ();

                    Прикажи_Смер(Табла_X,Табла_Y);

                }

                else if(Табла[Табла_X,Табла_Y+1]==0)

                {

                    Табла[Табла_X,Табла_Y+1] = Табла[Табла_X,Табла_Y];

                    Табла[Табла_X,Табла_Y] = 0;

                    Постави_Плочице_На_Таблу();

                    Додели_Индекс_Плочице_Пољима_За_Помоћ();

                    Прикажи_Смер(Табла_X,Табла_Y);

                }

                

                Провери_Решење();

            }

            else if(СлагалицаПреметаљка.Checked)

            {

                if(Премести)

                {

                    Cursor = Cursors.Hand;

                    Refresh();

                    

                    Табла[Позиција_Плочице_X, Позиција_Плочице_Y] = Табла[Табла_X, Табла_Y];

                    

                    Табла[Табла_X, Табла_Y] = Индекс_Плочице;

                    

                    Премести = false;

                    

                    Постави_Плочице_На_Таблу();

                    Додели_Индекс_Плочице_Пољима_За_Помоћ();

                    

                    Провери_Решење();

                }

                else

                {

                    Cursor = Cursors.NoMoveHoriz;

                    Refresh();

                    

                    Премести = true;

                    Позиција_Плочице_X = Табла_X;

                    Позиција_Плочице_Y = Табла_Y;

                    Индекс_Плочице = Табла[Табла_X, Табла_Y];

                }

            }

        }

        #endregion


        #region-   Опције менија слагалице   -

        void Нова_Слагалица(object sender, EventArgs e)

        {

            int Милисекунде = 0;

            int Индекс_Почетног_Распореда = 0;

            

            string Одабрани_Распоред = string.Empty;

            

            Cursor = Cursors.WaitCursor;

            Refresh();


            //

            // Промени доступност опција Менија

            //

            Сепаратор1.Visible = false;

            СлагалицаКлизаљка.Visible = false;

            СлагалицаПреметаљка.Visible = false;

            

            Сепаратор2.Visible = false;

            СледећаСлика.Visible = false;

            УчитајСлику.Visible = false;

            

            Сепаратор4.Visible = true;

            РешењеСлагалице.Visible = true;

            

            Сепаратор5.Visible = true;

            ПомоћСлагалице.Visible = true;

            

            Сепаратор6.Visible = false;

            СлучајнаПозицијаПразногПоља.Visible = false;

            

            ОпцијеСлагалице.Refresh();

            

            if(НоваСлагалица.Text == "Нова слагалица")

            {

                НоваСлагалица.Text = "Поново промешај плочице";

                

                Одабрани_Распоред = Почетни_Распоред_Плочица;

                Додели_Индекс_Плочице_Тренутној_Позицији_На_Табли(Одабрани_Распоред);

                Постави_Плочице_На_Таблу();

                Милисекунде = 300;

                Подеси_Видљивост_Поља(true, Милисекунде);

                Refresh();

            }

            

            Промешај_Плочице();

            

            if(СлучајнаПозицијаПразногПоља.Checked && СлагалицаКлизаљка.Checked)

            {

                Индекс_Празног_Поља = Одабери_Индекс_Празног_Поља();

            }

            else

            {

                Индекс_Празног_Поља = 9;

            }

            

            // Ако је Слагалица - Клизаљка

            if(СлагалицаКлизаљка.Checked)

            {

                Индекс_Почетног_Распореда = Одабери_Индекс_Почетног_Распореда_Плочица();

                Одабрани_Распоред = Следећи_Решив_Распоред_Плочица(Индекс_Празног_Поља);

                Одабрани_Распоред = Одабрани_Распоред.Replace(Индекс_Празног_Поља.ToString(),"0");

                Додели_Индекс_Плочице_Тренутној_Позицији_На_Табли(Одабрани_Распоред);

                Постави_Плочице_На_Таблу();

                Додели_Индекс_Плочице_Пољима_За_Помоћ();

            }

            

            // Ако је Слагалица - Преметаљка

            else

            {

                Индекс_Почетног_Распореда = Одабери_Индекс_Почетног_Распореда_Плочица();

                Одабрани_Распоред = Почетни_Распореди_Плочица[Индекс_Почетног_Распореда];

                Додели_Индекс_Плочице_Тренутној_Позицији_На_Табли(Одабрани_Распоред);

                Постави_Плочице_На_Таблу();

                Додели_Индекс_Плочице_Пољима_За_Помоћ();

            }

            

            Cursor = Cursors.Hand;

            Refresh();

        }

        

        void Учитај_Слику(object sender, EventArgs e)

        {

            DialogResult Избор;

            

            Избор = ДијалогУчитајСлику.ShowDialog();

            

            if( Избор == DialogResult.OK )

            {

                BackgroundImage = new Bitmap(ДијалогУчитајСлику.FileName);


                Иницијализуј_Плочице();

            }

            

            Cursor = Cursors.Hand;

            Refresh();

        }

        

        void Решење_Слагалице(object sender, EventArgs e)

        {

            Cursor = Cursors.Hand;

            Refresh();

            Слагалица_Је_Решена();

        }

        

        void Помоћ_Слагалице(object sender, EventArgs e)

        {

            int Милисекунде = 0;

            

            Cursor = Cursors.Hand;

            Refresh();

            

            //

            // Ако је ова опција одабрана,

            // приказани су индекси плочица као помоћ играчу

            //

            if(ПомоћСлагалице.Checked)

            {

                Милисекунде = 150;

                Подеси_Видљивост_Индекса_Плочица(true, Милисекунде);

            }

            else

            {

                Милисекунде = 10;

                Подеси_Видљивост_Индекса_Плочица(false, Милисекунде);

            }

        }

        

        void Следећа_Слика(object sender, EventArgs e)

        {

            Cursor = Cursors.Hand;

            Refresh();

            

            Следећа_Слика_Бројач++;

            if(Следећа_Слика_Бројач>85)

            {

                Следећа_Слика_Бројач = 1;

            }

            BackgroundImage = (System.Drawing.Image)

                (Слике.GetObject(Следећа_Слика_Бројач.ToString()));

            

            Иницијализуј_Плочице();

            

            Refresh();

        }

        

        void Слагалица_Клизаљка(object sender, EventArgs e)

        {

            Cursor = Cursors.Hand;

            Refresh();

            if(СлагалицаКлизаљка.Checked)

            {

                СлагалицаПреметаљка.Checked = false;

                MainForm.ActiveForm.Text = "   Слагалица - Клизаљка";

                Сепаратор6.Visible = true;

                СлучајнаПозицијаПразногПоља.Visible = true;

            }

            else

            {

                СлагалицаПреметаљка.Checked = true;

                MainForm.ActiveForm.Text = "   Слагалица - Преметаљка";

                Сепаратор6.Visible = false;

                СлучајнаПозицијаПразногПоља.Visible = false;

            }

        }

        

        void Слагалица_Преметаљка(object sender, EventArgs e)

        {

            Cursor = Cursors.Hand;

            Refresh();

            if(СлагалицаПреметаљка.Checked)

            {

                СлагалицаКлизаљка.Checked = false;

                MainForm.ActiveForm.Text = "   Слагалица - Преметаљка";

                Сепаратор6.Visible = false;

                СлучајнаПозицијаПразногПоља.Visible = false;

            }

            else

            {

                СлагалицаКлизаљка.Checked = true;

                MainForm.ActiveForm.Text = "   Слагалица - Клизаљка";

                Сепаратор6.Visible = true;

                СлучајнаПозицијаПразногПоља.Visible = true;

            }

        }

        #endregion

        

        #region-   Прикажи оригиналну сличицу по клику на индекс   -

        void Индекс1MouseDown(object sender, MouseEventArgs e)

        {

            Поље1.Hide();

        }

        

        void Индекс1MouseUp(object sender, MouseEventArgs e)

        {

            Поље1.Show();

        }

        

        void Индекс2MouseDown(object sender, MouseEventArgs e)

        {

            Поље2.Hide();

        }

        

        void Индекс2MouseUp(object sender, MouseEventArgs e)

        {

            Поље2.Show();

        }

        

        void Индекс3MouseDown(object sender, MouseEventArgs e)

        {

            Поље3.Hide();

        }

        

        void Индекс3MouseUp(object sender, MouseEventArgs e)

        {

            Поље3.Show();

        }

        

        void Индекс4MouseDown(object sender, MouseEventArgs e)

        {

            Поље4.Hide();

        }

        

        void Индекс4MouseUp(object sender, MouseEventArgs e)

        {

            Поље4.Show();

        }

        

        void Индекс5MouseDown(object sender, MouseEventArgs e)

        {

            Поље5.Hide();

        }

        

        void Индекс5MouseUp(object sender, MouseEventArgs e)

        {

            Поље5.Show();

        }

        

        void Индекс6MouseDown(object sender, MouseEventArgs e)

        {

            Поље6.Hide();

        }

        

        void Индекс6MouseUp(object sender, MouseEventArgs e)

        {

            Поље6.Show();

        }

        

        void Индекс7MouseDown(object sender, MouseEventArgs e)

        {

            Поље7.Hide();

        }

        

        void Индекс7MouseUp(object sender, MouseEventArgs e)

        {

            Поље7.Show();

        }

        

        void Индекс8MouseDown(object sender, MouseEventArgs e)

        {

            Поље8.Hide();

        }

        

        void Индекс8MouseUp(object sender, MouseEventArgs e)

        {

            Поље8.Show();

        }

        

        void Индекс9MouseDown(object sender, MouseEventArgs e)

        {

            Поље9.Hide();

        }

        

        void Индекс9MouseUp(object sender, MouseEventArgs e)

        {

            Поље9.Show();

        }

        #endregion

    }

}

/************************************************************************

 * Program Licence :                                                    *

 *                                                                      *

 * Copyright 2012 , Perić Željko                                        *

 * (periczeljkosmederevo@yahoo.com)                                     *

 *                                                                      *

 * According to it's main purpose , this program is licensed            *

 * under the therms of 'Free Software' licence agreement.               *

 *                                                                      *

 * If You do not know what those therms applies to                      *

 * please read explanation at the following link :                      *

 * (http://www.gnu.org/philosophy/free-sw.html.en)                      *

 *                                                                      *

 * Since it is Free Software this program has no warranty of any kind.  *

 ************************************************************************

 * Ethical Notice :                                                     *

 *                                                                      *

 * It is not ethical to change program code signed by it's author       *

 * and then to redistribute it under the same author name ,             *

 * especially if it is incorrect.                                       *

 *                                                                      *

 * It is recommended that if You make improvement in program code ,     *

 * to make remarks of it and then to sign it with Your own name ,       *

 * for further redistribution as new major version of program.          *

 *                                                                      *

 * Author name and references of old program code version should be     *

 * kept , for tracking history of program development.                  *

 *                                                                      *

 * For any further information please contact code author at his email. *

 ************************************************************************/


/************************************

 * List Of Revisions                *

 ************************************

 * Mајоr revision of version 1.0    *

 * Author 21.03.2014                *

 * New algorithm for finding        *

 * selecting and memorizing,        *

 * all solvable solutions of puzzle *

 * Visibility of Menu options are   *

 * changed, depending on selection  *

 * Help on index click developed    *

 * new comments added               *

 * New version number 2.0           *

 ************************************/