Принятие решений нейронной сети в игре крестики нолики - 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;
}
}
}
}