Tic Tac Toe: imprime todas las posiciones posibles sin duplicados


8

Escriba un programa que muestre todas las posiciones posibles de Tic Tac Toe, incluido el resultado del juego correspondiente. Evite la salida duplicada de posiciones iguales.

El programa no toma ninguna entrada.

Reglas:

  • Una salida de posición debe constar de 9 caracteres, utilizando Xy Opara los cuadrados tomados, y un carácter arbitrario que no sea un espacio en blanco para los cuadrados en blanco
  • Cada posición debe imprimirse en 3 líneas / columnas, con una línea en blanco como separador entre dos posiciones.
  • Se admiten espacios en blanco adicionales / líneas en blanco / caracteres de dibujo de recuadro
  • El jugador X va primero
  • El resultado puede ser cualquiera de:

    • X ha ganado
    • O ha ganado
    • Dibujar
    • Juego en progreso

    Usted es libre de elegir una visualización adecuada del resultado de la posición, por ejemplo, como texto en color o como anotación textual, siempre que se coloque cerca de la posición correspondiente

  • Las posiciones se consideran iguales si una se puede obtener de la otra por rotación o reflejo. No se deben imprimir posiciones duplicadas. (En otras palabras, imprima solo las clases de igualdad).
    Por ejemplo, imprima solo uno de los siguientes:
X••  ••X  •••  •••
•••  •••  •••  •••
•••  •••  X••  ••X

Salida de muestra:

•••
•••
••• -

X••
•••
••• -

•X•
•••
••• -

•••
•X•
••• -


[…]


XXO
OOX
XXO /

OXO
XXX
OXO X

Sugerencia: Hay 765 posiciones, con 91 victorias para X, 44 victorias para O y 3 empates.


Se ha hecho una pregunta similar antes, pero esta es diferente.


2
Bienvenido a PPCG! Cada desafío en PPCG debe tener un criterio ganador. ¿Cuál es el criterio para este desafío? ¿Es code-golf donde gana el programa con el bytecount más corto?
user41805

Si confirma el criterio ganador, esto debería abrirse nuevamente pronto. Todavía no he contado las posiciones, pero me preguntaba, ¿es el tablero vacío a) obligatorio b) prohibido c) opcional?
Level River St

Acabo de darme cuenta, ya dijiste que el código más corto gana. Edición en código-etiqueta de golf. Por lo general, puntuamos por número de bytes aquí, porque hay algunos idiomas específicamente inventados para usar caracteres multibyte para acortar el código, lo cual no es muy interesante.
Level River St

@StephenS Eso es algo diferente. Un byte puede tener cualquier valor entre 0 y 255. Este sitio web solo puede mostrar caracteres de un solo byte en el rango de 32-126 más algunos otros. Las páginas de códigos de 256 bytes han existido durante siglos y yo mismo he publicado respuestas C en la página de códigos 437. UTF-8 fue inventado porque estas páginas de códigos no tenían suficientes caracteres para todos los lenguajes naturales, pero UTF-8 no está diseñado para manejar texto sin texto. datos con bytes aleatorios. Me refería a idiomas como esolangs.org/wiki/Sclipting, que utiliza ampliamente caracteres asiáticos multibyte para explotar la escapatoria de la puntuación en caracteres
Level River St

@LevelRiverSt ah, te tengo. Gracias por la información :)
Stephen

Respuestas:


5

Gelatina , 192 179 168 bytes

5ĿḢṠµFf0L¬ị⁾-/µ5ĿḢṠµ?
U,µṚ,µ€µ“æɗþƑ’DịFs3,µ€€Fs9s3$€Ṣ
FSµ×’¬
ÑPµA_µọ9n1
,UŒDḢ$€;;ZS€f3,-3
Ç,SS€µṪµṪCµSṠ‘µ?÷Ḣ
Ça3Ŀa4Ŀ
3ṗ9_2s3$€ÇÐf2Ŀ€QḢ€µ;ÑFµ€µ3Ḷ’,“O¤X”yµ€Fs10µs3Gµ€j⁾¶¶

Pruébalo en línea! (Toma alrededor de 30 segundos, así que sea paciente).

Cómo funciona

Resumen de alto nivel:

En pasos intermedios, esto almacena X como 1, sin colocar como 0, y O como -1. El programa genera todas las posibilidades de 3 ^ 9, luego mantiene solo las posiciones válidas en función del cumplimiento de los tres criterios:

  • Hay 1 o 0 más X que O.
  • No tanto X como O han ganado.
  • Si X ha ganado, hay 1 X más que O. Si O ha ganado, hay un número igual de Os y Xs.

Luego, el programa reemplaza cada estado del juego con todas sus rotaciones y reflexiones para obtener una lista de todas las clases de equivalencia. Esta es la operación que lleva la mayor parte del tiempo.

El primer estado del juego se toma de cada una de las clases de equivalencia, luego se calcula quién ganó.

Dónde sucede esto Las líneas están numeradas para facilitar la lectura.

1: 5ĿḢṠµFf0L¬ị⁾-/µ5ĿḢṠµ?          ••calculates who wins (output as -1 or 1) or draw ("-") or in game ("/")
                 µ5ĿḢṠµ?          - if(someone won based on line 5):
   5ĿḢṠ                             - return 1 if X won and -1 if O won
       µ                          - else:
        Ff0L¬ị⁾-/                   - return "/" if the game is in progress and "-" if the game is at a tied end-state
2: U,µṚ,µ€µ“æɗþƑ’DịFs3,µ€€Fs9s3$€Ṣ••outputs the equivalence class to a game state
   U,                             - list of game state [reflected horizontally, unaltered]
     µṚ,µ€                        - for each, replace with the list [reflected vertically,unaltered]
          µ“æɗþƑ’DịFs3,µ€€        - for each, replace with the list [rotated 90 degrees counter-clockwise,unaltered]
                          Fs9s3$€ - reformat into list of game states
                                 Ṣ- Sort
3: FSµ×’¬                         ••outputs truthy iff there is the right number of `X`s to `O`s (condition 1)
   FS                             - d = number of `X`s minus number of `O`s
     µ×’                          - d*(d-1): falsey iff d is 0 or 1
        ¬                         - logical not, to return truthy iff d is 0 or 1
4: ÑPµA_µọ9n1                     ••outputs truthy iff there is the right number of winners (condition 2)
   Ñ                              - the winners. [-3,3] is what we want to return falsy on
    PµA_µ                         - 18 on [-3,3] and 0 otherwise
         ọ9n1                     - not divisible by 9 exactly once: 0 on [-3,3] and 1 otherwise
5: ,UŒDḢ$€;;ZS€f3,-3              ••outputs the number of times each player won.
   ,UŒDḢ$€;;Z                     - the diagonals, rows, and columns of a board
             S€                   - sum of each. Returns -3 or 3 iff the line is only 1s or -1s
               f3,-3              - filter out, keeping only 3s and -3s
6: Ç,SS€µṪµṪCµSṠ‘µ?÷Ḣ             ••return truthy iff the winner corresponds to the respective numbers of X and O (condition 3)
   Ç,SS€                          - list of winners and how many more Xs than Os there are
             µSṠ‘µ?               - if O won, then
        µṪ                          - how many more Xs than Os there are
                                  - else:
          µṪC                       - the complement of how many more Xs than Os there are
                   ÷Ḣ             - deal with no one winning
7: Ça3Ŀa4Ŀ                        ••return truthy iff the game state meets all three conditions
   Ç 3Ŀ 4Ŀ                        - the three conditions: on line 3,4, and 6
    a  a                          - joined by logical ANDs
8: 3ṗ9_2s3$€ÇÐf2Ŀ€QḢ€µ;ÑFµ€µ3Ḷ’,“O¤X”yµ€Fs10µs3Gµ€j⁾¶¶ ••do everything
   3ṗ9_2                        - all possible game states, with -1 for O and 1 for X
        s3$€                    - turn into two-dimensional game boards
            ÇÐf                 - filter based on line 6: if the board meets all three ocnditions
               2Ŀ€Q             - generate the equivalence classes for each and remove repeats based on line 1
                   Ḣ€           - get the first board from each class
                     µ;ÑFµ€     - append the winner to each board based on line 1
   µ3Ḷ’,“O¤X”yµ€                   - map each -1, 0, and 1 to the proper `O`,  `¤`, and `X`.
                Fs10µs3Gµ€         - format each board- winner combos
                          j⁾¶¶     - join the combos by double-newlines

2

Rubí, 305 bytes.

19683.times{|i|c=(i%3).to_s 
s=(9**8+i/3*6562).to_s(3)
w=0
t=(0..3).map{|j|r=s[1+j*2,9]
w|=1<<r[0..2].sum%8|1<<(c+r[j/2]+r[4+j/2]).sum%8
[r,r.reverse].min}.min
v=t[0..2]+$/+t[7]+c+t[3]+$/+t[6]+t[5]+t[4]
w&=65
b=v.sum%51
w<65&&b>w/64&&b<3-w%2&&t==s[1,9]&&puts(v.tr("012","X.O"),w<1?v.include?(?1):w%31,"")}

Esto funciona de manera similar a las otras respuestas, ya que genera todos los 3**9paneles y luego filtra los válidos. Internamente, usamos números ternarios 0=X 1=. 2=Oen la salida. Repite clos 3 valores posibles para el centro y slos 3**8 = 6561valores para el perímetro. Antes de convertir i/3a una representación de cadena de un número ternario, multiplicamos por 6562para duplicar todos los dígitos, y sumamos 3**16para comenzar el número con un 1, para asegurar que haya ceros a la izquierda cuando corresponda. wes la condición ganadora: establezca esto en cero.

Para cada tablero, itere a través de 4 rotaciones de los dígitos spara encontrar la versión léxicamente más baja del número ternario actual de 8 dígitos que representa el perímetro. Al mismo tiempo, agregue los valores ascii de los primeros 3 dígitos (fila superior de la rotación actual) y use esto para verificar una ganancia. Además, agregue los valores ascii de cy un par de dígitos diametralmente opuestos para verificar si hay una victoria en el centro.

Compruebe si la salida es válida : si tanto el bit 1 como el bit 64 westán configurados, ambos lados ganan, esto no es válido. Verifique el saldo de X y O (si todavía no hay un ganador, puede ser X y O igual o una X más, pero si el juego se gana, solo hay un valor posible, ya que el ganador debe haber sido el último). Para evitar mostrar diferentes rotaciones de la misma placa, solo emita si la versión léxicamente más baja del perímetro corresponde al valor actual de s[2,9].

Salida del tablero , sustituyendo los símbolos tr("012","X.O"). El estado del juego se muestra debajo del tablero. Si w = 0, esto es truesi todavía hay cuadrados vacíos (el juego aún está en progreso) y falsesi el tablero está lleno. Si wno es cero, sacamos 1si el jugador 1 (X) ha ganado o 64%31==2si el jugador 2 (O) ha ganado.

Sin golf

19683.times{|i|                             #check 3**9 possibilities
  c=(i%3).to_s                              #centre square: 0=X, 1=. 2=O 
  s=(9**8+i/3*6562).to_s(3)                 #perimeter:multiply i/3 by 3**8+1 to duplicate digits, add 3**16 to give a 1 at left side to ensure leading zeros
  w=0                                       #set w=0 to clear wins (1´s bit holds win for X, 64´s bit holds win for O)
  t=(0..3).map{|j|                          #build an array of 4 different rotations of the perimeter
     r=s[1+j*2,9]                           #by taking different 9-character slices of s
     w|=1<<r[0..2].sum%8|                   #add ascii codes mod 8 for top row of current rotation, take sum modulo 8 to give sum of digits. set a bit in w (we only care about bits 0 and 6)
        1<<(c+r[j/2]+r[4+j/2]).sum%8        #do the same for one of the 4 lines through the centre. if j/2=0 check diagonal, if j/2=1 check horizontal/vertical. 
     [r,r.reverse].min}.min                 #add to the array the lexically lowest version(forward or reverse) of the current rotation. When the loop ends, find the lexically lowest version overall and assign to t.
  v=t[0..2]+$/+t[7]+c+t[3]+$/+t[6]+t[5]+t[4]#format the output into a square 012\n 7c3\n 654
  w&=65                                     #clear bits 1 through 5 of w, leave only bits 0 and 6 which are the ones of interest.
  b=v.sum%51                                #valid values of sum of ascii codes in output are 461 (equal 0's and 2's) and 460 (one more 0 than 2). Take modulo 51 to reduce these values to 1 and 2       
  w<65&&                                    #if a maximum of one player has a winning line (not both) and
  b>w/64&&                                  #b must be 1 or 2 (only 2 permitted if O's won)
  b<3-w%2&&                                 #b must be 1 or 2 (only 1 permitted if X's won)
  t==s[1,9]&&                               #s[2,9] is the lexically lowest version of the current board (to avoid duplicates) then 
  puts(v.tr("012","X.O"),                   #output the board, subsituting internal "012" characters for external "X.O"
  w<1?v.include?(?1):w%31,"")               #if nobody won, output true if game in still in play (1's present on board) else false
}                                           #if there is a winner, output (player) 1 for X, (player) w%31=2 for O. Also output a blank line.

Esquema de comprobación

Los diagramas a continuación muestran el esquema de rotación (y verificación de victorias, en mayúsculas). Los diagramas se muestran sin rotar. Las cuatro rotaciones diferentes se toman como subcadenas de la copia doble de i/3, con las 3 letras mayúsculas consecutivas en el perímetro de cada diagrama (la "parte superior" por rotación actual) son los primeros 3 caracteres en la subcadena de 9 caracteres. Para cada rotación, también se intenta la inversión de 9 caracteres (giro diagonal sobre el eje AE o CG). La placa solo sale si el valor actual de i/3es el léxico más bajo de todas las rotaciones y espejos.

 ABC    abC    aBc    Abc 
 hZd    hZD    hZd    HZD
 gfE    GfE    GFE    Gfe

2

Python 2 , 648 620 bytes

import re
M=re.match
x='X';o='O'
R=lambda b,z=[6,3,0,7,4,1,8,5,2]:''.join(b[z[i]]for i in range(9))
p='XXX......|...XXX...|......XXX|X...X...X';q=p.replace(x,o)
def e(b):c=b.count;d=c(x)-c(o);w=M(p,b)or M(p,R(b));v=M(q,b)or M(q,R(b));return 0 if d not in[0,1]else 0 if w and v else(x if d==1 else 0)if w else(o if d==0 else 0)if v else'.'if'.'in b else'/'
h=set()
for n in range(3**9):
 b=reduce(lambda a,v:('.XO'[a[1]%3]+a[0],a[1]/3),range(9),('',n))[0]
 if b not in h:
	u=e(b)
	if u:print'%s\n%s\n%s %s\n'%(b[:3],b[3:6],b[6:],u)
	h.update(reduce(lambda a,v:a+[R(a[-2]),R(a[-1])],range(3),[b,R(b,[2,1,0,5,4,3,8,7,6])]))

Pruébalo en línea!

Probablemente un poco de golf menor posible aquí con este enfoque; pero no mucho.

Editar: Thx a ovs, que notó un ajuste que gana 28 bytes; y 3 de Artemis Fowl

Código sin golf

La idea básica aquí es: fuerza bruta cada una de las 3 ^ 9 = 19683 posibles codificaciones de placa. Mantenga un registro de los conjugados (rotaciones y reflexiones) de tableros que ya han sido examinados para no duplicar entradas. Como mínimo, los tableros válidos deben tener un número igual de X y O o una X más que O. No es posible tener tanto una victoria para X como una victoria para O; más algunas restricciones meticulosas adicionales.

import re
from collections import Counter

FLIP_XFRM = [2,1,0,5,4,3,8,7,6]
ROT_XFRM = [6,3,0,7,4,1,8,5,2]

def xfrm(b, xf):
    return ''.join(b[xf[i]] for i in range(9))

def flipIt(b):
    return xfrm(b,FLIP_XFRM)

def rotIt(b):
    return xfrm(b,ROT_XFRM)

def conjugates(b):
    conj = [b, flipIt(b)]
    for i in range(3):
        conj += [rotIt(conj[-2]), rotIt(conj[-1])]
    return conj

def tttToB(n):
    b = ''
    for i in range(9):
        b = '.XO'[n %3]+b
        n /= 3
    return b

def printBoard(b,outcome='.'):
    print '%s\n%s\n%s %s\n' % (b[:3],b[3:6],b[6:],outcome)

def evalBoard(b):
    c = Counter(b)
    if c['X']-c['O'] not in [0,1]:
        return False

    p1 = 'XXX......|...XXX...|......XXX|X...X...X'
    p2 = p1.replace('X','O')

    br = rotIt(b)
    w1 = re.match(p1,b) or re.match(p1,br)    
    w2 = re.match(p2,b) or re.match(p2,br)    
    if w1 and w2:
        return False

    if w1:
        return 'X' if c['X']==c['O']+1 else False

    if w2:
        return 'O' if c['X']==c['O'] else False

    if '.' in b:
        return '.'
    else:
        return '/'

def main():
    history = set()
    for m in range(3**9):
        b = tttToB(m)
        if b not in history:
            outcome = evalBoard(b)
            if outcome:
                printBoard(b,outcome)
            history.update(conjugates(b))

main()

No creo que necesites el Counter. Puede reemplazarlo conc=b.count;d=c(x)-c(o)
ovs

@ovs: tan notado!
Chas Brown

Ese gran tiempo returnpuede serreturn 0if d not in[0,1]else 0if w and v else(x*(d==1))if w else(o*(d==0))if v else'.'if'.'in b else'/'
Zacharý

Publicación anterior lo sé, pero esto parece ser 623 bytes? Puede reemplazar el segundo nivel de sangría (2 espacios) con una sola pestaña para 620 bytes, ¿tal vez quiso hacer esto?
Artemisa todavía no confía en SE

@ArtemisFowl Sí, esto fue antes de que descubriera TIO: ¡es fácil cometer errores de conteo!
Chas Brown
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.