Принятие решений нейронной сети в игре крестики нолики - C#
Формулировка задачи:
Собственно есть нейронная сеть(слизанная с хабра), там нейронная сеть была предназначена для распознавания изображений, то есть использовались двухмерные массивы я заменил его на одно мерный так как поле в крестики нолики можно записать в одну строку. Суть проблемы принятие решений нейронной сети по факту она их принимает ^_^, но как сделать так что бы она стремилась к победе.
using System; namespace GA { class Program { static Random _random = new Random(); public static int length = 9; // Колличество входных параметров public class Neuron { public int[] weight; // Веса нейронов public int minimum = 50; // Порог /** * Конструктор нейрона, создает веси и устанавливает случайные значения */ public Neuron() { weight = new int[length]; randomizeWeights(); } /** * ответы нейронов, жесткая пороговая * @param input - входной вектор * @return ответ 0 или 1 */ public int transferHard(int[] input) { int Power = 0; for (int r = 0; r < length; r++) { Power += weight[r] * input[r]; } //Debug.Log("Power: " + Power); return Power >= minimum ? 1 : 0; } /** * ответы нейронов с вероятностями * @param input - входной вектор * @return n вероятность */ public int transfer(int[] input) { int Power = 0; for (int r = 0; r < length; r++) Power += weight[r] * input[r]; //Debug.Log("Power: " + Power); return Power; } void randomizeWeights() { for (int r = 0; r < length; r++) weight[r] = _random.Next(0, 10); } /** * изменяет веса нейронов * @param input - входной вектор * @param d - разница между выходом нейрона и нужным выходом */ public void changeWeights(int[] input, int d) { for (int r = 0; r < length; r++) weight[r] += d * input[r]; } } public class NeuralNetwork { public Neuron[] neurons; /** * Конструктор сети создает нейроны */ public NeuralNetwork() { neurons = new Neuron[10]; for (int i = 0; i < neurons.Length; i++) neurons[i] = new Neuron(); } /** * Функция распознавания символа, используется для обучения * @param input - входной вектор * @return массив из нуллей и единиц, ответы нейронов */ int[] handleHard(int[] input) { int[] output = new int[neurons.Length]; for (int i = 0; i < output.Length; i++) output[i] = neurons[i].transferHard(input); return output; } /** * Функция распознавания, используется для конечново ответа * @param input - входной вектор * @return массив из вероятностей, ответы нейронов */ int[] handle(int[] input) { int[] output = new int[neurons.Length]; for (int i = 0; i < output.Length; i++) output[i] = neurons[i].transfer(input); return output; } /** * Ответ сети * @param input - входной вектор * @return индекс нейронов предназначенный для конкретного символа */ public int getAnswer(int[] input) { int[] output = handle(input); int maxIndex = 0; for (int i = 1; i < output.Length; i++) if (output[i] > output[maxIndex]) maxIndex = i; return maxIndex; } /** * Функция обучения * @param input - входной вектор * @param correctAnswer - правильный ответ */ public void study(int[] input, int correctAnswer) { int[] correctOutput = new int[neurons.Length]; correctOutput[correctAnswer] = 1; int[] output = handleHard(input); while (!compareArrays(correctOutput, output)) { for (int i = 0; i < neurons.Length; i++) { int dif = correctOutput[i] - output[i]; neurons[i].changeWeights(input, dif); } output = handleHard(input); } } /** * Сравнение двух вектор * @param true - если массивы одинаковые, false - если нет */ bool compareArrays(int[] a, int[] b) { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false; return true; } } private static void Main(string[] args) { NeuralNetwork nw = new NeuralNetwork(); int[] table = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var win = false; while (!win) { #region PlayerInput int x; do { input: Console.Write("Введите номер клетки где поставить крестик: "); try { x = Convert.ToInt16(Console.ReadLine()); } catch (Exception ex) { goto input; } } while (table[x-1] == 1 || table[x-1] == 2); table[x - 1] = 1; #endregion if (table[0] == 1 && table[1] == 1 && table[2] == 1 || table[0] == 2 && table[1] == 2 && table[2] == 2 || table[3] == 1 && table[4] == 1 && table[5] == 1 || table[3] == 2 && table[4] == 2 && table[5] == 2 || table[6] == 1 && table[7] == 1 && table[8] == 1 || table[6] == 2 && table[7] == 2 && table[8] == 2 || table[0] == 1 && table[4] == 1 && table[8] == 1 || table[0] == 2 && table[4] == 2 && table[8] == 2 || table[2] == 1 && table[4] == 1 && table[6] == 1 || table[2] == 2 && table[4] == 2 && table[6] == 2 || table[0] == 1 && table[3] == 1 && table[6] == 1 || table[0] == 2 && table[3] == 2 && table[6] == 2 || table[1] == 1 && table[4] == 1 && table[7] == 1 || table[1] == 2 && table[4] == 2 && table[7] == 2 || table[2] == 1 && table[5] == 1 && table[8] == 1 || table[2] == 2 && table[5] == 2 && table[8] == 2) { win = true; } else { #region WriteTable for (int i = 0; i < table.Length; i++) { Console.Write(table[i] == 1 ? "X" : table[i] == 2 ? "O" : "-"); if ((i + 1)%3 == 0 && i != 0) { Console.WriteLine(); } } Console.WriteLine(); #endregion #region NeuralNetwork int o; do { nw.study(table, _random.Next(0, 9)); o = nw.getAnswer(table); } while (table[o] == 1 || table[o] == 2); table[o] = 2; #endregion if (table[0] == 1 && table[1] == 1 && table[2] == 1 || table[0] == 2 && table[1] == 2 && table[2] == 2 || table[3] == 1 && table[4] == 1 && table[5] == 1 || table[3] == 2 && table[4] == 2 && table[5] == 2 || table[6] == 1 && table[7] == 1 && table[8] == 1 || table[6] == 2 && table[7] == 2 && table[8] == 2 || table[0] == 1 && table[4] == 1 && table[8] == 1 || table[0] == 2 && table[4] == 2 && table[8] == 2 || table[2] == 1 && table[4] == 1 && table[6] == 1 || table[2] == 2 && table[4] == 2 && table[6] == 2 || table[0] == 1 && table[3] == 1 && table[6] == 1 || table[0] == 2 && table[3] == 2 && table[6] == 2 || table[1] == 1 && table[4] == 1 && table[7] == 1 || table[1] == 2 && table[4] == 2 && table[7] == 2 || table[2] == 1 && table[5] == 1 && table[8] == 1 || table[2] == 2 && table[5] == 2 && table[8] == 2) { win = true; } #region WriteTable for (int i = 0; i < table.Length; i++) { Console.Write(table[i] == 1 ? "X" : table[i] == 2 ? "O" : "-"); if ((i + 1)%3 == 0 && i != 0) { Console.WriteLine(); } } Console.WriteLine(); #endregion } } Console.WriteLine("Кто-то кого-то нагнул."); Console.ReadKey(); } } }
Решение задачи: «Принятие решений нейронной сети в игре крестики нолики»
textual
Листинг программы
using System; using System.Windows.Forms; namespace NeuralNetwork { public partial class Form1 : Form { #region NeuralNetwork private static Random _random = new Random(); public static int length = 9; // Колличество входных параметров public class Neuron { public int[] weight; // Веса нейронов public int minimum = 50; // Порог /** * Конструктор нейрона, создает веси и устанавливает случайные значения */ public Neuron() { weight = new int[length]; randomizeWeights(); } /** * ответы нейронов, жесткая пороговая * @param input - входной вектор * @return ответ 0 или 1 */ public int transferHard(int[] input) { int Power = 0; for (int r = 0; r < length; r++) { Power += weight[r]*input[r]; } //Debug.Log("Power: " + Power); return Power >= minimum ? 1 : 0; } /** * ответы нейронов с вероятностями * @param input - входной вектор * @return n вероятность */ public int transfer(int[] input) { int Power = 0; for (int r = 0; r < length; r++) Power += weight[r]*input[r]; //Debug.Log("Power: " + Power); return Power; } private void randomizeWeights() { for (int r = 0; r < length; r++) weight[r] = _random.Next(0, 10); } /** * изменяет веса нейронов * @param input - входной вектор * @param d - разница между выходом нейрона и нужным выходом */ public void changeWeights(int[] input, int d) { for (int r = 0; r < length; r++) weight[r] += d*input[r]; } } public class NeuralNetwork { public Neuron[] neurons; /** * Конструктор сети создает нейроны */ public NeuralNetwork() { neurons = new Neuron[9]; for (int i = 0; i < neurons.Length; i++) neurons[i] = new Neuron(); } /** * Функция распознавания символа, используется для обучения * @param input - входной вектор * @return массив из нуллей и единиц, ответы нейронов */ private int[] handleHard(int[] input) { int[] output = new int[neurons.Length]; for (int i = 0; i < output.Length; i++) output[i] = neurons[i].transferHard(input); return output; } /** * Функция распознавания, используется для конечново ответа * @param input - входной вектор * @return массив из вероятностей, ответы нейронов */ private int[] handle(int[] input) { int[] output = new int[neurons.Length]; for (int i = 0; i < output.Length; i++) output[i] = neurons[i].transfer(input); return output; } /** * Ответ сети * @param input - входной вектор * @return индекс нейронов предназначенный для конкретного символа */ public int getAnswer(int[] input) { int[] output = handle(input); int maxIndex = 0; for (int i = 1; i < output.Length; i++) if (output[i] > output[maxIndex]) maxIndex = i; return maxIndex; } /** * Функция обучения * @param input - входной вектор * @param correctAnswer - правильный ответ */ public void study(int[] input, int correctAnswer) { int[] correctOutput = new int[neurons.Length]; correctOutput[correctAnswer] = 1; int[] output = handleHard(input); while (!compareArrays(correctOutput, output)) { for (int i = 0; i < neurons.Length; i++) { int dif = correctOutput[i] - output[i]; neurons[i].changeWeights(input, dif); } output = handleHard(input); } } /** * Сравнение двух вектор * @param true - если массивы одинаковые, false - если нет */ private bool compareArrays(int[] a, int[] b) { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false; return true; } } #endregion private NeuralNetwork nw = new NeuralNetwork(); private int[] _table = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; public Form1() { InitializeComponent(); #region Начальное обучение. Основанное на рандоме. for (int i = 0; i < 4608; i++) { answer1: int a = _random.Next(0, 9); if (_table[a] != 1 && _table[a] != 2) _table[a] = 1; else goto answer1; CheckWin(); answer: int answer = nw.getAnswer(_table); if (_table[answer] != 1 && _table[answer] != 2) { _table[answer] = 2; if (answer == 0) button1.Text = @"O"; if (answer == 1) button2.Text = @"O"; if (answer == 2) button3.Text = @"O"; if (answer == 3) button4.Text = @"O"; if (answer == 4) button5.Text = @"O"; if (answer == 5) button6.Text = @"O"; if (answer == 6) button7.Text = @"O"; if (answer == 7) button8.Text = @"O"; if (answer == 8) button9.Text = @"O"; CheckWin(); } else { int index = _random.Next(0, 9); nw.study(_table, index); goto answer; } } TableEmpty(); textBox1.Text = String.Empty; #endregion } public void CheckWin() { if (_table[0] == 1 && _table[1] == 1 && _table[2] == 1 || _table[3] == 1 && _table[4] == 1 && _table[5] == 1 || _table[6] == 1 && _table[7] == 1 && _table[8] == 1 || _table[0] == 1 && _table[4] == 1 && _table[8] == 1 || _table[2] == 1 && _table[4] == 1 && _table[6] == 1 || _table[0] == 1 && _table[3] == 1 && _table[6] == 1 || _table[1] == 1 && _table[4] == 1 && _table[7] == 1 || _table[2] == 1 && _table[5] == 1 && _table[8] == 1) { textBox1.Text += @"Вы победили "; nw.study(_table, _random.Next(0, 9)); TableEmpty(); } else { if (_table[0] == 2 && _table[1] == 2 && _table[2] == 2 || _table[3] == 2 && _table[4] == 2 && _table[5] == 2 || _table[6] == 2 && _table[7] == 2 && _table[8] == 2 || _table[0] == 2 && _table[4] == 2 && _table[8] == 2 || _table[2] == 2 && _table[4] == 2 && _table[6] == 2 || _table[0] == 2 && _table[3] == 2 && _table[6] == 2 || _table[1] == 2 && _table[4] == 2 && _table[7] == 2 || _table[2] == 2 && _table[5] == 2 && _table[8] == 2) { textBox1.Text += @"Победила нейронная сеть "; nw.study(_table, _random.Next(0, 9)); TableEmpty(); } else { int counter = 0; for (int i = 0; i < _table.Length; i++) { if (_table[i] != 1 && _table[i] != 2) counter++; } if (counter == 0) { textBox1.Text += @"Ничья! "; nw.study(_table, _random.Next(0, 9)); TableEmpty(); } } } } #region Кнопки private void button1_Click(object sender, EventArgs e) { if (_table[0] != 1 && _table[0] != 2) { _table[0] = 1; button1.Text = @"X"; CheckWin(); Answer(); } } private void button2_Click(object sender, EventArgs e) { if (_table[1] != 1 && _table[1] != 2) { _table[1] = 1; button2.Text = @"X"; CheckWin(); Answer(); } } private void button3_Click(object sender, EventArgs e) { if (_table[2] != 1 && _table[2] != 2) { _table[2] = 1; button3.Text = @"X"; CheckWin(); Answer(); } } private void button4_Click(object sender, EventArgs e) { if (_table[3] != 1 && _table[3] != 2) { _table[3] = 1; button4.Text = @"X"; CheckWin(); Answer(); } } private void button5_Click(object sender, EventArgs e) { if (_table[4] != 1 && _table[4] != 2) { _table[4] = 1; button5.Text = @"X"; CheckWin(); Answer(); } } private void button6_Click(object sender, EventArgs e) { if (_table[5] != 1 && _table[5] != 2) { _table[5] = 1; button6.Text = @"X"; CheckWin(); Answer(); } } private void button7_Click(object sender, EventArgs e) { if (_table[6] != 1 && _table[6] != 2) { _table[6] = 1; button7.Text = @"X"; CheckWin(); Answer(); } } private void button8_Click(object sender, EventArgs e) { if (_table[7] != 1 && _table[7] != 2) { _table[7] = 1; button8.Text = @"X"; CheckWin(); Answer(); } } private void button9_Click(object sender, EventArgs e) { if (_table[8] != 1 && _table[8] != 2) { _table[8] = 1; button9.Text = @"X"; CheckWin(); Answer(); } } #endregion public void TableEmpty() { _table = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; button1.Text = ""; button2.Text = ""; button3.Text = ""; button4.Text = ""; button5.Text = ""; button6.Text = ""; button7.Text = ""; button8.Text = ""; button9.Text = ""; } public void Answer() { answer: int answer = nw.getAnswer(_table); if (_table[answer] != 1 && _table[answer] != 2) { _table[answer] = 2; if (answer == 0) button1.Text = @"O"; if (answer == 1) button2.Text = @"O"; if (answer == 2) button3.Text = @"O"; if (answer == 3) button4.Text = @"O"; if (answer == 4) button5.Text = @"O"; if (answer == 5) button6.Text = @"O"; if (answer == 6) button7.Text = @"O"; if (answer == 7) button8.Text = @"O"; if (answer == 8) button9.Text = @"O"; CheckWin(); } else { int index = _random.Next(0, 9); nw.study(_table, index); goto answer; } } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д