I did not bother to name this...

From Chartreuse Penguin, 1 Week ago, written in Plain Text, viewed 16 times.
URL http://codebin.org/view/bb2e12c5 Embed
Download Paste or View Raw
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace TikTakToe
  8. {
  9.     public class Program
  10.     {
  11.         // Field - Это поле, которое мы подаём на вход функции
  12.         // whoseTurn - Это переменная отвечающая за очередность хода
  13.         // Если она равна true, то следующий ход за О
  14.         // Если она равна false, то следующий ход за Х
  15.         // side - Это переменная отвечабщая за сторону, которая должна выиграть
  16.         // Если она равна -1, то  О
  17.         // Если она равна 1, то Х
  18.         public static int[,] FindSolution(int[,] Field, int[,] winField, bool whoseTurn, int side)
  19.         {
  20.             int winSide = CheckWin(Field); // Вызываем функцию, которая возращает цифру победителя (1 или -1) или 0, что показывает отсутствие победителя
  21.  
  22.             if (winSide == 0) // Если У нас нет победителя, то продолжаем искать его дальше
  23.             {
  24.  
  25.                 bool temp = false; // Иницилиазируем переменную temp
  26.                 int i = 0; // Инициализируем переменную i
  27.  
  28.                 // В Цикле ниже мы перебираем все возможные варианты, пока не найдём победный, либо они просто не закончатся
  29.                 // !temp Эквивалентна temp == false
  30.  
  31.                 while (i < 3 && !temp) // Пока Мы не достигнем конца поля по строкам (i < 3) и пока нет выигрыша !temp (Восклицательный знак перед булевой переменной означает её отрицание. Например: !true==false)
  32.                 {
  33.                     int j = 0; // Инициализация j
  34.  
  35.                     while (j < 3 && !temp) // Пока не достигнем конца поля по столбцам (i < 3 ) и пока нет выигрыша !temp
  36.                     {
  37.                         if (Field[i, j] == 0) // Если мы нашли пустую клетку в поле
  38.                         {
  39.                             bool flag = true;
  40.  
  41.                             if (whoseTurn)
  42.                             {
  43.                                 Field[i, j] = -1; // (if (whoseTurn) данная запись эквивалентна if (whoseTurn == true)) Если true (O), то мы ставим -1 (0) в данную клетку
  44.  
  45.                                 // Проверяем следующий ход на победу противника
  46.                                 int l = 0;
  47.                                 while (l < 3 && flag)
  48.                                 {
  49.                                     int k = 0;
  50.                                     while (k < 3 && flag)
  51.                                     {
  52.                                         if (Field[l, k] == 0) // проверка на возможность хода
  53.                                         {
  54.                                             Field[l, k] = 1; // устанавливаем значение хода. проверяем на победу
  55.  
  56.                                             int winSideField = CheckWin(Field);
  57.  
  58.                                             if (winSideField != 0)
  59.                                             {
  60.                                                 if (winSideField != side)
  61.                                                 {
  62.                                                     flag = false; // Если побеждает противник, значит кто ходил проиграл этим путём.
  63.                                                 }
  64.                                                 else
  65.                                                 {
  66.                                                     if (winField == null) // Если у нас нет выигрышного поля, то мы его копируем
  67.                                                         winField = Copy(Field);
  68.                                                     else
  69.                                                     {
  70.                                                         if (Count(winField) < Count(Field)) winField = Copy(Field); // Если количество свободных клеток в выигрышном поле, меньше чем текущем поле
  71.                                                     }
  72.                                                 }
  73.                                             }
  74.  
  75.                                             Field[l, k] = 0; // возращаем исходное значение
  76.                                         }
  77.                                         k++;
  78.                                     }
  79.                                     l++;
  80.                                 }
  81.                             }
  82.                             else
  83.                             {
  84.                                 Field[i, j] = 1; // иначе (Х), то мы ставим 1 (Х) в данную клетку
  85.  
  86.                                 // Проверяем следующий ход на победу противника
  87.                                 int l = 0;
  88.  
  89.                                 while (l < 3 && flag)
  90.                                 {
  91.                                     int k = 0;
  92.                                     while (k < 3 && flag)
  93.                                     {
  94.                                         if (Field[l, k] == 0)
  95.                                         {
  96.                                             Field[l, k] = -1;
  97.  
  98.                                             int winSideField = CheckWin(Field);
  99.  
  100.                                             if (winSideField != 0)
  101.                                             {
  102.                                                 if (winSideField != side)
  103.                                                 {
  104.                                                     flag = false; // Если побеждает противник, значит кто ходил проиграл этим путём.
  105.                                                 }
  106.                                                 else
  107.                                                 {
  108.                                                     if (winField == null) // Если у нас нет выигрышного поля, то мы его копируем
  109.                                                         winField = Copy(Field);
  110.                                                     else
  111.                                                     {
  112.                                                         if (Count(winField) < Count(Field)) winField = Copy(Field); // Если количество свободных клеток в выигрышном поле, меньше чем текущем поле
  113.                                                     }
  114.                                                 }
  115.                                             }
  116.  
  117.                                             Field[l, k] = 0;
  118.                                         }
  119.                                         k++;
  120.                                     }
  121.                                     l++;
  122.                                 }
  123.  
  124.                             }
  125.  
  126.                             int[,] NewField = Copy(Field); // Делаем копию нашего поля, так как массив(Матрица) Ссылочный тип, и нам приходится под него выделять новую память, чтобы сделать копию
  127.  
  128.                             whoseTurn = !whoseTurn; // Меняем игрока, который делает следующий ход.
  129.                             if (!flag) temp = false;
  130.                             else winField = FindSolution(NewField, winField, whoseTurn, side); // Отправлаем всё в рекурсию с уже новым полем изменённой стороной
  131.  
  132.                             // После выхода из рекурсии возращаем значения, которые были до входа.
  133.  
  134.                             whoseTurn = !whoseTurn; // Меняем игрока, который делает следующий ход.
  135.  
  136.                             Field[i, j] = 0; // Возращаем значение поля, чтобы продолжить перебор
  137.                         }
  138.  
  139.                         j++; // Переход в Следующий столбец
  140.                     }
  141.  
  142.                     i++; //  Переход в Следующую строку
  143.                 }
  144.  
  145.             }
  146.             else
  147.             {
  148.                 if (winSide == side) // Если победила та сторона, которая нам нужна
  149.                 {
  150.                     if (winField == null) // Если у нас нет выигрышного поля, то мы его копируем
  151.                         winField = Copy(Field);
  152.                     else
  153.                     {
  154.                         if (Count(winField) < Count(Field)) winField = Copy(Field); // Если количество свободных клеток в выигрышном поле, меньше чем текущем поле
  155.                     }
  156.                 }
  157.  
  158.             }
  159.  
  160.             return winField; // Возвращаем поле победителя
  161.         }
  162.  
  163.  
  164.         // Функция подсчёта пустых элементов в поле
  165.         private static int Count(int[,] Field)
  166.         {
  167.             int count = 0;
  168.  
  169.             // цикл foreach проходит каждый элемент в поле
  170.             foreach (int el in Field)
  171.             {
  172.                 if (el == 0) count++;
  173.             }
  174.  
  175.  
  176.             return count;
  177.         }
  178.  
  179.         //Проверка на наличие поюедителя. Функция возращает цифру победителя
  180.         // Если она равна -1, то  О
  181.         // Если она равна 1, то Х
  182.         // Если она равно 0, то победителя нет
  183.         public static int CheckWin(int[,] Field)
  184.         {
  185.             // Это условие проверяет диагонали на равенство.
  186.  
  187.             if (Field[0, 0] == Field[1, 1] && Field[1, 1] == Field[2, 2] ||
  188.                 Field[0, 2] == Field[1, 1] && Field[1, 1] == Field[2, 0] && Field[0, 0] != 0 && Field[2, 0] != 0)
  189.                 return Field[1, 1]; // Возвращаем значение середины, потому что оно принадлежит обоим диагоналям
  190.  
  191.             // Проверять Строки и столбцы
  192.  
  193.             for (int i = 0; i < 3; i++)
  194.             {
  195.                 // Инициализируем переменные
  196.                 bool tempStr = true;
  197.                 bool tempCol = true;
  198.                 int j = 0;
  199.  
  200.                 // Проверем строку. j<2, чтобы не выйти за пределы матрицы , потому что идёт сравнение j - того элемента с j+1 - ым элементом
  201.                 // если все элементы равны, то это победитель
  202.  
  203.                 while (j < 2 && tempStr) // Проверяем строку на равенство
  204.                 {
  205.                     if (Field[i, j] == Field[i, j + 1] && Field[i, j] != 0) tempStr = true; //Условие не равно 0, чтобы 0 строки не считались победителями
  206.                     else tempStr = false; // Если элементы не равны, то tempStr = false и выходим из цикла
  207.  
  208.                     j++;
  209.                 }
  210.  
  211.                 // Если мы нашли строку, то возращаем значение из неё, то есть -1 или 1 (X или О)
  212.  
  213.                 if (tempStr)
  214.                     return Field[i, j];
  215.  
  216.                 j = 0; // Обнуляем переменную
  217.  
  218.                 // Проверяем столбец на равенство  по аналогии со строкой
  219.  
  220.                 while (j < 2 && tempCol)
  221.                 {
  222.                     if (Field[j, i] == Field[j + 1, i] && Field[j, i] != 0) tempCol = true;
  223.                     else tempCol = false;
  224.  
  225.                     j++;
  226.                 }
  227.  
  228.                 if (tempCol) // Если есть победитель, то возращаем его цифру
  229.                     return Field[j, i];
  230.  
  231.  
  232.             }
  233.  
  234.             return 0; // Если победитель не найден, возвращаем 0
  235.         }
  236.  
  237.  
  238.         // Функция копирования Массива
  239.         // На вход подаётся массив, возращает новой массив.
  240.         // Это связано с особенностью хранения массива
  241.         // Чтобы скопировать массив, мы сначал должны выделить память под новый
  242.         // И по элементо скопировать туда старый
  243.         public static int[,] Copy(int[,] Field)
  244.         {
  245.             int[,] NewField = new int[3, 3]; // Создаём новый Массив
  246.  
  247.             for (int i = 0; i < Field.GetLength(0); i++)
  248.             {
  249.                 for (int j = 0; j < Field.GetLength(1); j++)
  250.                 {
  251.                     NewField[i, j] = Field[i, j]; // По элементно копируем
  252.                 }
  253.             }
  254.  
  255.             return NewField;
  256.         }
  257.  
  258.  
  259.         // Метод ввода поля
  260.         public static void InputField(int[,] Field)
  261.         {
  262.             Console.WriteLine("Введите поле через запятую. \n1 - это крестик. \n-1 - это нолик. \n0 - это неизвестность"); // Вывод текста
  263.  
  264.             for (int i = 0; i < 3; i++)
  265.             {
  266.                 Console.WriteLine($"Введите {i + 1} Строку"); // Знак $ (Доллара) перед кавычками ("") позволяет писать переменные прям в строке используя фигурные скобки ({})
  267.                 // Метод Split создает массив подстрок, разбивая входную строку по одному
  268.                 string[] str = Console.ReadLine().Split(',');
  269.  
  270.                 for (int j = 0; j < Field.GetLength(1); j++)
  271.                 {
  272.                     Field[i, j] = int.Parse(str[j]); // Преобразуем строку в число
  273.                 }
  274.             }
  275.         }
  276.  
  277.  
  278.         // Метод Вывода Поля
  279.         public static void OutPutField(int[,] Field)
  280.         {
  281.             Console.WriteLine("Состояние поля");
  282.  
  283.             for (int i = 0; i < Field.GetLength(0); i++)
  284.             {
  285.                 for (int j = 0; j < Field.GetLength(1); j++)
  286.                 {
  287.                     if (Field[i, j] == -1) Console.Write("O\t");
  288.                     else if (Field[i, j] == 1) Console.Write("X\t");
  289.                     else Console.Write(".\t");
  290.                 }
  291.                 Console.WriteLine();
  292.             }
  293.         }
  294.  
  295.         static void Main(string[] args)
  296.         {
  297.             int[,] Field = new int[3, 3]; // Создаём Матрица
  298.  
  299.             int[,] winField = null;
  300.  
  301.             InputField(Field); // Метод Ввода поля
  302.  
  303.             Console.Clear(); // Очищаем консоль после ввода
  304.  
  305.             Console.WriteLine("Начальное поле");
  306.             OutPutField(Field); // Вывод Поля в консоль
  307.  
  308.             Console.WriteLine("Выигрышная последовательность");
  309.             // В параметры функции передаём: Следуюзий ход нолика (true), ищем крестики (1)
  310.             // И передаём поле, победителя изначально оно равнается null
  311.             winField = FindSolution(Field, winField, true, -1); // Вызываем метод
  312.             if (winField != null) OutPutField(winField); // Если решение нашлось выводим
  313.             else Console.WriteLine("Решения нет");
  314.  
  315.             winField = null;
  316.  
  317.             Console.ReadLine(); // Считываем строку, чтобы не закрывалась консоль
  318.         }
  319.     }
  320. }
  321.  
  322.  
  323. using System;
  324. using Microsoft.VisualStudio.TestTools.UnitTesting;
  325. using TikTakToe;
  326.  
  327. namespace UnitTestProject1
  328. {
  329.     [TestClass]
  330.     public class UnitTest1
  331.     {
  332.         [TestMethod]
  333.         public void TestMethod1()
  334.         {
  335.             int[,] field =
  336.             {
  337.                 {-1, 1, -1},
  338.                 {0, 1, 1},
  339.                 {-1, -1, 1},
  340.             };
  341.             int[,] winField = null;
  342.             winField = Program.FindSolution(field, winField, false, 1);
  343.             // false - значит следующий ход крестика
  344.             // 1 - значит проверяем крестики
  345.             Assert.IsTrue(winField != null);
  346.         }
  347.         [TestMethod]
  348.         public void TestMethod2()
  349.         {
  350.             int[,] field =
  351.             {
  352.                 {-1, 1, -1},
  353.                 {0, 1, 1},
  354.                 {-1, -1, 1},
  355.             };
  356.             int[,] winField = null;
  357.             winField = Program.FindSolution(field, winField, false, -1);
  358.             // false - значит следующий ход крестика
  359.             // -1 - значит проверяем нолики
  360.             Assert.IsFalse(winField != null);
  361.         }
  362.         [TestMethod]
  363.         public void TestMethod3()
  364.         {
  365.             int[,] field =
  366.             {
  367.                 {1, -1, -1},
  368.                 {1, 1, 0},
  369.                 {-1, 0, 0},
  370.             };
  371.             int[,] winField = null;
  372.             winField = Program.FindSolution(field, winField, false, -1);
  373.             // false - значит следующий ход крестика
  374.             // -1 - значит проверяем нолики
  375.             Assert.IsFalse(winField != null); //у ноликов нет возможности выиграть
  376.         }
  377.  
  378.         [TestMethod]
  379.         public void TestMethod4()
  380.         {
  381.             int[,] field =
  382.             {
  383.                 {1, 0, 0},
  384.                 {0, -1, 0},
  385.                 {0, 0, 0},
  386.             };
  387.             int[,] winField = null;
  388.             winField = Program.FindSolution(field, winField, false, 1);
  389.             // false - значит следующий ход крестика
  390.             // 1 - значит проверяем крестики
  391.             Assert.IsTrue(winField != null); // у крестиков есть возможность выиграть
  392.         }
  393.         [TestMethod]
  394.         public void TestMethod5()
  395.         {
  396.             int[,] field =
  397.             {
  398.                 {1, 0, 0},
  399.                 {0, -1, 0},
  400.                 {0, 0, 0},
  401.             };
  402.             int[,] winField = null;
  403.             winField = Program.FindSolution(field, winField, false, -1);
  404.             // false - значит следующий ход крестика
  405.             // -1 - значит проверяем нолики
  406.             Assert.IsTrue(winField != null); // у ноликов есть возможность выиграть
  407.         }
  408.  
  409.         [TestMethod]
  410.         public void TestMethod6()
  411.         {
  412.             int[,] field =
  413.             {
  414.                 {1, 0, -1},
  415.                 {-1, 0, 0},
  416.                 {1, 0, 1},
  417.             };
  418.             int[,] winField = null;
  419.             winField = Program.FindSolution(field, winField, true, -1);
  420.             // true - значит следующий ход нолика
  421.             // -1 - значит проверяем нолики
  422.             Assert.IsFalse(winField != null); // у ноликов нет возможности выиграть
  423.         }
  424.         [TestMethod]
  425.         public void TestMethod7()
  426.         {
  427.             int[,] field =
  428.             {
  429.                 {1, 0, -1},
  430.                 {-1, 0, 0},
  431.                 {1, 0, 1},
  432.             };
  433.             int[,] winField = null;
  434.             winField = Program.FindSolution(field, winField, true, 1);
  435.             // true - значит следующий ход нолика
  436.             // 1 - значит проверяем крестики
  437.             Assert.IsTrue(winField != null); // у крестиков есть возможности выиграть
  438.         }
  439.  
  440.  
  441.         [TestMethod]
  442.         public void TestMethod8()
  443.         {
  444.             int[,] field =
  445.             {
  446.                 {1, -1, 1},
  447.                 {1, -1, 0},
  448.                 {-1, 0, 0},
  449.             };
  450.             int[,] winField = null;
  451.             winField = Program.FindSolution(field, winField, false, 1);
  452.             // false - значит следующий ход крестика
  453.             // 1 - значит проверяем крестики
  454.             Assert.IsFalse(winField != null); // у крестиков нет возможности выиграть
  455.         }
  456.         [TestMethod]
  457.         public void TestMethod9()
  458.         {
  459.             int[,] field =
  460.             {
  461.                 {1, -1, 1},
  462.                 {1, -1, 0},
  463.                 {-1, 0, 0},
  464.             };
  465.             int[,] winField = null;
  466.             winField = Program.FindSolution(field, winField, false, -1);
  467.             // false - значит следующий ход крестика
  468.             // -1 - значит проверяем нолики
  469.             Assert.IsTrue(winField != null); // у ноликов есть возможность выиграть
  470.         }
  471.  
  472.  
  473.         [TestMethod]
  474.         public void TestMethod10()
  475.         {
  476.             int[,] field =
  477.             {
  478.                 {1, 0, 0},
  479.                 {1, 1, -1},
  480.                 {-1, 0, -1},
  481.             };
  482.             int[,] winField = null;
  483.             winField = Program.FindSolution(field, winField, false, -1);
  484.             // false - значит следующий ход крестика
  485.             // -1 - значит проверяем нолики
  486.             Assert.IsTrue(winField != null); // у ноликов есть возможность выиграть
  487.         }
  488.         [TestMethod]
  489.         public void TestMethod11()
  490.         {
  491.             int[,] field =
  492.             {
  493.                 {1, 0, 0},
  494.                 {1, 1, -1},
  495.                 {-1, 0, -1},
  496.             };
  497.             int[,] winField = null;
  498.             winField = Program.FindSolution(field, winField, false, 1);
  499.             // false - значит следующий ход крестика
  500.             // 1 - значит проверяем крестики
  501.             Assert.IsFalse(winField != null); // у крестиков нет возможности выиграть
  502.         }
  503.  
  504.  
  505.     }
  506. }
  507.  

Reply to "I did not bother to name this..."

Here you can reply to the paste above