![]() |
![]() |
![]() |
|
Почему у нейронки в крестики-нолики лучший ход всегда в 0? | ☑ | ||
---|---|---|---|---|
0
program345
01.08.25
✎
17:32
|
привет!
Код модуля формы: &НаКлиенте Перем КоличествоПолей; // 3x3 //Перем КоличествоПолей = 9; // 3x3 &НаКлиенте Перем Веса; // Массив весов нейронной сети &НаКлиенте Перем Ввод; // Массив весов нейронной сети // Инициализация нейронной сети &НаКлиенте Процедура ИнициализироватьСеть() Веса = Новый Массив(КоличествоПолей); Для i = 0 По КоличествоПолей-1 Цикл Веса[i] = СлучайноеЧисло(0, 1); // Инициализация случайными весами КонецЦикла; КонецПроцедуры &НаКлиенте Функция СлучайноеЧисло(Число1,Число2) ГСЧ = Новый ГенераторСлучайныхЧисел; Возврат ГСЧ.СлучайноеЧисло(Число1,Число2); КонецФункции // () // Функция активации (ReLU) &НаКлиенте Функция ReLU(х) Возврат Макс(0, х); КонецФункции // Получить лучший ход на основе текущего состояния &НаКлиенте Функция ПолучитьЛучшийХод(СостояниеДоски) ЛучшийХод = -1; МаксОценка = -9999; Для i = 0 По КоличествоПолей-1 Цикл Если СостояниеДоски[i] = 0 Тогда // Если клетка свободна Оценка = 0; Для j = 0 По КоличествоПолей-1 Цикл Оценка = Оценка + Веса[j] * СостояниеДоски[j]; КонецЦикла; Оценка = Оценка + Веса[i] * 1; // Предполагаем наш ход в эту клетку Оценка = ReLU(Оценка); Если Оценка > МаксОценка Тогда МаксОценка = Оценка; ЛучшийХод = i; КонецЕсли; КонецЕсли; КонецЦикла; Возврат ЛучшийХод; КонецФункции // Обновление весов на основе результата игры &НаКлиенте Процедура ОбновитьВеса(СостояниеДоски, ВыбранныйХод, Результат, СкоростьОбучения = 0.1) // Вычисляем целевую оценку ЦелеваяОценка = Результат; // 1 - победа, 0 - ничья, -1 - поражение // Предсказанная оценка до обучения Предсказание = 0; Для i = 0 По КоличествоПолей-1 Цикл Предсказание = Предсказание + Веса[i] * СостояниеДоски[i]; КонецЦикла; Предсказание = ReLU(Предсказание); // Ошибка Ошибка = ЦелеваяОценка - Предсказание; // Обновляем веса Для i = 0 По КоличествоПолей-1 Цикл Веса[i] = Веса[i] + СкоростьОбучения * Ошибка * СостояниеДоски[i]; КонецЦикла; Веса[ВыбранныйХод] = Веса[ВыбранныйХод] + СкоростьОбучения * Ошибка * 1; КонецПроцедуры // Проверка победы &НаКлиенте Функция ПроверитьПобеду(Доска, Игрок) // Горизонтальные линии Если (Доска[0] = Игрок И Доска[1] = Игрок И Доска[2] = Игрок) Или (Доска[3] = Игрок И Доска[4] = Игрок И Доска[5] = Игрок) Или (Доска[6] = Игрок И Доска[7] = Игрок И Доска[8] = Игрок) Тогда Возврат Истина; КонецЕсли; // Вертикальные линии Если (Доска[0] = Игрок И Доска[3] = Игрок И Доска[6] = Игрок) Или (Доска[1] = Игрок И Доска[4] = Игрок И Доска[7] = Игрок) Или (Доска[2] = Игрок И Доска[5] = Игрок И Доска[8] = Игрок) Тогда Возврат Истина; КонецЕсли; // Диагонали Если (Доска[0] = Игрок И Доска[4] = Игрок И Доска[8] = Игрок) Или (Доска[2] = Игрок И Доска[4] = Игрок И Доска[6] = Игрок) Тогда Возврат Истина; КонецЕсли; Возврат Ложь; КонецФункции // Проверка ничьи &НаКлиенте Функция ПроверитьНичью(Доска) Для i = 0 По КоличествоПолей-1 Цикл Если Доска[i] = 0 Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; КонецФункции // Процедура обучения &НаКлиенте Процедура ОбучитьНейронку(КоличествоЭпох = 10000) ИнициализироватьСеть(); Для эпоха = 1 По КоличествоЭпох Цикл Доска = Новый Массив(КоличествоПолей); Для i = 0 По КоличествоПолей-1 Цикл Доска[i] = 0; // 0 - пусто, 1 - X, -1 - O КонецЦикла; Ход = 1; // 1 - X (нейронка), -1 - O (оппонент) Пока Истина Цикл Если Ход = 1 Тогда // Ход нейронки ЛучшийХод = ПолучитьЛучшийХод(Доска); Если ЛучшийХод = -1 Тогда Прервать; // Нет доступных ходов КонецЕсли; Доска[ЛучшийХод] = 1; Если ПроверитьПобеду(Доска, 1) Тогда ОбновитьВеса(Доска, ЛучшийХод, 1); // Победа Прервать; ИначеЕсли ПроверитьНичью(Доска) Тогда ОбновитьВеса(Доска, ЛучшийХод, 0); // Ничья Прервать; КонецЕсли; Иначе // Ход оппонента (случайный) СвободныеКлетки = Новый Массив; Для i = 0 По КоличествоПолей-1 Цикл Если Доска[i] = 0 Тогда СвободныеКлетки.Добавить(i); КонецЕсли; КонецЦикла; Если СвободныеКлетки.Количество() = 0 Тогда Прервать; КонецЕсли; СлучайныйХод = СвободныеКлетки[СлучайноеЧисло(0, СвободныеКлетки.Количество()-1)]; Доска[СлучайныйХод] = -1; Если ПроверитьПобеду(Доска, -1) Тогда ОбновитьВеса(Доска, ЛучшийХод, -1); // Поражение Прервать; ИначеЕсли ПроверитьНичью(Доска) Тогда ОбновитьВеса(Доска, ЛучшийХод, 0); // Ничья Прервать; КонецЕсли; КонецЕсли; Ход = -Ход; // Смена хода КонецЦикла; КонецЦикла; Сообщить("Обучение завершено!"); КонецПроцедуры // Пример игры против обученной нейронки &НаКлиенте Процедура ИгратьПротивНейронки() Доска = Новый Массив(КоличествоПолей); Для i = 0 По КоличествоПолей-1 Цикл Доска[i] = 0; КонецЦикла; Ход = 1; // 1 - нейронка (X), -1 - игрок (O) Пока Истина Цикл // Отображаем доску СтрокаДоски = ""; Для i = 0 По 8 Цикл Если Доска[i] = 1 Тогда СтрокаДоски = СтрокаДоски + "X"; ИначеЕсли Доска[i] = -1 Тогда СтрокаДоски = СтрокаДоски + "O"; Иначе СтрокаДоски = СтрокаДоски + i; КонецЕсли; Если (i+1) % 3 = 0 Тогда СтрокаДоски = СтрокаДоски + Символы.ПС; Иначе СтрокаДоски = СтрокаДоски + "|"; КонецЕсли; КонецЦикла; Сообщить(СтрокаДоски); Если Ход = 1 Тогда // Ход нейронки ЛучшийХод = ПолучитьЛучшийХод(Доска); Если ЛучшийХод = -1 Тогда Сообщить("Ничья!"); Возврат; КонецЕсли; Доска[ЛучшийХод] = 1; Сообщить("Нейронка походила в клетку " + ЛучшийХод); Если ПроверитьПобеду(Доска, 1) Тогда Сообщить("Нейронка победила!"); Возврат; ИначеЕсли ПроверитьНичью(Доска) Тогда Сообщить("Ничья!"); Возврат; КонецЕсли; Иначе // Ход игрока Сообщить("Ваш ход (введите номер клетки 0-8):"); ВвестиЧислоМодально = ВвестиЧисло(Ввод); Если Не ВвестиЧислоМодально Тогда Пока Ввод < 0 Или Ввод > 8 Или Доска[Ввод] <> 0 Цикл Сообщить("Некорректный ход. Попробуйте еще раз:"); ВвестиЧислоМодально = ВвестиЧисло(Ввод); КонецЦикла; КонецЕсли; Доска[Ввод] = -1; Если ПроверитьПобеду(Доска, -1) Тогда Сообщить("Вы победили!"); Возврат; ИначеЕсли ПроверитьНичью(Доска) Тогда Сообщить("Ничья!"); Возврат; КонецЕсли; КонецЕсли; Ход = -Ход; // Смена хода КонецЦикла; КонецПроцедуры // Запуск обучения и игры &НаКлиенте Процедура Главная() ОбучитьНейронку(10000); // Обучаем на 10,000 играх ИгратьПротивНейронки(); // Играем против обученной нейронки КонецПроцедуры &НаКлиенте Процедура ОбучитьНейронку_1(Команда) ОбучитьНейронку(); КонецПроцедуры &НаКлиенте Процедура ИгратьПротивНейронки_2(Команда) ИгратьПротивНейронки(); КонецПроцедуры КоличествоПолей =9; Что мне кажется тут где-то ошибка в лучшем коде или все верно?
|
|||
1
OldCondom
02.08.25
✎
14:12
|
Ошибка где-то в лучшем коде или вам кажется. Возможно, все верно.
|
|||
2
Greeen
02.08.25
✎
21:45
|
Лучше уберите этот код из открытого доступа, иначе этот ИИ сможет развиться и уничтожить человечество
|
|||
3
Волшебник
02.08.25
✎
21:46
|
Если противник первым ходом поставил в центр, то надо ставить в угол, иначе проиграешь
|
|||
4
b_ru
03.08.25
✎
01:00
|
(3) Если противник первым ходом поставил в центре, то он уже не выиграл.
|
|||
5
Волшебник
03.08.25
✎
15:49
|
(4) Если после первого хода противника в центр вы поставите в боковушечку, то вы уже проиграли
|
|||
6
Chai Nic
03.08.25
✎
10:26
|
(2) Раньше это называли "метод Монте-Карло", а теперь "нейросеть")
|
|||
7
Волшебник
03.08.25
✎
20:19
|
(4) Вы не понимаете, что крестики-нолики - это ничья? Вы совсем дурак и в школе не учились? Вы вообще хоть раз проигрывали в крестики-нолики? Если да, то я вам так скажу: когда вы перестали проигрывать в крестики-нолики без поддавков, тогда вы стали программистом. А потом вы начали поддаваться и ребёнок начал иногда выигрывать. Так вы стали родителем, то есть начали программировать новых программистов.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |