Determinar ganador de Tic-Tac-Toe (basado en ronda)

26

¡Juguemos un poco de golf de código!

El desafío es encontrar al ganador de un juego de Tic-Tac-Toe.

Esto se ha hecho muchas veces dando una tabla que tiene un ganador claro pero aquí está el giro:

Las celdas están numeradas así:

1|2|3
-+-+-
4|5|6
-+-+-
7|8|9

Obtiene una matriz de exactamente 9 movimientos así:

{3, 5, 6, 7, 9, 8, 1, 2, 3}

Esto se analiza de la siguiente manera:

  • El jugador 1 marca la celda 3
  • El jugador 2 marca la celda 5
  • El jugador 1 marca la celda 6
  • El jugador 2 marca la celda 7
  • El jugador 1 marca la celda 9
  • El jugador 1 ha ganado

Nota: El juego no se detiene después de que un jugador ha ganado, puede suceder que el jugador perdedor logre obtener tres seguidos después del jugador ganador, pero solo cuenta la primera victoria.

Su trabajo ahora es obtener 9 números como entrada y salida del jugador ganador y la ronda en la que ocurrió la victoria. Si nadie gana, muestra algo constante de tu elección. Puede recibir entradas y proporcionar salidas a través de cualquier media / formato estándar.

¡Que te diviertas!

Algunos ejemplos más según lo solicitado:

{2,3,4,5,6,7,1,8,9} => Player 2 wins in round 6
{1,2,4,5,6,7,3,8,9} => Player 2 wins in round 8
{1,2,3,5,4,7,6,8,9} => Player 2 wins in round 8
Grunzwanzling
fuente
11
Bienvenido a PPCG! Esta es una buena primera publicación, pero generalmente no nos gustan los formatos de entrada / salida muy restrictivos . ¿Consideraría eliminar el "Jugador X gana en la ronda Y" y dejarnos salir en cualquier formato razonable, como una lista [X, Y]? En caso de empate, ¿podemos generar algún otro valor consistente? Lo recomiendo, porque imprimir esas cadenas exactas no es realmente parte del golf. Para futuras ideas de desafío, recomiendo usar el sandbox . :-)
Sr. Xcoder
Disculpa, me equivoque. Creo que es correcto ahora.
Grunzwanzling
Lea el desafío hasta el final, le digo que puede haber un empate y que puede sacar algo de su elección cuando suceda. Devuelvo {2,6} cuando el jugador 2 gana en la ronda 6 y {0,0} cuando nadie gana.
Grunzwanzling
¿Podemos usar todo indexado 0? (células, jugadores, rondas)
Arnauld
1
"Obtiene una serie de exactamente 9 movimientos así: {3, 5, 6, 7, 9, 8, 1, 2, 3}" - ¿ 3realmente debería aparecer dos veces?
Jonathan Allan el

Respuestas:

8

Retina , 114 bytes

(.)(.)
$1O$2X
^
123;;456;;789¶X
{`(.)(.*¶)(.)\1
$3$2
}`.*(.)(.)*\1(?<-2>.)*(?(2)(?!))\1.*¶(..)*
$1$#3
.*¶
T
T`d`Rd

Pruébalo en línea! ¿De acuerdo con mi respuesta a Tic-Tac-Toe - X u O? . Salidas X<N>si el primer jugador gana después de los Nturnos, O<N>si el segundo jugador gana, Tsi ninguno gana. Explicación:

(.)(.)
$1O$2X
^
123;;456;;789¶X

Crea un tablero interno y también marca cada movimiento con el jugador cuyo movimiento es.

{`(.)(.*¶)(.)\1
$3$2

Aplica un movimiento.

}`.*(.)(.)*\1(?<-2>.)*(?(2)(?!))\1.*¶(..)*
$1$#3

Busca una victoria y, si encuentra una, reemplace el tablero con el ganador y el número de movimientos restantes.

.*¶
T

Si los movimientos están agotados y nadie ha ganado, entonces el juego es un empate.

T`d`Rd

Calcule el número de la ronda a partir del número de movimientos restantes.

Neil
fuente
44
Esta es una de las respuestas más ... voluptuosas que he visto aquí.
Lord Farquaad el
6

MATL , 39 bytes

3:g&+XIx"IX@oXK@(XIt!yXdyPXd&hK=Aa?KX@.

La salida es

  • 1y R, en líneas separadas, si el usuario 1 gana en la ronda R ;
  • 0y R, en líneas separadas, si el usuario 2 gana en la ronda R ;
  • vacío si nadie gana.

Pruébalo en línea! O verificar todos los casos de prueba .

Explicación

3:       % Push [1 2 3]
g        % Convert to logical. Gives [true true true]
&+       % Matrix of all pairs of additions. Gives a 3×3 matrix, which represents
         % the board in its initial state, namely all cells contain 2. This value
         % means "cell not used yet". 1 will represent "cell marked by user 1",
         % and 0 will represent "cell marked by user 2"
XI       % Copy into clipboard I
x        % Delete
"        % Implicit input: array with moves. For each move
  I      %   Push current board state
  X@     %   Push iteration index (starting at 1), that is, current round number
  o      %   Modulo 2: gives 1 or 0. This represents the current user
  XK     %   Copy into clipboard K
  @      %   Push current move ((that is, cell index)
  (      %   Write user identifier (1 or 0) into that cell. Cells are indexed
         %   linearly in column-major order. So the board is transposed compared
         %   to that in the challenge, but that is unimportant
  XI     %   Copy updated board into clipboard I
  t!     %   Duplicate and transpose
  y      %   Duplicate from below: push copy of board
  Xd     %   Extract main diagonal as a 3×1 vector
  y      %   Duplicate from below: push copy of transposed board
  PXd    %   Flip vertically and extract main diagonal. This is the anti-diagonal
         %   of the board
  &h     %   Concatenate stack horizontally. This concatenates the board (3×3),
         %   transposed board (3×3), main diagonal (3×1 vector) and anti-diagonal
         %   (3×1) into an 3×8 matrix
  K=     %   Push current user identifier. Test for equality with each entry of the
         %   3×8 matrix
  A      %   For each column, this gives true if all its entries are true. Note 
         %   that the first three columns in the 3×8 matrix are the board columns;
         %   the next three are the board rows; and the last two columns are the
         %   main diagonal and anti-diagonal. The result is a 1×8 vector
  a      %   True if any entry is true, meaning the current user has won
  ?      %   If true
    K    %     Push current user identifier
    X@   %     Push current round number
    .    %     Break for loop
         %   Implicit end
         % Implicit end
         % Implicit display
Luis Mendo
fuente
5

Javascript (ES6), 130 bytes

m=>m.reduce((l,n,i)=>l||(b[n-1]=p=i%2+1,"012,345,678,036,147,258,048,246".replace(/\d/g,m=>b[m]).match(""+p+p+p)&&[p,i+1]),0,b=[])

f=m=>m.reduce((l,n,i)=>l||(b[n-1]=p=i%2+1,"012,345,678,036,147,258,048,246".replace(/\d/g,m=>b[m]).match(""+p+p+p)&&[p,i+1]),0,b=[])
console.log(JSON.stringify(f([3,5,6,7,9,8,1,2,3])))
console.log(JSON.stringify(f([2,3,4,5,6,7,1,8,9])))
console.log(JSON.stringify(f([1,2,4,5,6,7,3,8,9])))
console.log(JSON.stringify(f([1,2,3,5,4,7,6,8,9])))

Explicación

m=>m.reduce((l,n,i)=>               // Reduce the input array with n as the current move
  l||(                              //  If there is already a winner, return it
  b[n-1]=p=i%2+1,                   //  Set the cell at b[n-1] to the current player p
  "012,345,678,036,147,258,048,246" //  For every digit in the list of possible rows:
    .replace(/\d/g,m=>b[m])         //   Replace it with the player at the cell
    .match(""+p+p+p)                //  If any of the rows is filled with p:
      &&[p,i+1]                     //   Return [p, current move]
),0,b=[])
Herman L
fuente
¿Te importaría dar una explicación o una versión sin golf por favor? Estoy interesado en entender tu solución.
Jack
4

Java (OpenJDK 8) , 445 bytes

int[] t(int[]m){int[][]f=new int[3][3];boolean z=false;for(int i=0;i<9;i++){f[m[i]%3][m[i]/3]=z?2:1;if(f[m[i]%3][0]==(z?2:1)&&f[m[i]%3][1]==(z?2:1)&&f[m[i]%3][2]==(z?2:1)||f[0][m[i]/3]==(z?2:1)&&f[1][m[i]/3]==(z?2:1)&&f[2][m[i]/3]==(z?2:1)||m[i]%3+m[i]/3==2&&f[0][2]==(z?2:1)&&f[1][1]==(z?2:1)&&f[2][0]==(z?2:1)||m[i]%3==m[i]/3&&f[0][0]==(z?2:1)&&f[1][1]==(z?2:1)&&f[2][2]==(z?2:1)){return(new int[]{(z?2:1),++i});}z=!z;}return(new int[]{0,0});}

Pruébalo en línea!

El valor de retorno {1,8} significa que el jugador 1 ganó en la ronda 8. El valor de retorno {0,0} significa empate.

Grunzwanzling
fuente
55
A menos que elimine todo el espacio innecesario, esta respuesta se considera inválida debido a la falta de esfuerzo de golf. Además, no se recomienda realmente responder a su propio desafío tan rápido, y es posible que desee agregar un enlace TIO para que podamos probar su código.
Sr. Xcoder
Enlaces de referencia: contendiente serio , compite en tu propio desafío
usuario202729
Lo siento, copié la cosa equivocada. De hecho, es mucho más corto
Grunzwanzling
Puede ver los consejos para jugar golf en la pregunta de Java para eliminar algunos bytes. Por ejemplo, falsepuede reemplazarse por 1<0, y el espacio después del primero ]puede eliminarse.
user202729
442 bytes . También la razón por la cual la sección "Encabezado" y "Pie de página" existe en TIO es que no necesita comentar //Code that was submittedy //End of code.
user202729
2

Kotlin , 236 bytes

i.foldIndexed(l()to l()){o,(a,b),p->fun f(i:(Int)->Int)=b.groupBy(i).any{(_,v)->v.size>2}
if(f{(it-1)/3}|| f{it%3}|| listOf(l(1,5,9),l(3,5,7)).any{b.containsAll(it)}){return p%2+1 to o}
b to a+p}.let{null}
fun l(vararg l:Int)=l.toList()

Embellecido

    i.foldIndexed(l() to l()) { o, (a, b), p ->
        fun f(i: (Int) -> Int) = b.groupBy(i).any { (_, v) -> v.size > 2 }
        if (f { (it - 1) / 3 } || f { it % 3 } || listOf(l(1, 5, 9), l(3, 5, 7)).any { b.containsAll(it) }) {
            return p % 2 + 1 to o
        }
        b to a + p
    }.let { null }
fun l(vararg l:Int)= l.toList()

Prueba

fun f(i: List<Int>): Pair<Int, Int>? =
i.foldIndexed(l()to l()){o,(a,b),p->fun f(i:(Int)->Int)=b.groupBy(i).any{(_,v)->v.size>2}
if(f{(it-1)/3}|| f{it%3}|| listOf(l(1,5,9),l(3,5,7)).any{b.containsAll(it)}){return p%2+1 to o}
b to a+p}.let{null}
fun l(vararg l:Int)=l.toList()

data class Test(val moves: List<Int>, val winner: Int, val move: Int)

val tests = listOf(
        Test(listOf(3, 5, 6, 7, 9, 8, 1, 2, 3), 1, 5),
        Test(listOf(2, 3, 4, 5, 6, 7, 1, 8, 9), 2, 6),
        Test(listOf(1, 2, 4, 5, 6, 7, 3, 8, 9), 2, 8),
        Test(listOf(1, 2, 3, 5, 4, 7, 6, 8, 9), 2, 8)
)

fun main(args: Array<String>) {
    tests.forEach { (input, winner, move) ->
        val result = f(input)
        if (result != winner to move) {
            throw AssertionError("$input ${winner to move} $result")
        }
    }
}

TIO

TryItOnline

jrtapsell
fuente
1

Python 2 , 170 bytes

q=map(input().index,range(1,10))
z=zip(*[iter(q)]*3)
o='',
for l in[q[2:7:2],q[::4]]+z+zip(*z):
 r=[n%2for n in l];y=all(r)*2+1-any(r)
 if y:o+=[max(l)+1,y],
print min(o)

Pruébalo en línea! o Pruebe todos los casos de prueba

#swap cell number / turn
q=map(input().index,range(1,10))
#split in 3 parts (rows)
z=zip(*[iter(q)]*3)
#starting value for the list with the results
#since string are "greater" than lists, this will
#be the output value when there is a draw
o='',
#iterate over diagonals, rows and columns
for l in[q[2:7:2],q[::4]]+z+zip(*z):
 #use %2 to separate between player 1 and 2
 r=[n%2 for n in l]
 #store in y the value of the player if the trio is a valid win, 0 otherwise
 #it's a win if all moves are from the same player
 y=all(r)*2+1-any(r)
 #if y has a valid player, add the highest turn of the trio, and the player to o
 if y:o+=[max(l)+1,y],
#output the smaller turn of the valid winning trios
print min(o)
Barra
fuente
1

Jalea , 38 bytes

;⁵s2ZṬḤ2¦SṖs3µ,ṚJị"$€;;ZEÐfṀḢµ$ƤµTḢ,ị¥

Pruébalo en línea!

Jugador 1 triunfo: [round, 1]
Jugador 2 triunfo: [round, 2]
Empate:[0, 0]

Erik el Outgolfer
fuente
1

Python 3.6+, 137 bytes

n=m=c=z=0
for a in input():m+=1<<~-int(a);c+=1;z=z or f'{c&1}:{c}'*any(m&t==t for t in[7,56,448,73,146,292,273,84]);n,m=m,n
print(z or-1)

El formato de salida es winner number:roundo -1para un empate. El jugador 2 es el 0jugador 1 es 1. Ingrese en forma de una cadena no delimitada de números cuadrados indexados en 1.

mypetlion
fuente
1

Jalea , 35 bytes

9s3,ZU$$;ŒD$€Ẏf€⁸L€3e
s2ZÇƤ€ZFTḢ;Ḃ$

Un enlace monádico que toma una lista de los movimientos y devuelve una lista, [move, player]donde los jugadores se identifican como 1(primero en actuar) y 0(segundo en actuar).

Pruébalo en línea!

¿Cómo?

9s3,ZU$$;ŒD$€Ẏf€⁸L€3e - Link 1: any winning play?: list of player's moves:
9s3                   - (range of) nine split into threes = [[1,2,3],[4,5,6],[7,8,9]]
       $              - last two links as a monad:
      $               -   last two links as a monad:
    Z                 -     transpose = [[1,4,7],[2,5,8],[3,6,9]]
     U                -     upend     = [[7,4,1],[8,5,2],[9,6,3]]
   ,                  -  pair = [[[1,2,3],[4,5,6],[7,8,9]],[[7,4,1],[8,5,2],[9,6,3]]]
           $€         - last two links as a monad for €ach:
         ŒD           -   diagonals = [[1,5,9],[2,6],[3],[7],[4,8]] or [[7,5,3],[4,2],[1],[9],[8,6]]
        ;             -  concatenate = [[1,2,3],[4,5,6],[7,8,9],[1,5,9],[2,6],[3],[7],[4,8]] or [[7,4,1],[8,5,2],[9,6,3],[7,5,3],[4,2],[1],[9],[8,6]]
             Ẏ        - tighten = [[1,2,3],[4,5,6],[7,8,9],[1,5,9],[2,6],[3],[7],[4,8],[7,4,1],[8,5,2],[9,6,3],[7,5,3],[4,2],[1],[9],[8,6]]
                      -    i.e.:    row1    row2    row3    diag\   x     x   x   x     col1    col2    col3    diag/   x     x   x   x
                      -    where x's are not long enough to matter for the rest...
                ⁸     - chain's left argument, list of player's moves
              f€      - filter to keep those moves for €ach of those lists to the left
                 L€   - length of €ach result
                   3e - 3 exists in that? (i.e. were any length 3 when filtered down to only moves made?)

s2ZÇƤ€ZFTḢ;Ḃ$ - Main link: list of the moves  e.g. [2,3,4,5,6,7,1,8,9]
s2            - split into twos                    [[2,3],[4,5],[6,7],[1,8],[9]]
  Z           - transpose                          [[2,4,6,1,9],[3,5,7,8]]
    Ƥ€        - for Ƥrefixes of €ach:
   Ç          -   call last link (1) as a monad     [0,0,0,0,0] [0,0,1,1]
      Z       - transpose                          [[0,0],[0,0],[0,1],[0,1],[0]]
       F      - flatten                            [0,0,0,0,0,1,0,1,0]
        T     - truthy indices                     [          6   8  ]
         Ḣ    - head (if empty yields 0)           6
            $ - last two links as a monad:
           Ḃ  -   modulo by 2 (evens are player 2) 0
          ;   -   concatenate                      [6,0]
Jonathan Allan
fuente
0

Python 2, 168 bytes

import itertools as z
f=lambda g:next(([i%2+1,i+1]for i in range(9) if any(c for c in z.combinations([[0,6,1,8,7,5,3,2,9,4][j]for j in g[i%2:i+1:2]],3)if sum(c)==15)),0)

Salidas (jugador, ronda) o 0 para un empate.

Mapea el juego en un cuadrado mágico de 3 por 3 y busca conjuntos de 3 Os o X que suman 15.

aPaulT
fuente
0

Limpio , 244 ... 220 bytes

import StdEnv
f[a,b]i#k= \l=or[and[isMember(c+n)(take i l)\\c<-:"123147159357"%(j,j+2)]\\j<-[0,3..9]&h<-:"\0\0",n<-[h-h,h,h+h]]
|k a=(1,i*2-1)|i>4=(0,0)|k b=(2,i*2)=f[a,b](i+1)
@l=f(map(map((!!)l))[[0,2..8],[1,3..7]])1

Pruébalo en línea!

La cadena iterada en hcontiene no imprimibles, y es equivalente a "\003\001\000\000".

Οurous
fuente
0

Python 2 , 140 136 134 bytes

lambda a,i=0:i<9and(any(set(a[i%2:i+1:2])>=set(map(int,t))for t in'123 456 789 147 258 369 159 357'.split())and(i%2+1,i+1)or f(a,i+1))

Pruébalo en línea!

EDITAR: 4 bytes + 2 bytes gracias a Eric the Outgolfer.

Emite una tupla (playerNumber, roundNumber) o False si no hay un ganador.

Chas Brown
fuente
134 bytes
Erik the Outgolfer
@Erik - Yah, ya debería haberlo hecho; pero estoy luchando contra la gripe y me dolían los ojos :). ¡Gracias!
Chas Brown
Bueno, que te mejores pronto. :)
Erik the Outgolfer