Крестики-нолики - X или O?

14

Фон

Перейдите к «Задаче», если вы знакомы с Крестики-нолики (я думаю, что большинство из них!)

Tic-Tac-Toe - известная игра для двух игроков. Он состоит из доски 3х3, которая постепенно заполняется двумя игроками (пояснения ниже); Первый игрок использует персонажа, Xа другой использует O. Победитель первым получает 3 последовательных и одинаковых символа ( Xили O) по горизонтали, вертикали или диагонали. Если доска заполнена и ни одному из игроков не удалось получить трех последовательных персонажей, как описано выше, игра заканчивается ничьей. Обратите внимание, что в конце игры могут быть пустые места, если один из игроков выиграет менее чем за 9 ходов (это не может произойти в случае ничьей).

задача

По заданной доске Tic-Tac-Toe в конце игры (в виде строки, матрицы, простого списка из 9 упорядоченных значений в любом другом приличном формате) определите, кто победит в игре.

  • Входные данные будут состоять из отдельных и непротиворечивых значений, одного для X, одного для Oи другого, которое представляет пустое место.

  • Ваша программа должна иметь возможность выводить 3 различных, непротиворечивых и непустых значения: одно в случае Xвыигрыша, другое в случае Oвыигрыша или другое, если игроки связаны.

    Пожалуйста, укажите эти значения в своем ответе. Вы можете предположить, что ввод будет действительной платой Tic-Tac-Toe.

Тестовые случаи

X, O, _Являются входными значениями здесь; X wins, O winsИ Tieпредназначены для выхода.

X O X
O X _
O _ X

Выход: X wins.

X _ O
X O _
X O X

Выход: X wins.

X O X
_ O X
_ O _

Выход: O wins.

X O X
O O X
X X O

Выход: Tie.


Как обычно, применяются все наши стандартные правила. Это , выигрывает самый короткий код в байтах на каждом языке!

Мистер Xcoder
источник
2
Убирайся из моего мозга! Буквально только что пришла идея принять участие в конкурсе Noughts & Crosses о том, что я собираюсь отправиться в Санбокс в понедельник. Тогда я взломал сайт и увидел это!
Лохматый
1
@Shaggy Чтобы процитировать кого-то из серии "Форсаж": слишком медленно! ; р
г-н Xcoder
Все в порядке, моя идея была для играбельной версии, предполагая, что это еще не было сделано.
Лохматый
4
@ Laikoni Я не думаю, что это обман, так как он имеет более гибкий ввод и вывод, а также имеет пустые поля, и это также позволяет предположить, что вход является допустимой доской.
Эрик Outgolfer
1
@ Джошуа Это о создании игры в крестики-нолики. Это примерно один класс.
DonielF

Ответы:

6

Желе ,  16 15  14 байт

U,Z;ŒD$€ẎḄỊÐḟḢ

Монадическая ссылка, принимающая список списков (строк или столбцов) со значениями:

X = 0.155; O = -0.155; _ = 0

Возвращение результатов:

X wins = 1.085; O wins = -1.085; Tie = 0

Примечание: используя значение ноль для _, и равные, но противоположные значения для Xи O, это значение (здесь 0.155) может находиться в диапазоне (1/6, 1/7)(исключая на обоих концах) - я выбрал только значение в этом диапазоне, которое дало бы точно представимый результат с плавающей запятой для выигрышных дел.

Попробуйте онлайн!

Как?

U,Z;ŒD$€ẎḄỊÐḟḢ - Link: list of lists (as described above)
U              - upend (reverse each row)
  Z            - transpose (get the columns)
 ,             - pair the two
      $€       - last two links as a monad for each of them:
    ŒD         -   diagonals (leading diagonals - notes: 1. only one is of length 3;
               -              2. the upend means we get the anti-diagonals too)
        Ẏ      - tighten (make a single list of all the rows, columns and diagonals)
         Ḅ     - from binary (vectorises) (note that [0.155, 0.155, 0.155]
               -                           converts to 4*0.155+2*0.155+1*0.155 = 1.085
               -                           and [-0.155, -0.155, -0.155]
               -                           converts to 4*-0.155+2*-0.155+1*-0.155 = -1.085
               -                           while shorter lists or those of length three
               -                           with any other mixtures of 0.155, -0.155 and 0
               -                           yield results between -1 and 1
               -                           e.g. [.155,.155,0] -> 0.93)
           Ðḟ  - filter discard if:
          Ị    -   insignificant (if abs(z) <= 1) (discards all non-winning results)
             Ḣ - head (yields the first value from the list or zero if it's empty)
Джонатан Аллан
источник
Да, я думаю, что у любых ответов на эзотерическом языке должно быть объяснение (и мне нравится видеть объяснения для нормальных языков!)
Джонатан Аллан
Спасибо за добавление! Очень хороший подход, гораздо умнее, чем я думаю ...
Хорошо
6

Javascript (ES6), 103 87 байт

a=>"012+345+678+036+147+258+048+246T".replace(/\d/g,n=>a[n]||!1).match(/(\d)\1\1|T/)[0]

вход

  • Х представлен как 1
  • O представлен как 2
  • _ представлен как 0

Выход

  • Х побед представлен как "111"
  • O побед представлен в виде "000"
  • Галстук представлен как "T"

объяснение

a=>
    "012+345+678+036+147+258+048+246" // List of indexes for each row
    .replace(/\d/g,n=>a[n]||!1)       // Replace all digits with the value of the cell
    .match(/(\d)\1\1|$/)[0]           // Find the first row filled with the same value

Контрольные примеры

f=
a=>"012+345+678+036+147+258+048+246T".replace(/\d/g,n=>a[n]||!1).match(/(\d)\1\1|T/)[0]
console.log(f([1,2,1,2,1,0,2,0,1]))
console.log(f([1,0,2,1,2,0,1,2,1]))
console.log(f([1,2,1,0,2,1,0,2,0]))
console.log(f([1,2,1,2,2,1,1,1,2]))

Герман Л
источник
«Ваша программа должна иметь возможность выводить 3 различных, непротиворечивых и непустых значения », поэтому вы не можете вывести пустую строку для связи.
RedClover
1
@ Соаку Боже мой, я пропустил эту часть правил.
Герман Л
4

Желе , 18 байт

UŒD;;Z;ŒDµSA⁼3µÐfḢ

Попробуйте онлайн!

X= 1, O= -1, _= 0
X wins = [1, 1, 1], O wins = [-1, -1, -1], Tie = 0
Ввести как список из 3 списков по 3 элемента в (1, -1, 0)каждом.

Эрик Outgolfer
источник
Вау, хорошо ... Когда вы закончите играть в гольф, пожалуйста, добавьте значения ввода / вывода и объяснение :-)
Mr. Xcoder
Вот аналогичный подход с немного более коротким тестом. Takes X= 1, O= 2, _= 3, Returns 1(X побед), 2(O побед) или 3(ничья).
Арно
@Arnauld спасибо за сокращение
Эрик Outgolfer
3

Python 3 , 73 байта

lambda b:{'XXX','OOO'}&{*b.split(),b[::4],b[1::4],b[2::4],b[::5],b[2::3]}

Попробуйте онлайн!


Python 2 , 100 95 92 87 82 77 байт

lambda b:{'XXX','OOO'}&set(b.split()+[b[::4],b[1::4],b[2::4],b[::5],b[2::3]])

Попробуйте онлайн!


Принимает ввод в виде строки, разделенной новой строкой XO_

Выходы:

  • {'XXX'}для X,
  • {'OOO'} за O
  • {} для галстука

Работает, разрезая строку на строки столбцов и диагоналей:

The board:
    1 2 3
    4 5 6
    7 8 9
which is '123\n456\n789' is sliced into:

['123', '456', '789', '147', '258', '369', '159', '357']
rows: b.split() -> ['123', '456', '789']
cols: [b[::4],b[1::4],b[2::4]] -> ['147', '258', '369']
diag: [b[::5],b[2::3]] -> ['159', '357']

тогда 'XXX'и'OOO'проверяются на ломтики.

Принимает ввод в виде строки, разделенной новой строкой XO_

Выходы:

  • {'XXX'}для X,
  • {'OOO'} за O
  • {} для галстука

Работает, разрезая строку на строки столбцов и диагоналей:

The board:
    1 2 3
    4 5 6
    7 8 9
which is '123\n456\n789' is sliced into:

['123', '456', '789', '147', '258', '369', '159', '357']
rows: b.split() -> ['123', '456', '789']
cols: [b[::4],b[1::4],b[2::4]] -> ['147', '258', '369']
diag: [b[::5],b[2::3]] -> ['159', '357']

Затем 'XXX'и 'OOO'проверяются на ломтики.

TFeld
источник
Я думаю, что Python нарезает FTW В любом случае, 81 байт должен работать.
полностью человек
@icrieverytim [2::2]ломтики 3579, в то время как [2:8:2]дает357
TFeld
Python 3, 73 байта .
Джонатан Фрех
3

R 118 116 115 байт

Спасибо @ user2390246 за два дополнительных байта.

function(M,b=table,u=unlist(c(apply(M,1,b),apply(M,2,b),b(diag(M)),b(M[2*1:3+1]))))`if`(any(u>2),names(u[u>2]),"T")

Слегка разгульный

function(M){
    u=unlist(c(apply(M,1,table), #Contingency table of the rows
             apply(M,2,table), #of the columns
             table(diag(M)), #of the diagonal
             table(M[2*1:3+1]))) #of the opposite diagonal
    `if`(any(u>2),names(u[u>2]),"T") #Give name of element that occurs more than twice in any setting
 }

Возвращает, Xесли X выигрывает, Oесли O выигрывает и Tв случае ничьей.

Попробуйте онлайн!

plannapus
источник
1
M[c(3,5,7)]короче для противоположной диагонали
user2390246
3

Perl 5 , 58 байт

56 байт код + 2 фпр -p0.

$_=eval sprintf'/(.)(.{%s}\1){2}/s||'x4 .'0?$1:T',0,2..4

Попробуйте онлайн!

Выходы Xи Oдля побед, или Tдля ничьи. Включает кучу кода верхнего / нижнего колонтитула, чтобы проверить все сразу.


Альтернатива, 58 байт

$}.="/(.)(.{$_}\\1){2}/s||"for 0,2..4;$_=eval$}.'0?$1:T'

Попробуйте онлайн!

Дом Гастингс
источник
2

Python 2 , 124 118 117 115 байтов

  • Сохранено шесть байтов благодаря Эрику Аутгольферу ; используя строку, чтобы избежать запятых.
  • Сохранено один байт благодаря мистеру Xcoder ; игра [j*3:j*3+3]в гольф на[j*3:][:3] .
  • Сохранено два байта с использованием магического числа для сжатия строки.
def T(B):
 for j in range(8):
	a,b,c=map(int,`0x197bf3c88b2586f4bef6`[j*3:][:3])
	if B[a]==B[b]==B[c]>0:return B[a]

Попробуйте онлайн!

Входные / выходные значения

  • X представляется как 1
  • O представляется как 2
  • _ представляется как None
Джонатан Фрех
источник
[8,0,3,6,1,4,7,2,5,8,0,4,8,2,4,6]->map(int,'8036147258048246')
Эрик Outgolfer
@EriktheOutgolfer Спасибо. Я пытался сыграть в список целых чисел с помощью map(ord,"..."), хотя nulбайт в середине строки не
удался
117 байт . [j*3:j*3+3]есть [j*3:][:3]. Как примечание стороны, j*3+3то же самое -~j*3, но это также 118 байтов.
г-н Xcoder
@JonathanFrech У тебя, кажется, есть дополнительный 01234567...
Эрик Игрок в гольф
1
@ Mr.Xcoder Спасибо. Узнал новый нарезки гольфа сегодня.
Джонатан Фрех
2

Python 3 , 173 байта

lambda x:h(x,1)*2or+h(x,0)
h=lambda x,y:g(x,y)or g(zip(*x),y)or x[0][0]==x[1][1]==x[2][2]==y or x[0][2]==x[1][1]==x[2][0]==y
g=lambda x,y:any(all(e==y for e in r)for r in x)

Попробуйте онлайн!

  • Ввод в виде матрицы 1 == X, 0 == O, -1 == _

  • Вывести как одно значение: 2 == X, 1 == O, 0 == TIE

-8 байтов благодаря Эрику Аутгольферу

HyperNeutrino
источник
Вы можете заменить первую строку lambda x:h(x,1)*2or+h(x,0)на -8 байт и 0 == TIE(что лучше imo).
Эрик Outgolfer
@EriktheOutgolfer круто, спасибо
HyperNeutrino
2

PHP, 70 байт

for($c=95024101938;${${$i++&7}.=$argn[$c%9]}=1<$c/=3;);echo$XXX-$OOO;

Предполагается -n(переводчик по умолчанию). Дополнительно требует -R(выполнить <code>для каждой строки ввода), считается как один.

Ввод выполняется в одной строке (точно так же, как в описании проблемы, за исключением удаления всех пробелов).

Вывод следующий: 1→ X Wins, -1→ O Wins, 0→ Tie.

Попробуйте онлайн!

Примо
источник
Вам не нужно иметь целые строки, вы можете выбрать свои выходные значения. 'X Wins'может быть изменено на 'X'(или даже целое число - скажем 1). То же самое относится 'O wins'и к Tie. При этом 109 байтов .
г-н Xcoder
@ Mr.Xcoder спасибо за разъяснения.
прима
1

Сетчатка , 49 байт

;
;;
.*(\w)(.)*\1(?<-2>.)*(?(2)(?!))\1.*
$1
..+
T

Попробуйте онлайн! Принимает ввод в виде 11-символьной строки из 9 Xс, Oс или -с в трех группах по три, разделенных ;s, хотя ссылка содержит заголовок, который переводит данные тестовые примеры в этот формат. Работает путем сопоставления выигрышной линии напрямую с использованием балансировочной группы, чтобы гарантировать, что три совпадающих символа равноудалены. (Подходящие расстояния: 0 (горизонтальная линия), 4 (обратная диагональ), 5 (вертикальная линия) или 6 (диагональ); другие расстояния могут попасть ;в строку или выйти за ее пределы.)

Нил
источник
1

Ява 8, 112 108 106 104 90 102 93 байта

b->b.replaceAll(".*(X|O)(\\1|...\\1...|.{4}\\1.{4}|..\\1..)\\1.*","$1").replaceAll("..+","T")

+12 байт (90 → 102) из-за исправления ошибки проверки только одной диагонали вместо обоих ..
-9 байт (102 → 93) с использованием replaceAllвместоmatches .

Входные данные в формате XOX OX_ O_X, выход X, Oили T.

Объяснение:

Попробуй это здесь.

b->{                   // Method with String as both parameter and return-type
  b.replaceAll(".*(X|O)(\\1|...\\1...|.{4}\\1.{4}|..\\1..)\\1.*",
                       //  If we found a line of X or O:
     "$1")             //   Replace it with either X or O
   .replaceAll("..+",  //  If there are now more than 2 characters left:
     "T")              //   Replace it with T
                       // End of method (implicit / single-line return-statement)

Объяснение регулярное выражение:

.*(X|O)(\1|...\1...|.{4}\1.{4}|..\1..)\1.*
.*                                      .*# 0 or more trailing & leading chars
  (X|O)                               \1  # X or O next to those leading/trailing chars
       (\1                                # A single X or O in between (row found)
          |...\1...                       # 3 chars, X or O, 3 chars (column found)
                   |.{4}\1.{4}            # 4 chars, X or O, 4 chars (diagonal TLBR found)
                              |..\1..)    # 2 chars, X or O, 2 chars (diagonal TRBL found)
Кевин Круйссен
источник
0

Сетчатка , 127 байт

.*(X|O)\1\1.*
$1
(X|O).. \1.. \1..
$1
.(X|O). .\1. .\1.
$1
..(X|O) ..\1 ..\1
$1
(X|O).. .\1. ..\1
$1
..(X|O) .\1. \1..
$1
..+
_

Попробуйте онлайн!

... Я думаю, вы могли бы назвать это грубой силой ... Думаю, в этом есть какая-то заслуга ...

totallyhuman
источник
0

Сетчатка , 51 байт

.*(X|O)(\1|...\1...|.{4}\1.{4}|..\1..)\1.*
$1
..+
T

Порт моего Java 8 ответа . Входные данные в формате XOX OX_ O_X, выход X, Oили T.

Объяснение:

Попробуй это здесь.

.*(X|O)(\1|...\1...|.{4}\1.{4}|..\1..)\1.*
.*                                      .*# 0 or more trailing & leading chars
  (X|O)                               \1  # X or O next to those leading/trailing chars
       (\1                                # A single X or O in between (row found)
          |...\1...                       # 3 chars, X or O, 3 chars (column found)
                   |.{4}\1.{4}            # 4 chars, X or O, 4 chars (diagonal TL→BR found)
                              |..\1..)    # 2 chars, X or O, 2 chars (diagonal TR→BL found)

$1                                        #  Replace match of above with either X or O

..+                                       # If there are now 2 or more characters left:
T                                         #  Replace everything with T
Кевин Круйссен
источник
0

J, 34 байта

[:>./[:+./"1(2 1 0},:0 1 2}),(,|:)

Ungolfed:

[: >./ [: +./"1 (2 1 0} ,: 0 1 2}) , (, |:)

объяснение

Кодирование:

X = 2
O = 3
_ = 1

Наша высокоуровневая стратегия заключается в том, чтобы сначала создать матрицу, каждая строка которой является возможным выигрышем. Строка один - диагональ /, строка 2 - диагональ \, следующие три строки - строки, а последние три строки - столбцы. Эта часть завершается фразой (используя пункт Amend }):

(2 1 0},:0 1 2}),(,|:)

Наконец, мы берем GCD каждой строки:

+./"1

Благодаря нашему кодированию любая строка с пробелом будет иметь GCD 1, как и любая строка, содержащая любое сочетание X и Os, потому что 2 и 3 взаимно просты. Все, что нам нужно сделать дальше, это найти максимальный элемент:>./

Если игра ничья, то будет 1. Если игрок выигрывает, это будет номер этого игрока.

Попробуйте онлайн!

Ион
источник
0

JavaScript, 66 байт

([a,b,c,d,e,f,g,h,i])=>e&(a&i|c&g|b&h|d&f)|a&(b&c|d&g)|i&(c&f|g&h)

Сохраняя это простым.

  • Ввод: строка или массив чисел или строк, с 0соответствующим пробелом, 1X и2 O.
  • Выход: 0 за ничью, 1за победу Х, 2за победу О.

Расширено, слегка прокомментировано:

( [a,b,c,d,e,f,g,h,i] ) => // Break apart the input into nine variables w/ destructuring
  // Run through all possible win conditions. 1&1&1 -> 1, 2&2&2 -> 2
  e & (             // All victories involving the middle square
    a & i | c & g | // Diagonal lines
    b & h | d & f   // Vertical/horizontal through the middle
  ) | 
  a & ( b & c | d & g ) | // Victories with the top-left square
  i & ( c & f | g & h )   // Victories with the bottom-right square
Яир Рэнд
источник