Kółko i krzyżyk - X czy O?

14

tło

Przejdź do „Zadania”, jeśli znasz Tic-Tac-Toe (myślę, że większość to!)

Tic-Tac-Toe to słynna gra dla dwóch graczy. Składa się z planszy 3x3, która jest stopniowo wypełniana przez dwóch graczy (wyjaśnienia poniżej); Pierwszy gracz używa postaci, Xa drugi używa O. Zwycięzca jako pierwszy otrzymuje 3 kolejne i identyczne postacie ( Xlub O), poziomo, pionowo lub ukośnie. W przypadku, gdy plansza jest zapełniona i żadnemu z graczy nie udało się zdobyć trzech kolejnych postaci, jak opisano powyżej, gra kończy się remisem. Zauważ, że na końcu gry mogą znajdować się puste miejsca, na wypadek gdyby którykolwiek z graczy wygrał w sumie mniej niż 9 ruchów (nie może się to zdarzyć w przypadku remisu).

Zadanie

Biorąc pod uwagę planszę kółko i krzyżyk na końcu gry (w postaci łańcucha, matrycy, płaskiej listy 9 uporządkowanych wartości, dowolnego innego przyzwoitego formatu), określ, kto wygrywa grę.

  • Dane wejściowe będą składały się z odrębnych i spójnych wartości, jednej dla X, jednej dla Oi drugiej reprezentującej puste miejsce.

  • Twój program powinien być w stanie wygenerować 3 różne, spójne i niepuste wartości: jedna w przypadku Xwygranej, druga w przypadku Owygranej lub inna, jeśli gracze są remisowani.

    Podaj te wartości w swojej odpowiedzi. Możesz założyć, że wejście będzie prawidłową tablicą Kółko i krzyżyk.

Przypadki testowe

X, O, _Są wartości wejściowe tutaj; X wins, O winsI Tiesą na wyjściu.

X O X
O X _
O _ X

Wyjście: X wins.

X _ O
X O _
X O X

Wyjście: X wins.

X O X
_ O X
_ O _

Wyjście: O wins.

X O X
O O X
X X O

Wyjście: Tie.


Jak zwykle obowiązują wszystkie nasze standardowe zasady. To jest , wygrywa najkrótszy kod w bajtach w każdym języku!

Pan Xcoder
źródło
2
Wynoś się z mojego mózgu! Dosłownie właśnie wpadłem na pomysł wyzwania Noughts & Crosses, które zamierzałem odbyć w Sanbox w poniedziałek. Potem otwieram witrynę i widzę to!
Shaggy
1
@Shaggy Aby zacytować kogoś z serii „Szybcy i wściekli”: Zbyt wolno! ; p
Mr. Xcoder
W porządku, mój pomysł dotyczył grywalnej wersji, zakładając, że jeszcze tego nie zrobiono.
Shaggy
4
@Laikoni Nie sądzę, że to duplikat, ponieważ ma to o wiele bardziej elastyczne wejście i wyjście, a także ma puste pola, a to także pozwala założyć, że wejście jest prawidłową kartą.
Erik the Outgolfer
1
@Joshua Chodzi o stworzenie gry w kółko i krzyżyk. Chodzi o ocenę pierwszego.
DonielF

Odpowiedzi:

6

Galaretka ,  16 15  14 bajtów

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

Monadyczny link akceptujący listę list (wierszy lub kolumn) z wartościami:

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

Zwracane wyniki:

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

Uwaga: używając wartości zero dla _i równych, ale przeciwnych wartości dla Xi O, ta wartość (tutaj 0.155) może należeć do zakresu (1/6, 1/7)(wyłączne na obu końcach) - wybrałem tylko wartość z tego zakresu, która dała dokładnie reprezentowalny wynik zmiennoprzecinkowy dla przypadków wygranych.

Wypróbuj online!

W jaki sposób?

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)
Jonathan Allan
źródło
Tak, myślę, że wszelkie ezoteryczne odpowiedzi językowe powinny zawierać wyjaśnienia (i lubię też zobaczyć wyjaśnienia dla normalnych języków!)
Jonathan Allan
Dzięki za dodanie! Bardzo dobre podejście, znacznie mądrzejsze niż to, co myślałem o ... Miło
Pan Xcoder
6

JavaScript (ES6), 103 87 bajtów

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

Wejście

  • X jest reprezentowany jako 1
  • O jest reprezentowane jako 2
  • _ jest reprezentowany jako 0

Wynik

  • X wygranych jest reprezentowane jako "111"
  • Wygrane O są reprezentowane jako "000"
  • Krawat jest reprezentowany jako "T"

Wyjaśnienie

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

Przypadki testowe

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]))

Herman L.
źródło
„Twój program powinien być w stanie wyprowadzić 3 różne, spójne i niepuste wartości ”, więc nie możesz wypisać pustego łańcucha dla remisu.
RedClover,
1
@ Soaku Mój zły, tęskniłem za tą częścią zasad.
Herman L
4

Galaretka , 18 bajtów

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

Wypróbuj online!

X= 1, O= -1, _= 0
X wygrywa = [1, 1, 1], O wygrywa = [-1, -1, -1], Remis = 0
Wprowadź jako listę 3 list po 3 elementy w (1, -1, 0)każdym.

Erik the Outgolfer
źródło
Wow Nice ... Kiedy skończysz grać w golfa, dodaj wartości I / O i wyjaśnienie :-)
Mr. Xcoder 30.09.17
Oto podobne podejście z nieco krótszym testem. Bierze X= 1, O= 2, _= 3, zwraca 1(X zwycięstw), 2(O zwycięstw) lub 3(remis).
Arnauld
@Arnauld dzięki za skrócenie
Erik the Outgolfer
3

Python 3 , 73 bajty

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

Wypróbuj online!


Python 2 , 100 95 92 87 82 77 bajtów

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

Wypróbuj online!


Pobiera dane wejściowe jako ciąg oddzielony znakiem nowej linii XO_

Wyjścia:

  • {'XXX'}dla X,
  • {'OOO'} dla O
  • {} na remis

Działa poprzez pocięcie łańcucha na kolumny i przekątne w wierszach:

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']

następnie 'XXX' i 'OOO'są sprawdzane przed plasterki.

Pobiera dane wejściowe jako ciąg oddzielony znakiem nowej linii XO_

Wyjścia:

  • {'XXX'}dla X,
  • {'OOO'} dla O
  • {} na remis

Działa poprzez pocięcie łańcucha na kolumny i przekątne w wierszach:

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']

wtedy'XXX' i 'OOO'są sprawdzane przed plasterki.

TFeld
źródło
Python krojenie FTW W każdym razie, 81 bajtów , powinno działać, tak myślę.
całkowicie ludzki,
@icrieverytim [2::2]kroi na 3579, a [2:8:2]daje357
TFeld
Python 3, 73 bajty .
Jonathan Frech
3

R, 118 116 115 bajtów

Podziękowania dla @ user2390246 za dwa dodatkowe bajty.

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")

Nieznacznie nie golfista:

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
 }

Zwraca Xjeśli X wygra, Ojeśli O wygra iT aw przypadku remisu.

Wypróbuj online!

plannapus
źródło
1
M[c(3,5,7)]jest krótszy dla przeciwnej przekątnej
2390246
3

Perl 5 , 58 bajtów

56 bajtów kod + 2 fpr -p0.

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

Wypróbuj online!

Wyniki Xi Owygrane lub Tremis. Zawiera kilka kodów nagłówka / stopki do przetestowania naraz.


Alternatywnie, 58 bajtów

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

Wypróbuj online!

Dom Hastings
źródło
2

Python 2 , 124 118 117 115 bajtów

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]

Wypróbuj online!

Wartości wejściowe / wyjściowe

  • X jest reprezentowany jako 1
  • O jest reprezentowany jako 2
  • _ jest reprezentowany jako None
Jonathan Frech
źródło
[8,0,3,6,1,4,7,2,5,8,0,4,8,2,4,6]->map(int,'8036147258048246')
Erik the Outgolfer
@EriktheOutgolfer Thanks. Próbowałem zagrać w golfa na liście liczb całkowitych za pomocą map(ord,"..."), chociaż nulbajt pośrodku łańcucha nie zadziałał ...
Jonathan Frech
117 bajtów . [j*3:j*3+3]jest [j*3:][:3]. Na marginesie, j*3+3jest taki sam jak -~j*3, ale to również 118 bajtów.
Pan Xcoder,
@JathanathanFrech Wygląda na to, że masz dodatkowe 01234567...
Erik the Outgolfer
1
@ Mr.Xcoder Thanks. Nauczyłem się dzisiaj nowego krojenia w golfa.
Jonathan Frech
2

Python 3 , 173 bajtów

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)

Wypróbuj online!

  • Dane wejściowe jako macierz 1 == X, 0 == O, -1 == _

  • Dane wyjściowe jako pojedyncza wartość: 2 == X, 1 == O, 0 == TIE

-8 bajtów dzięki Erikowi Outgolfer

HyperNeutrino
źródło
Możesz zamienić pierwszy wiersz lambda x:h(x,1)*2or+h(x,0)na -8 bajtów i 0 == TIE(co jest ładniejsze imo).
Erik the Outgolfer
@EriktheOutgolfer spoko, dzięki
HyperNeutrino
2

PHP, 70 bajtów

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

Zakłada -n(domyślne ustawienia interpretera). Dodatkowo wymaga -R(wykonaj<code> dla każdego wiersza wejścia), liczonego jako jeden.

Dane wejściowe są pobierane w jednym wierszu (dokładnie tak, jak w opisie problemu, z wyjątkiem usuniętych wszystkich białych znaków).

Dane wyjściowe są następujące: 1→ X wygranych, -1→ O wygranych, 0→ remis.

Wypróbuj online!

primo
źródło
Nie musisz mieć całych ciągów, możesz wybrać wartości wyjściowe. 'X Wins'można zmienić na 'X'(lub nawet na liczbę całkowitą - powiedzmy 1). To samo dotyczy 'O wins'i Tie. Biorąc to pod uwagę, 109 bajtów .
Pan Xcoder
@ Mr.Xcoder dziękuje za wyjaśnienie.
primo
1

Siatkówka , 49 bajtów

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

Wypróbuj online! Pobiera dane wejściowe jako 11-znakowy ciąg 9 Xs, Os lub -s w trzech grupach po trzy oddzielone ;s, chociaż łącze zawiera nagłówek, który tłumaczy podane przypadki testowe na ten format. Działa poprzez dopasowanie linii wygrywającej bezpośrednio za pomocą grupy równoważącej, aby zapewnić, że trzy pasujące znaki są w równej odległości. (Odpowiednie odległości to 0 (linia pozioma), 4 (odwrotna przekątna), 5 (linia pionowa) lub 6 (przekątna); inne odległości uderzyłyby ;lub rozciągałyby się poza sznurkiem.)

Neil
źródło
1

Java 8, 112 108 106 104 90 102 93 bajtów

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

+12 bajtów (90 → 102) ze względu na naprawę błędu polegającego na sprawdzeniu tylko jednej przekątnej zamiast obu ..
-9 bajtów (102 → 93) przy użyciu replaceAllzamiast matches.

Wejście w formacie XOX OX_ O_X, wyjścia X, Oalbo T.

Wyjaśnienie:

Wypróbuj tutaj.

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)

Wyjaśnienie wyrażenia regularnego:

.*(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)
Kevin Cruijssen
źródło
0

Siatkówka , 127 bajtów

.*(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
..+
_

Wypróbuj online!

... Myślę, że możesz nazwać tę brutalną siłą ... Pomyślałem, że może być w tym jakaś zasługa ...

całkowicie ludzki
źródło
0

Siatkówka , 51 bajtów

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

Port mojej odpowiedzi Java 8 . Wejście w formacie XOX OX_ O_X, wyjścia X, Oalbo T.

Wyjaśnienie:

Wypróbuj tutaj.

.*(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
Kevin Cruijssen
źródło
0

J, 34 bajty

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

Nie golfowany:

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

Wyjaśnienie

Kodowanie:

X = 2
O = 3
_ = 1

Nasza strategia na wysokim poziomie polega na stworzeniu matrycy, której każdy z rzędów jest możliwą wygraną. Pierwszy rząd to przekątna /, rząd 2 to przekątna \, następne trzy rzędy to rzędy, a ostatnie trzy rzędy to kolumny. Ta część została zrealizowana poprzez wyrażenie (używając Item Amend }):

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

Na koniec bierzemy GCD każdego rzędu:

+./"1

Dzięki naszemu kodowaniu każdy wiersz ze spacją będzie miał GCD równy 1, podobnie jak każdy wiersz zawierający dowolną mieszankę Xs i OS, ponieważ 2 i 3 są pierwszymi kopiami. Więc wszystko, co musimy zrobić, to znaleźć maksymalny element:>./

Jeśli gra jest remisowa, będzie to 1. Jeśli gracz wygra, będzie to numer tego gracza.

Wypróbuj online!

Jonasz
źródło
0

JavaScript, 66 bajtów

([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)

Prostota.

  • Dane wejściowe: ciąg znaków lub tablica liczb lub ciągów znaków, 0odpowiadające pustej spacji, 1X i2 O.
  • Wyjście: 0remis, 1zwycięstwo X, zwycięstwo 2O.

Rozszerzone, lekko komentowane:

( [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
Yair Rand
źródło