Чи дійсна ця дошка Tic-Tac-Toe?


48

Виклик

Давши дошку-тик-носок у будь-якому форматі, визначте, чи вона дійсна чи ні. Якщо дошка може бути результатом гри в тик-нок, то вона дійсна. Наприклад, ця дошка дійсна:

XOX
OXO
XOX
Навпаки, ця рада недійсна:

XXX
XXO
ТОВ

Вхідні дані

  • Повна (9/9) тикова такт-дошка (результат, а не гра).

Правила

  • Формат введення повинен бути в змозі зображувати всі 512 можливих плати введення. Він повинен бути вказаний разом із інструкціями щодо його створення, якщо він незрозумілий / незрозумілий. Ви повинні вказувати позначки ради окремо.
  • Повинно бути два можливих виходи, один для дійсності та один для недійсності.
  • Можна припустити, що на дошці немає порожніх плям.

Тестові справи

Дійсний:

XOX
OXO
XOX

XOX
XOX
OXO

XOO
OOX
OXX

OXO
XOX
OXO

Недійсний:

XXX
XXX
XXX

ТОВ
ТОВ
ТОВ

XXX
ТОВ
XXX

ТОВ
OOX
XXX

XXO
OXO
OOX

Трохи допомогти?

Дошка вважається дійсною (для цього виклику), якщо і лише за умови виконання двох наступних умов:

  • Є 5 X і 4 O, або 4 X і 5 O. Наприклад,
    XXX
    OXO
    XXX
    вважається недійсним, оскільки є 7 Xs та 2 Os.
  • Перемогла лише гравець з 5 балами, або жодна з них не виграла. Наприклад,
    XXX
    ТОВ
    OOX
    вважається недійсним, оскільки першим буде сформований або ряд Os, або рядок Xs. Два гравці не можуть мати свою чергу одночасно.

Поточний переможець ...

... відповідь желейника ais523 , вражаючими 26 байтами!


2
Можливо, також додайте тестовий випадок O O O X O X X O X, щоб показати, що той самий гравець може мати і горизонтальний, і вертикальний ряд.
smls

2
Ви повинні вказувати позначки ради окремо. Я не впевнений, що розумію цю частину. Чи можете ви надати контрприклад?
Арнольд

3
@Tim X має 4 позначки.
Мартін Ендер

2
@Sparr "Виграв лише той гравець, який має 5 балів, або жоден з них не виграв."
Мартін Ендер

2
@Kevin (Відповідь на 1-й коментар) Тому що жодна дошка 9/9 не буде заповнена, якщо виграє другий гравець (гравець з 4 балами).
Ерік Аутгольфер

Відповіді:


11

Желе , 26 байт

ṢŒrṪ4=$$Ðfx3ðœ-µẆm€6R¤;/µL

Спробуйте в Інтернеті!

Формат введення трохи незвичний; це рядок, що представляє дошку, але з новинками для Windows (повернення каретки з наступним рядком). Наприклад, XXO\r\nOXO\r\nOOX. (Насправді, будь-яка дво символьна рядок накладки між рядками працює, але нові рядки Windows набагато захисніші, ніж інші параметри.)

Основна ідея полягає в тому, що ми шукаємо символи, які відображаються 4 рази на вході, але не мають трьох рівномірно розташованих вхідних даних у вихідному рядку. З двома або більше символами прокладки між лініями сітки 3 × 3 всі горизонтальні, вертикальні та діагональні лінії розташовані рівномірно, але жодна інша рівномірна лінія не може мати три елементи.

Пояснення:

ðІ µз є ланцюгові сепаратори , які розділити програму на кілька частин, кожна з яких є незалежними. Я замінив їх пробілами внизу, щоб зробити речі яснішими.

ṢŒrṪ4=$$Ðfx3 œ- Ẇm€6R¤;/ L
Ṣ                           sorted version of the input
 Œr                         run-length-encode it
        Ðf                  keep only elements where
   Ṫ                        delete the last element, and it was
    4=                      equal to 4
      $$                    parse Ṫ4= as a group
          x3                repeat each element three times

                Ẇ           all sublists of the input
                 m€         take every nth element of each (€) sublist
                   6R       for each n in 1..6
                     ¤      parse 6R as a group
                      ;/    flatten one level (m€ creates a nested structure)

             œ-             multiset difference
                         L  length of that difference

Іншими словами, ми знаходимо список символів, які з’являються рівно чотири рази на вході, і складаємо список, що складається з трьох примірників кожного з них; ми знаходимо список усіх підрядів, які рівномірно розташовані у вихідному рядку; і якщо ми віднімаємо другу від першої, ми хочемо, щоб результат мав довжину 1 (тобто гравець грав чотири рази, але не виграв). Зауважте, що оскільки ми знаходимося на 3 × 3 сітці, і кожен квадрат заповнений, неможливо, щоб обидва гравці грали чотири рази. У Jelly 1 є неправдоподібним, 0 - фальсий, тому нам не потрібно робити нічого особливого для перетворення отриманого списку в булевий. (Хоча µLце потрібно, тому що в протилежному випадку і те, “XXX”і інше “OOO”було б можливим тривалістю вихідних значень, і питання вимагає, щоб усі дійсні дошки давали однаковий вихід.)


3
Це цілком читабельно.
пабрам

21

JavaScript (ES6), 88 87 байт

s=>(a=[...s]).sort()[5]-a[3]&[7,56,73,84,146,273,292,448].every(j=>j&i,i=`0b`+s^~-a[4])

Приймає вхідний сигнал у вигляді рядка з 9 0і 1символів і повертається 1за дійсне, 0для інваліда. Сортуємо символи за порядком. Якщо середні три символи тепер однакові, дошка недійсна, оскільки їх занадто багато. В іншому випадку ми перетворюємо оригінальну плату в двійкову, гортаючи біти, якщо їх більше 0s, ніж 1s. На даний момент плата дійсна, якщо у неї 0немає рядка з трьох, тому ми просто тестуємо всі вісім рядків за допомогою масиву бітових масок. Редагувати: Збережено 1 байт завдяки @ETHproductions.


@ETHproductions Ах, звичайно, результат все одно буде лише 0 або 1.
Ніл

14

Python 3, 131 127 125 100 96 байт

Для іншого алгоритмічного підходу (і того, який дійсно підходить для цих багатобайтових мов для гри в гольф із вбудованою компресією), замість обчислення, чи дійсна дошка, давайте мати 512-бітне число, де кожен біт являє собою чи ні певна плата є дійсною чи ні і передає двійкове значення, що представляє дошку. Крім того, завдяки симетрії другу половину таблиці можна усунути разом із купою нулів:

def z(b):return int('agqozfx67wwye6rxr508ch2i8qicekpreqkap0725pk',36)<<24&1<<b+(b>255)*(511-b-b)

Значення тесту:

X X X
O X O
X X X

Представляється як двійкове значення 0b111010111, і функція повертає ненульове значення, якщо плата є дійсною.


Видалено проміжну змінну на 4 менші байти
Ken YN

На два менших байти, як a&(1<<b)дужки не потрібні.
Кен ЙН

Збив 25 байт, використовуючи симетрію та ще один за допомогою скорочення 24 найнижчих нульових бітів - це має бути гольфіст if b>255:b=511-b!
Кен ЙН

Знайшов гольфіст спосіб зробити це if.
Кен ІН

11

Пакет, 140 байт

@set/aXXX=OOO=O=0
@for %%l in (%* %1%2%3 %1%4%7 %1%5%9 %2%5%8 %3%5%7 %3%6%9 %4%5%6 %7%8%9)do @set/a%%l+=1
@cmd/cset/a!XXX*!(O-=5)+!OOO*!~O

Вводить дані як дев'ять окремих аргументів командного рядка та виводить 1для дійсних та 0недійсних. Працює, відстежуючи кількість разів, коли вона бачить Oі ортогональну лінію OOOабо XXX. Зручно Batch дозволяє нам виконувати цілу арифметику побічно, тому ми не збільшуємо, %%lа якусь змінну (хоча нас цікавлять лише три згадані змінні). Тоді нам потрібно перевірити, що або Xне виграв, і є п'ять Oс, або Oне виграв, і є чотири Oс.


10

Математика, 82 75 байт

Дякуємо Мартіну Ендеру за збереження 7 байт!

t=Total;3<(b=#~t~2)<6&&{t[c=If[b>4,1-#,#]],t/@c,Tr@c,Tr@Reverse@c}~FreeQ~3&

Без імені функція приймає 3x3 вкладений список 1s і 0s в якості вхідних даних і виведення Trueабо False.

Використовує зручну гнучкість Totalфункції (тут гольф t): з прикладу масиву e = { {1,2,3} , {4,5,6} , {7,8,9} }команда t[e]підсумовує три вектори (тут поступається {12,15,18}); команда t/@eпідсумовує кожен підсклад окремо (тут поступається {6,15,24}); і команда e~t~2підсумовує всі дев'ять елементів (тут поступається 45).

Отже, спочатку ми перевіримо, 3<(b=#~t~2)<6чи загальна кількість 1 дорівнює 4 або 5; якщо не, ми виходимо з False. Якщо так, ми використовуємо, c=If[b>4,1-#,#]щоб примусити чотирьох, а не п'ять. Потім ми обчислюємо суми стовпців t[c], рядкові t/@cпідсумки, суму основної діагоналі Tr@cта суму протилежної діагоналі Tr@Reverse~c, і використовуємо ~FreeQ~3для перевірки, чи 3не з’являється на будь-якому рівні цих обчислених сум.

Кумедна сторона: на відміну від більшості зображень на цьому веб-сайті, тут Trне використовується для підсумовування одновимірного списку, а фактично використовується як розроблено - для обчислення сліду двовимірної матриці!



5

JavaScript (ES6), 101 байт

Вводиться як 9-бітова двійкова маска, де X = 1і O = 0(MSB = верхня ліва комірка, LSB = нижня права клітина).

n=>[7,56,73,84,146,273,292,448,o=x=0].map((m,i)=>(c-=n>>i&1,m&n^m?m&n||o++:m&&x++),c=4)&&!(c|x&&~c|o)

Тестові справи


Я знав, що повинно бути (дещо) просте розрядне рішення. Приємна робота
ETHproductions

5

Пітон 2, 158 132 109 92 91 123 байт

def v(b):f=sum(b,());w={x[0]for x in b+zip(*b)+[f[::4],f[-3:1:-2]]if len(set(x))==1};return sum(map(`b`.count,w))==len(w)*5

Введення - це список / кортеж рядків, кожен з яких складається з трьох рядків рядків, наприклад:
[('X', 'O', 'X'), ('O', 'X', 'O'), ('X', 'O', 'X')]

Збережено кілька байтів, ігноруючи діагоналі на відповідь @ Мальтісена, що також скоротило наступний вираз.

Дякуємо @vaultah за економію 17 18 байт.

Перевірка діагоналей виявляється необхідною, що призвело до значної економії коштів.

Спробуйте тут.

Пояснення

def v(b):
  f=sum(b,())
  w={x[0]for x in b+zip(*b)+[f[::4],f[-3:1:-2]]if len(set(x))==1}
  return sum(map(`b`.count,w))==len(w)*5

f- це сплющений вхід для нарізки.
wмістить символів з переможними послідовностями.
Порахуйте кількість випадків кожного виграючого персонажа, який буде або 0, якщо wпорожній, або 5, якщо len(w)дорівнює 1. 10 суми, коли обидва мають виграшну послідовність, неможливо. Переможець, який має 5, означає, що програв має 4. Неможливо мати> 5 без виграшної послідовності.


lambda b:len({x[0]for x in b+zip(*b)if len(set(x))==1})<2and set(map(b .count,'XO'))=={4,5}зберігає кілька байт.
vaultah

і я щойно помітив, що ...and{4,5}==set(map(b .count,'XO'))зберігає ще один байт.
vaultah

Я думаю, що це неправильно вважає останній "Недійсний" приклад із питання справжнім, оскільки це не гарантує, що переможцем буде гравець з 5 балами.
smls

@smls Ви маєте рацію. Перевірка цього стану коштувала чимало байтів, можливо, його можна буде додатково пограти в гольф.
Джейк Кобб

5

R, 88 82 байт

x=scan();`if`(sum(x)%in%4:5,all(apply(combn(which(x==(sum(x)<5)),3),2,sum)!=15),F)

Усі комбінації трьох цілих чисел від 1 до 9, які дорівнюють 15, - це рядки / стовпці / діагоналі квадрата, показані нижче.

2 7 6
9 5 1
4 3 8

Функція приймає вхід як вектор булевих значень, T для "X", F для "O", що є сплющеним поданням плати. АЛЕ вони перепорядковані так, що їх індекс такий самий, як число у квадраті, у порядку (2,7,6,9,5,1,4,3,8). Цей порядок може бути досягнутий, якщо дошку звичайним чином розрівняти, а потім нарізати на c (6,1,8,7,5,3,2,9,4). Так це

X O X
O X O
X O X

представлено у вигляді:

c(T, F, T, F, T, F, T, F, T)[c(6,1,8,7,5,3,2,9,4)]

який:

c(F, T, F, T, T, T, F, T, F)

Функція спочатку визначає, чи є гравець з точно чотирма позначками. Якщо так, то функція використовує доповнення до 15-ти фактів-речей-речей, щоб визначити, чи має цей гравець трійку в ряд (дошка недійсна в тому випадку, якщо це робить гравець).

Якби ви хотіли взяти звичайну плоску дошку як вхід, код замість цього виглядатиме так:

f=function(x)ifelse(sum(x)%in%4:5,all(apply(combn(c(2,7,6,9,5,1,4,3,8)[which(x==(sum(x)<5))],3),2,sum)!=15),F)

Я новачок у цьому, поради будуть вдячні.


1
Збережіть 2 байти, якщо ви використовуєте if()натомість: f=function(x)якщо (sum(x)%in%4:5,all(apply(combn(which(x==(sum(x)<5)),3),2,sum)!=15),F). Не випробований розумом ви. Повернення руйнує код, але це backtick if backtick(.
Джонатан Керролл

1
Ще краще; x=scan();якщо (sum(x)%in%4:5,all(apply(combn(which(x==(sum(x)<5)),3),2,sum)!=15),F)і введіть як 1і 0. 82 байти.
Джонатан Керролл

3

JavaScript (ES6), 145 139 131 127 байт

s=>!(q="XO"[s.split`O`.length-5])|![...s].some((c,i)=>c==q&!/(.)(\1|..(\1|.(\1|.\1.).)..)\1/.test(s.slice(0,i)+0+s.slice(i+1)))

Введіть як розділений пробілом рядок, наприклад "XOX OXO XOX". Виходи 1для недійсної дошки, 0для дійсної. Це, очевидно, не найкраща техніка, принаймні не з JavaScript ...

Це в основному перевіряє, чи мають право обидва наступні:

  • Є рівно 4 або 5 Oс, І
  • є принаймні один із 5-екземплярних фігур, який створює невизначену гру при її видаленні.

Регекс - це перевірити, чи була вирішена гра. Це збігається з дошкою, якщо є будь-які прогони довжиною три з одного символу з 0 (рядок), 2 (діагонал вниз вправо), 3 (стовпець) або 4 (вліво-вліво діагоналі), що розділяють кожну пару.

Фрагмент тесту


2

Рубі, 104 99 91 байт

->x{[7,56,448,292,146,73,84,273].none?{|y|b=x.to_i 2;((a=x.count'1')==4?b:a==5?~b:7)&y==y}}

Формат вводу: двійковий рядок з 9 символів (0s і 1s), що представляють дошку, наприклад перший тестовий випадок 101010101. Спочатку перетворіть його у двійкове число, перевірте, чи попконт дорівнює 4 або 5, якщо це 5 інвертувати число, тому у нас завжди є 4. Перевірте, чи три їх вирівняні (маскуючи горизонтальну, вертикальну, діагональну).

TL; DR : Поверніть помилкове значення, якщо гравець з 4 балами виграв, правда інакше.

Дякую Йордану за коментарі,

Я не можу відтворити рядок UTF-8, який би врятував інший байт.


Ви можете замінити .select{...}[0]на .find{...}.
Йорданія

І ви можете зберегти ще один байт, замінивши масив чисел на "8ǀĤITđ".unpack("U*")(якщо щось втрачається в перекладі, рядок є результатом виклику pack("U*")вихідного масиву; це 12 байт).
Йорданія

Ви могли б використовувати any?замість цього none?, гортаючи вихід і зберігаючи цілий байт?
Олексій Андерсен

Я намагався з одним? замість жодної? але тоді мені потрібно! перевернути вихід.
ГБ

1

Perl 6 , 103 99 байт

{my \c=%(.flat.Bag.invert)<5>;?all c,|(.[0]===c if [eq] $_ for |.flat[<0 4 8>,<2 4 6>],|$_,|.&zip)}

Лямбда, яка приймає список подібних списків (('X','O','X'), ('O','X','O'), ('X','O','X'))і повертає Bool.

Це працює так:

  1. Перевірте, яка марка з’являється рівно 5 разів, і збережіть її c. (Якщо жодна позначка не з’являється рівно 5 разів, це буде містити помилкове значення)
  2. Повторіть всі діагоналі, рядки та стовпці та відфільтруйте «виграшні» (тобто ті, де всі три букви рівні) .
  3. Перевірте, чи cправда, і кожен виграшний рядок має тип c.

1

PHP, 125 байт

for($p=$n=$argv[1];$p;$p/=2)$i+=$p&1;foreach([7,56,448,73,146,292,273,84]as$m)$n&$m^$m?$n&$m||$o++:$x++;echo!$x|!$o&&2>$i^=4;

У мене була така ж ідея, що і в Арнаульда : Дошка діє, якщо встановлено 4 або 5 біт і або Xабо, Oабо ніхто не має смуги (але не обидва).

Щоб генерувати вхід із поля замінити Xна 1та Oз 0, з'єднати рядки та перетворити двійкове в десяткове, надати аргумент командного рядка.

відбитки 1для дійсних; порожній вихід для недійсного. Бігайте з -r.

зламатися

// count set bits
for($p=$n=$argv[1];$p;$p/=2)$i+=$p&1;
    /* ($p/=2 takes longer than $p>>=1, but eventually
       $p will come close enough to 0 for the loop to finish */
// count streaks for X and O
foreach([7,56,448,73,146,292,273,84]as$m)
    $n&$m^$m            // ($n masked with streak)!=streak <=> no streak for X
        ?$n&$m||$o++    // true: O has a streak if ($n masked with streak) is empty
        :$x++;          // false: X has a streak
echo!$x|!$o&&2>$i^=4;   // valid if not both have a streak
                        // AND $i is 4 or 5 (toggle 4 -> result 0 or 1)

1

Свіфт, 178 байт

func t(i:String)->Bool{let r=i.characters.filter({$0=="X"}).count;let g=i.characters.split(separator:"\n").map(String.init).contains;return(r==5||r==4)&&(!g("XXX") && !g("OOO"))}

0

ES6 (Javacript), 130, 138, 117 байт

ЗМІНИ:

  • 21 байт вимкнено завдяки чудовій раді @Neil!
  • Початкова версія була схильна до помилки, яку тепер слід виправити за ціною +8 байт. (Дякуємо @ETHproductions за вказівку на це)

Надзвичайно прямий підхід. Можливо, можна трохи далі пройти в гольф.

Приймає введення як 9 окремих аргументів, 1es і 0es

  • 1 - для X
  • 0 - для О

Аргументи: 1-3 - перший ряд, 4-6 - другий ряд, 7-9 - третій ряд.

Гольф

(a,b,c,d,e,f,g,h,j)=>![a+b+c,d+e+f,g+h+j,a+d+g,b+e+h,c+f+j,a+e+j,g+e+c,7].some(x=>x=="7777307777"[a+b+c+d+e+f+g+h+j])

Інтерактивне "Тестове ліжко"

var a=b=c=d=e=f=g=h=j=0;

T=(a,b,c,d,e,f,g,h,j)=>![a+b+c,d+e+f,g+h+j,a+d+g,b+e+h,c+f+j,a+e+j,g+e+c,7].some(x=>x=="7777307777"[a+b+c+d+e+f+g+h+j]);

function test() {
  if(T(a,b,c,d,e,f,g,h,j)) {
     grid.style.backgroundColor='green';
     msg.innerHTML="GOOD"
  } else {
     grid.style.backgroundColor='red';
     msg.innerHTML="BAD"
  }
}
<table id=grid style="background: red">
<thead>
  <tr>
     <td id=msg align="center" colspan="3">BAD</td>
    </tr>
  </thead>
  <tr>
      <td><input type="checkbox" onchange="a=this.checked*1;test();" id="ca"/></td>
      <td><input type="checkbox" onchange="b=this.checked*1;test();" id="cb"/></td>
      <td><input type="checkbox" onchange="c=this.checked*1;test();" id="cc"/></td>
    </tr>
    <tr>
      <td><input type="checkbox" onchange="d=this.checked*1;test();" id="cd"/></td>
      <td><input type="checkbox" onchange="e=this.checked*1;test();" id="ce"/></td>
      <td><input type="checkbox" onchange="f=this.checked*1;test();" id="cf"/></td>
    </tr>
    <tr>
      <td><input type="checkbox" onchange="g=this.checked*1;test();" id="cg"/></td>
      <td><input type="checkbox" onchange="h=this.checked*1;test();" id="ch"/></td>
      <td><input type="checkbox" onchange="j=this.checked*1;test();" id="cj"/></td>
    </tr>
 </table>


Я можу помилятися, але, схоже, це лише перевіряє, чи є переможець. На дійсній дошці не може бути переможця; наприклад, [1,0,1,1,0,1,0,1,0]( XOX XOX OXO).
ETHproductions

Так, я втратив заперечення, граючи в нього. Передбачається, що протилежна сторона не є переможцем. Слід виправити зараз. Дякую !
цепелін

(Я почав коментувати перед останньою редакцією) Чи можете ви а) написати a+b+c+d+e+f+g+H+iзамість F.reduce((r,c)=>r+=c*1)(у який момент вам не потрібно F) б) написати .includes(C)(і перейти до значення рядка C)?
Ніл

@Neil, це, мабуть, спрацює, я спробую завтра. Дякую !
zeppelin

Є чи OOO XXX OXOнесправність?
Ісмаїл Мігель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.