Який ваш наступний крок?


18

Це завдання полягає в тому, щоб написати функцію minimax мовою на ваш вибір, щоб вивести наступний найкращий хід у грі NxN з тик-так-носком з урахуванням поточного стану дошки . Вхід дошки може бути прийнятий як Матриця, 2D колекція або що- небудь інше, що для вас має сенс, але дотримується правил . Вихід є наступним найкращим кроком для того, хто навертається на даний момент , де X вважається розпочатим .

Швидкий перегляд алгоритму Minimax

Основна ідея алгоритму minimax полягає в перерахуванні всіх можливих результатів як DAG, а потім зважування їх на користь, яку послідовність рухів має для гравця, вводиться під час першого зробленого ходу. Усі можливі результати потім "заряджаються" першим кроком і оцінюються на основі суми всіх результатів (-1 за програш, 0 за нічию та 1 за виграш). У реалізаціях, в яких потрібно грати декількох гравців, ви перераховуєте всі можливі рухи гравця, а також всі можливі відповіді опонентів. Наприклад, в грі в тик-так-ногу (після першого ходу) є 8 можливих перших кроків, які ви можете зробити, і всі вони можуть здатися рівними лише при аналізі наступного ходу. Але шляхом повторення всіх можливих результатів для кожного можливого набору кроків, що призводить до кінцевого результату, та підведення їх підсумків,

Для кращого, більш поглибленого та контекстуального резюме алгоритму mini-max з точки зору tic-tac-toe читайте більше тут: http://neverstopbuilding.com/minimax

XKCD (лише 3x3 рішення)

Всі можливі рухи для гри 3x3 в тик-так.

Правила

  • Можна використовувати будь-яку мову, але не допускаються зовнішні бібліотеки minimax.
  • Вихід може бути координатою (0-n, 0-n) або числом (1-n * n), що вказує на найкращий наступний хід.
    • На додаток до цього, ви повинні мати змогу визначити, коли найкращий сценарій - це програш або нічия замість виграшу.
    • Те, як ви позначаєте втрату чи краватку, знову залежить від вас.
  • Вхід повинен використовувати традиційні X і O, і ви повинні припустити, що X рухається спочатку; порожні пробіли можуть бути представлені чим завгодно.
  • Ви можете припустити, що будь-які входи, що надходять у вашу програму, мають n O та n + 1 X, іншими словами, ви можете припустити, що ви отримуєте добре сформовану дошку.
  • Поточний стан дошки повинен бути єдиним входом до вашої програми, якщо ви використовуєте рекурсію, для полегшення вимог до введення повинні бути використані допоміжні методи. Для уточнення див. Https://codegolf.stackexchange.com/a/92851/59376 .
  • Будь-яке значення 10> = n> = 1 повинно підтримуватися; якщо ваша програма "вичерпується" на n> 10, я вважаю це також прийнятним, оскільки деякі мови мають значно меншу потужність обробки (Особливо, використовуючи консолі, спрямовані на веб).

Судження

  • Це код-гольф, тому найнижча кількість байтів програми виграє, а стандартні лазівки заборонені загалом.
  • У разі зрівноваження переможе програма, яка підтримує найбільший 'n'.

Приклади введення

2х2

[[X,O]
 [-,-]]

Вихід: 2 або [0,1] (3 або [1,1] також може бути вірним) (деяка форма вказівки місця, довільна до тих пір, поки ви можете легко пояснити використаний формат)


3х3

[[X,O,X]
 [O,X,-]
 [-,-,-]]

Вихід: -1 (втрата)


Ще раз дозволений будь-який потрібний формат введення, але потрібно використовувати X та O, надані приклади не мали на меті обмежувати цей формат, а лише надихати.


Вибачте DJMCMayhem, я насправді намагався позначити ці речі, але не зміг, оскільки я тут новий.
Magic Octopus Urn

Бонус також зняли, не додали нічого, крім нудоту.
Чарівна урва восьминога

Чи дозволений наступний вихідний формат: схема положення дошки з кожним спочатку порожнім простором унікальним символом, який вказує, якщо гра там призводить до виграшу / програші / нічиї (наприклад, W, L і D)
Ton Hospel

1
У прикладі 3x3 O повинен втрачати незалежно від того, що він грає, але ви кажете, вихід повинен бути [2,1], чому це так?
Дада

Відредагований, хороший улов. Не знаю, про що я думав, це був негативний приклад.
Magic Octopus Urn

Відповіді:


8

Perl, 101 98 байт

Включає +4для-0p

Запустити з введенням на STDIN

tictactoe.pl
OXO
---
--X
^D

Вихід - це та сама діаграма, але з кожним кроком, оновленим своїм статусом, 1представляє виграш, 2представляє нічию і 3представляє програш. У цьому випадку це було б

OXO
223
21X

тому 3 ходи нічия, 1 перемога та 1 програв (я оновлю рішення, якщо цей вихідний формат неприйнятний, але основний код залишиться колишнім)

tictactoe.pl:

#!/usr/bin/perl -0p
m%@{[map"O.{$_}"x"@-"."O|",1-/.(
)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

Це вже болісно повільно і використовує багато пам’яті для порожньої плати 3 * 3 (чому насправді рекурсія не йде так глибоко. Повинна бути деяка протікання пам'яті). Додавання запам'ятовування коштує 6 байтів, але значно економніше:

#!/usr/bin/perl -0p
$$_||=m%@{[map"O.{$_}"x"@-"."O|",1-/.(\n)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

Нічого собі, не помічаючи, що це pl і, швидше за все, абсолютно не працюватимуть за n = 10 з великою кількістю порожніх ... Ви зробили обидві речі, на які я сподівався когось зробити. Введення рядків і відображення результату для всіх кроків, не тільки найкращих. Браво.
Чарівна урва восьминога

Якщо одна рекурсивна функція "просочиться", як це може бути нормально ??? Занадто висока мова не дозволяє побачити 32-бітний реєстр в процесорі (або щось таке, що проста інструкція)
RosLuP

@RosLup Витік у цьому контексті не обов'язково означає недосяжну втрачену пам’ять. Perl досить своєрідний, коли він вивільняє пам'ять, досить часто робить це пізніше, ніж ви очікували, і, використовуючи набагато більше пам'яті, ніж ви очікували. Він також має тенденцію виділяти більше, ніж потрібно безпосередньо, в очікуванні того, що ви будете рости ваші структури даних. У цьому випадку використання "нормальної" рекурсії з функцією замість зловживання do$0використовуватиме в 10 разів менше пам'яті. Зауважте, цей випадок настільки екстремальний, що насправді може бути справжнім витоком пам'яті.
Тон Євангелія

Мало того, що не бачать регістри чи базові інструкції (з інструкцій щодо зали), але втрачають контроль над використанням пам'яті ... Для мене вони не масштабують ...
RosLuP

Досить довго, ви виграєте мою людину, сумно, що ми не отримали більше спроб.
Чарівна восьминога урна

2

Javascript (ES6), 320 294 байт

(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

Вхідні дані

1) Масив масивів символів, що описують поточну дошку, наприклад:

[['X', '-'], ['-', 'O']]

2) Ціле число, що описує поточний виток: 1 = X, -1 =O

Вихід

Масив із:

  • масив, що описує найкращий хід у [x, y]форматі
  • результат гри як ціле число: 1 = виграш, -1 = втрата, 0 = нічия

Приклад

У наступному прикладі Xгарантується перемога, граючи [1, 2].

let f =
(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

console.log(JSON.stringify(f(
  [['O','X','O'],
   ['-','-','-'],
   ['-','-','X']],
  1
)));

СИЛЬНА ІГРА. ТІЛЬКИ ПЕРЕМОЖЕНИЙ РУХ НЕ ГРАЮ.
ЯК ПРО НІЖНУ ГРУШКУ?


Молодці, хороший перший запис. Лише у мене зауваження є потенційним для збереження байтів із заданою інформацією "X завжди рухатиметься першою" А ви пробували з дошкою не 3х3;)?
Чарівна урва восьминога

@carusocomputing - Не забудьте зрозуміти, що ви маєте на увазі під "X завжди рухатиметься першим". З його допомогою можна було б визначити, на якій стороні рухається лише одна плата, але обчислення, що фактично коштуватиме більше байтів; тож я гадаю, що ти говориш про щось інше. Відповідь так: я зробив кілька тестів з трохи більшими дошками. Це повинно працювати так, як очікувалося, поки… помилка… порожніх позицій не так вже й багато. :-)
Арнольд

Проблема говорить The current state of the board must be the only input to your program. Ваш код потребує двох входів, що порушує це правило.
Дада

1
@Dada - Мені було цікаво з цього приводу, але я припустив, що активний колір є частиною стану дошки (так само, як шахова позиція завжди виходить з активним кольором + ансамбль пасажира + доступність). Тож я думаю, що ОП має уточнити цей момент. (І якщо ви маєте рацію, це звучить як зайва додаткова складність, ІМХО.)
Арнольд,

1
Ммм .. мені дуже подобається пояснення стану ради у його відповіді. Думаючи про це, деякі ланаги можуть використовувати лише рядки як вхідні дані, тому що дошка на зразок XXOOXO-OO важко буде розшифрувати в низьких підрахунках байтів без додаткової інформації, як розміри плати. Я дозволяю будь-які додаткові входи, які сприяють стану плати, хоча я все ще думаю, що інформація "припустимо, що X рухається першою" відрізняється від "з огляду на те, хто це поверне". Деякі мови скористаються цим як припущення;).
Чарівна урва восьминога
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.