Tic-Tac-латинский!
Это правдивая история, поэтому имена были изменены.
Мой латинский учитель, мистер Латино, создал свой собственный (без шуток) вариант «крестики-нолики». Давайте назовем это тик-так-латин. Игра проста, по сути, это крестики-нолики, сыгранные по четыре на четыре.
Официальное объявление правила
Линия - это либо строка, столбец или диагональ. Есть два символа, «X» и «O», но один или оба могут быть заменены другим символом.
Вы получаете одно очко, когда у вас есть три символа и один другой персонаж.
Эти договоренности оценивают:
--- O -O-- XXXO XOOX O -XX - О - - Х - --- O
Это не оценка:
---- XXXX ---- ОООО ---- xxx- ---- OOO-
Игра выигрывается, когда у одного игрока больше очков, чем у другого. Игра является ничьей, только если доска заполнена.
Вызов
Решите эту игру. Ваша задача состоит в том, чтобы обеспечить способ гарантировать победу или ничью, в зависимости от того, какой результат является оптимальным.
Ваше решение может выбрать начало или второе (и поэтому может выбрать его символ). Не обязательно реализовывать интерактивную игру, в которой пользовательский ввод перемещается, а соответствующий дисплей изменяется. Это также может быть функция или программа, которая принимает входные данные в качестве игрового состояния и выводит новую доску или описание их хода . Любой из вариантов должен быть запущен в течение примерно десяти секунд за каждый сделанный ход
Игра вашего игрока против любой последовательности ходов должна дать оптимальный результат. Это означает, что вы можете предполагать, что входная позиция является той, которую она достигла из игры с вашим игроком. Материалы должны быть детерминированными и не обязательно должны содержать доказательство оптимальности, но если они будут взломаны (будучи избитыми), ваши материалы будут считаться недействительными (вы можете оставить это, но добавьте (взломали) в заголовок).
Это нетривиальное задание, поэтому любая действительная заявка впечатляет и заслуживает принятой галочки, но я сделаю код гольф основным критерием выигрыша.
Победитель выбирается по списку, пока не будет выбран один победитель.
- Кратчайшая решаемая реализация, которая всегда выигрывает
- Кратчайшая реализация
Ответы:
Perl, 147 байт (не конкурирует, занимает больше 10 секунд за ход)
Включает +4 для
-0p
Программа играет
X
. Будет играть в идеальную игру.Введите плату на STDIN, например:
Выход будет той же платой со всеми
X
замененыO
и наоборот. Пустые места будут заполнены числом, указывающим результат, если X сыграет там, а это1
означает, что результатом будут выигрыш,2
ничья и3
поражение. Законченная игра просто возвращает ту же позицию с перевернутыми цветами.В этом примере вывод будет:
Таким образом, позиция является победой,
X
если он играет в 3-х точках по верху и слева. Все остальные ходы проигрывают.Этот запутанный вывод на самом деле удобен, если вы хотите знать, как продолжается игра после хода. Поскольку программа всегда играет,
X
вы должны поменяться местамиX
иO
посмотреть ходыO
. Здесь, например, довольно ясно, чтоX
выигрывает, играя в левом верхнем углу, но что еслиX
играть в третьей позиции вдоль верха? Просто скопируйте вывод, поместитеO
вместо выбранного движения ход и замените все остальные числа-
снова, вот так:В результате чего:
Очевидно, что каждый ход
O
должен проигрывать, так как же он проигрывает, если играет в левом верхнем углу? Снова сделайте это, поместивO
верхний левый угол и заменив цифры на-
:Предоставление:
Так что у Х есть только один способ победить:
дающий
Ситуация для
O
остается безнадежной. Теперь легко увидеть, что каждый ход позволяетX
сразу же выиграть. Давайте хотя бы попробуем пойти на 3 О подряд:Предоставление:
X
играет единственный выигрышный ход (обратите внимание, что это делаетXXXO
вдоль третьего столбца:Вот вывод:
потому что игра была уже закончена. Вы можете увидеть победу в третьей колонке.
Актуальная программа
tictaclatin.pl
:Применительно к пустой доске это оценивает 9506699 позиций, что занимает 30 Гб и 41 минуту на моем компьютере. Результат:
Таким образом, каждый стартовый ход ничья. Так что игра ничья.
Чрезвычайное использование памяти в основном вызвано использованием рекурсии
do$0
. Для использования этой 154-байтовой версии с использованием простой функции требуется 3 Гб и 11 минут:что более терпимо (но все же слишком много, что-то должно все еще течь память).
Объединение нескольких ускорений приводит к этой 160-байтовой версии (5028168 позиций, 4 минуты и 800M для пустой доски):
Последний использует
0
для победы (не путайте сO
),1
для ничьей и2
для поражения. Вывод этого также более запутанный. Он заполняет выигрышный ход для X в случае выигрыша без замены цвета, но если входная игра уже была выиграна, он все равно выполняет замену цвета и не выполняет ни одного хода.Все версии, конечно, становятся быстрее и используют меньше памяти по мере заполнения платы. Более быстрые версии должны генерировать ход менее чем за 10 секунд, как только было сделано 2 или 3 хода.
В принципе, эта 146-байтовая версия также должна работать:
но на моей машине это вызывает ошибку Perl и сбрасывает ядро.
Все версии в принципе все еще будут работать, если
$$_||=
удалено 6-байтовое позиционное кэширование, но оно использует столько времени и памяти, что работает только для почти заполненных плат. Но в теории по крайней мере у меня есть 140-байтовое решение.Если вы положили
$\=
(стоимость: 3 байта) непосредственно перед тем, за$@<=>0
каждой выходной платой будет следовать статус всей платы:1
дляX
выигрышей,0
для розыгрыша и-1
для проигрыша.Вот интерактивный драйвер, основанный на самой быстрой версии, упомянутой выше. У водителя нет логики, когда игра заканчивается, поэтому вы должны остановить себя. Гольф-код знает, хотя. Если предложенный ход возвращается без
-
замены, игра окончена.источник
$move
объявлено в строке 11. Я понятия не имею, существует ли эвристика человека. Эта программа просто делает минимакс на дереве игры, у нее нет никаких стратегических знаний.JavaScript (ES6) 392 байта
использование
«Бот» будет играть вторым.
Нарисуйте сетку 4x4, которая пронумерована так:
Давайте запустим это в консоли браузера: просто поместите
f=
перед кодомИтак, если я хочу начать с
1
, я бы побежал,f([1])([])
и это даст мне14
.Хороший ход ... Что если я сыграю
2
потом?f([2,1])([14])
, Это вернется13
.Дай мне попробовать сдаться. Играть
3
.f([3,2,1])([14,13])
, Ох0
! Ты поймал меня!Играть
0
?f([0,2,1])([14,13])
,15
Хорошо, давайте продолжим играть ...Запись
Играйте в интерактивном режиме. Начните с
f([your-step])([])
.Подготовьте ваш следующий шаг. (См. Демонстрацию выше)
Помогите «боту» ввести свои шаги. Это не даст вам хороших результатов, если вы дадите ему случайную настройку. (Как
f([1,2,4])([14,12])
даст14
- Эй, бот хотел играть13
на своем втором ходу!Краткое содержание
Пока вы не сдаетесь, бот будет играть зеркальным движением.
Спасибо @EHTproductions за сообщение, что я неправильно понял правила игры и советы по игре в гольф: P
Теперь он также обнаружит, есть ли у него мат. Если да, заблокируйте это!
Его приоритеты: Блок> Зеркало> (запасной вариант) искать способы воспроизведения зеркала.
источник
3,2,1
для вас и0
для бота победа для вас?[0,1,2,3].map(i=>{k(n=>n%4==i);k(n=>Math.floor(n/4)==i);})
можно играть в гольф[0,1,2,3].map(i=>k(n=>n%4==i)+k(n=>(n/4|0)==i))
.