Befunge, 181 168 байт
>>4&5pp20555>>03>16p\::5g8%6p5v
^p5.:g605$_ #!<^_|#:-1g61+%8g<
543217539511|:_^#->#g0<>8+00p3+5%09638527419876
v<304p$_v#:->#$$:2`#3_:^
>#\3#13#<111v124236478689189378
Позиції на дошці пронумеровані від 1 до 9. За замовчуванням ви отримуєте перший хід, але якщо ви хочете дозволити комп’ютеру першим рухатись, ви можете просто ввести 0 для першого переміщення. Коли ви зробили крок, комп’ютер відповість цифрою, що вказує на їх переїзд.
Немає перевірок, щоб переконатися, що ти не вступив у дійсний хід, а також немає перевірок, щоб хтось виграв чи програв. Як тільки їх більше не буде зроблено, програма просто переходить у нескінченний цикл.
Трохи складно перевірити це в Інтернеті, оскільки немає онлайн-перекладачів з інтерактивним введенням. Однак, якщо ви знаєте, які рухи ви збираєтеся зробити заздалегідь (що передбачає, що ви знаєте, як комп’ютер буде реагувати), ви можете надати тест на TIO за допомогою попередньо запрограмованих кроків.
Користувач грає першим: спробуйте онлайн!
Перший комп'ютер грає: спробуйте онлайн!
Щоб було легше бачити, що відбувається, я також отримав версію, яка виводить плату між ходами.
Користувач грає першим: спробуйте онлайн!
Перший комп'ютер грає: спробуйте онлайн!
Зауважте, що вам доведеться зачекати, коли TIO вичерпається, щоб побачити результати.
Пояснення
Плата зберігається в області пам'яті Befunge як плоский масив з 9 значень, індексований від 1 до 9. Це дозволяє нам використовувати нульове зміщення як особливий випадок "без руху", коли ми хочемо спочатку відпустити комп'ютер. Рухи гравця зберігаються як 4, а комп'ютер - як 5. Для початку всі позиції ініціалізуються на 32 (за замовчуванням пам'яті Befunge), тому кожен раз, коли ми отримуємо доступ до плати, ми модифікуємо 8, тому ми повернемося або 0, 4 або 5.
Враховуючи це розташування, якщо ми підсумовуємо значення будь-яких трьох позицій на дошці, ми знаємо, що комп’ютер знаходиться в одному кроці від виграшу, якщо загальна сума 10, гравець знаходиться в одному кроці від виграшу, якщо загальний 8 позиції діляться між комп'ютером та гравцем (але все ж одна позиція вільна), якщо загальна сума 9.
Вся наша стратегія базується на цій концепції. У нас є розпорядок, який займає перелік трійки із зазначенням наборів з трьох позицій на дошці, ми обчислюємо суму цих позицій, і якщо сума дорівнює певній загальній сумі, комп'ютер рухається до того, який із позицій у наборі вільний.
Основний список трійки, яку ми тестуємо, - це виграшні комбінації (1/2/3, 1/5/9, 1/4/7 тощо). Спочатку шукаємо в цілому 10 (комп'ютер збирається виграти), а потім 8 (гравець збирається виграти, і нам потрібно заблокувати цей хід). Менш очевидно, ми також перевіряємо на загальну кількість 9 (якщо у гравця та комп'ютера є одна з позицій, це хороша стратегія, щоб комп'ютер зайняв третє).
До цього останнього сценарію, другий стратегічний крок, який ми робимо, - це перевірити всі кутові набори (1/2/4, 2/3/6 тощо), а також дві протилежні кутові комбінації (1/8/9 та 3 / 7/8). Якщо будь-яка з цих комбінацій дорівнює 8, тобто гравець зайняв дві позиції, комп’ютер буде гарною стратегією зайняти решту вільної позиції.
Нарешті, є два особливих кроки справи. По-перше, ми завжди намагаємося займати центральне положення перед будь-яким іншим рухом. Це досягається тим самим рутином, що і всі наші інші рухи, просто пройшовши в одній трійці, 5/5/5, і цільовою сумою 0. Крім того, якщо всі інші тести не змогли знайти хід, ми намагаємося взяти один із верхніх кутів в крайньому випадку. Знову ж цього просто досягається шляхом тестування потрій 1/1/1 та 3/3/3, цільова сума 0.
Я не думаю, що це обов'язково ідеальна стратегія - можуть бути ігри, в яких комп'ютер малює, які потенційно можна було б виграти, - але це досить добре, щоб ніколи не програти матч. Я запустив тестовий сценарій, який намагався відтворити всі можливі рухи проти комп'ютера, і за кожну дійсну послідовність рухів комп'ютер або виграв, або виграв гру.
we can assume that all previous moves of the 2nd player were also played by our engine