ratings rated pegiinfo pegi games game esrb all code-golf rosetta-stone tic-tac-toe

code golf - rated - Código de golf: Tic Tac Toe



pegiinfo (30)

Publique su código más corto, por número de caracteres, para verificar si un jugador ha ganado, y si es así, cuál.

Supongamos que tiene una matriz de enteros en una variable b (tablero), que contiene el tablero de Tic Tac Toe, y los movimientos de los jugadores donde:

  • 0 = nada establecido
  • 1 = jugador 1 (X)
  • 2 = jugador 2 (O)

Entonces, dada la matriz b = [ 1, 2, 1, 0, 1, 2, 1, 0, 2 ] representaría el tablero

X|O|X -+-+- |X|O -+-+- X| |O

Para esa situación, su código debe mostrar 1 para indicar que el jugador 1 ha ganado. Si nadie ha ganado, puede generar 0 o false .

Mi propia solución (Ruby) estará lista pronto.

Edición : Lo sentimos, olvidé marcarlo como wiki de la comunidad. Puede asumir que la entrada está bien formada y no tiene que verificarse el error.

Actualización : Por favor, publique su solución en forma de una función. La mayoría de las personas ya lo han hecho, pero otras no, lo cual no es del todo justo. La placa se suministra a su función como parámetro. El resultado debe ser devuelto por la función. La función puede tener un nombre de su elección.


C, 77 (83) caracteres

Esta es una variante de la dmckee de dmckee , excepto que cada par de dígitos en la codificación compacta ahora es la base de 9 dígitos de los caracteres ASCII.

La versión de 77 caracteres, no funciona en MSVC:

// "J)9/t8/r=,/0" == 82,45,63,10,62,14,67,48,00 in base 9. char*k="J)9 8/r=,",c;f(int*b){return(c=*k++)?b[c/9]&b[c%9]&b[*k--%9]|f(b):0;}

Esta versión de 83 caracteres, debería funcionar en cada compilador de C:

f(int*b){char*k="J)9 8/r=,",s=0,c;while(c=*k++)s|=b[c%9]&b[c/9]&b[*k%9];return s;}

(Tenga en cuenta que los espacios entre el 9 y el 8 deben ser una pestaña. convierte todas las pestañas en espacios).

Caso de prueba:

#include <stdio.h> void check(int* b) { int h0 = b[0]&b[1]&b[2]; int h1 = b[3]&b[4]&b[5]; int h2 = b[6]&b[7]&b[8]; int h3 = b[0]&b[3]&b[6]; int h4 = b[1]&b[4]&b[7]; int h5 = b[2]&b[5]&b[8]; int h6 = b[0]&b[4]&b[8]; int h7 = b[2]&b[4]&b[6]; int res = h0|h1|h2|h3|h4|h5|h6|h7; int value = f(b); if (value != res) printf("Assuming f({%d,%d,%d, %d,%d,%d, %d,%d,%d}) == %d; got %d instead./n", b[0],b[1],b[2], b[3],b[4],b[5], b[6],b[7],b[8], res, value); } #define MAKEFOR(i) for(b[(i)]=0;b[(i)]<=2;++b[(i)]) int main() { int b[9]; MAKEFOR(0) MAKEFOR(1) MAKEFOR(2) MAKEFOR(3) MAKEFOR(4) MAKEFOR(5) MAKEFOR(6) MAKEFOR(7) MAKEFOR(8) check(b); return 0; }


C, 99 caracteres

No es un ganador, pero quizás haya margen de mejora. Nunca hice esto antes. Concepto original, primer borrador.

#define l w|=*b&b[s]&b[2*s];b+=3/s;s f(int*b){int s=4,w=0;l=3;l;l;l=2;--b;l=1;b-=3;l;l;return l;}

Gracias a KennyTM por algunas ideas y el arnés de prueba.

La "versión de desarrollo":

#define l w|=*b&b[s]&b[2*s];b+=3/s;s // check one possible win f( int *b ) { int s=4,w=0; // s = stride, w = winner l=3; // check stride 4 and set to 3 l;l;l=2; // check stride 3, set to 2 --b;l=1; // check stride 2, set to 1 b-=3;l;l; return l; // check stride 1 }


Lua, 130 caracteres

Los 130 caracteres es el tamaño de la función solamente. La función no devuelve nada si no se encuentra una coincidencia, lo que en Lua es similar a devolver falso.

function f(t)z={7,1,4,1,1,3,2,3,3}for b=1,#z-1 do i=z[b]x=t[i]n=z[b+1]if 0<x and x==t[i+n]and x==t[i+n+n]then return x end end end assert(f{1,2,1,0,1,2,1,0,2}==1) assert(f{1,2,1,0,0,2,1,0,2}==nil) assert(f{1,1,2,0,1,2,1,0,2}==2) assert(f{2,1,2,1,2,1,2,1,2}==2) assert(f{2,1,2,1,0,2,2,2,1}==nil) assert(f{1,2,0,1,2,0,1,2,0}~=nil) assert(f{0,2,0,0,2,0,0,2,0}==2) assert(f{0,2,2,0,0,0,0,2,0}==nil) assert(f{0,0,0,0,0,0,0,0,0}==nil) assert(f{1,1,1,0,0,0,0,0,0}==1) assert(f{0,0,0,1,1,1,0,0,0}==1) assert(f{0,0,0,0,0,0,1,1,1}==1) assert(f{1,0,0,1,0,0,1,0,0}==1) assert(f{0,1,0,0,1,0,0,1,0}==1) assert(f{0,0,1,0,0,1,0,0,1}==1) assert(f{1,0,0,0,1,0,0,0,1}==1) assert(f{0,0,1,0,1,0,1,0,0}==1)


Python, 140 caracteres

Mi primer código de golf, con un peso de 140 caracteres (declaración de importación, ¡lo niego!):

import operator as o def c(t):return({1:1,8:2}.get(reduce(o.mul,t[:3]),0)) def g(t):return max([c(t[x::y]) for x,y in zip((0,0,0,1,2,2,3,6),(1,3,4,3,3,2,1,1))])

Un poco menos oscuro g:

def g(t):return max([c(t[x::y]) for x,y in [[0,1],[0,3],[0,4],[1,3],[2,3],[2,2],[3,1],[6,1]]])


Python, 285 bytes

b,p,q,r=["."]*9,"1","2",range while"."in b: w=[b[i*3:i*3+3]for i in r(3)]+[b[i::3]for i in r(3)]+[b[::4],b[2:8:2]] for i in w[:3]:print i if["o"]*3 in w or["x"]*3 in w:exit(q) while 1: m=map(lambda x:x%3-x+x%3+7,r(9)).index(input()) if"."==b[m]:b[m]=".xo"[int(p)];p,q=q,p;break

... Oh, esto no era lo que querías decir cuando dijiste "Code Golf: Tic Tac Toe"? ;) (ingrese los números del teclado numérico para colocar los x o los o, es decir, 7 es noroeste)

Versión larga

board = ["."]*9 # the board currentname = "1" # the current player othername = "2" # the other player numpad_dict = {7:0, 8:1, 9:2, # the lambda function really does this! 4:3, 5:4, 6:5, 1:6, 2:7, 3:8} while "." in board: # Create an array of possible wins: horizontal, vertical, diagonal wins = [board[i*3:i*3+3] for i in range(3)] + / # horizontal [board[i::3] for i in range(3)] + / # vertical [board[::4], board[2:8:2]] # diagonal for i in wins[:3]: # wins contains the horizontals first, print i # so we use it to print the current board if ["o"]*3 in wins or ["x"]*3 in wins: # somebody won! exit(othername) # print the name of the winner # (we changed player), and exit while True: # wait for the player to make a valid move position = numpad_dict[input()] if board[position] == ".": # still empty -> change board if currentname == "1": board[position] = "x" else: board[position] = "o" currentname, othername = othername, currentname # swap values


(Hierro) pitón, 75 caracteres

75 caracteres para una función completa

T=lambda a:max(a[b/6]&a[b/6+b%6]&a[b/6+b%6*2]for b in[1,3,4,9,14,15,19,37])

66 caracteres si omite la definición de la función como lo han hecho otros.

r=max(a[b/6]&a[b/6+b%6]&a[b/6+b%6*2]for b in[1,3,4,9,14,15,19,37])

Las 8 direcciones diferentes se representan por valor de inicio + incrementador, comprimidas en un solo número que se puede extraer mediante división y módulo. Por ejemplo 2,5,8 = 2 * 6 + 3 = 15.

La comprobación de que una fila contiene tres valores iguales se realiza mediante el operador &. (lo que resulta en cero si no son iguales). max se utiliza para encontrar el posible ganador.


C #, 154 163 170 177 caracteres

Tomando prestadas un par de técnicas de otras presentaciones. (No sabía C # te permite iniciar matrices de esa manera)

static int V(int[] b) { int[] a={0,1,3,1,6,1,0,3,1,3,2,3,0,4,2,2}; int r=0,i=-2; while((i+=2)<16&&(r|=b[a[i]]&b[a[i]+a[i+1]]&b[a[i]+a[i+1]*2])==0){} return r; }


C, 113 caracteres

f(int*b){char*s="012345678036147258048264/0";int r=0;while(!r&&*s){int q=r=3;while(q--)r&=b[*s++-''0''];}return r;}

Creo que funciona? Mi primer código de golf, sé amable.

Cada 3 dígitos codifica 3 celdas que deben coincidir. El interior revisa una tríada. El exterior mientras comprueba los 8.


Haskell, asumiendo los cuadrados mágicos de arriba. 77 personajes

77 excluye importaciones y definición b.

import Data.Bits import Data.Array b = listArray (0,8) [2,1,0,1,1,1,2,2,0] w b = maximum[b!x.&.b!y.&.b!z|x<-[0..8],y<-[x+1..8],z<-[12-x-y],z<8,z>=0,z/=y]

O 82 asumiendo el orden normal:

{-# LANGUAGE NoMonomorphismRestriction #-} import Data.Bits import Data.Array b = listArray (0,8) [1,2,1,0,1,2,1,0,2] w b = maximum[b!x.&.b!y.&.b!z|x<-[0..8],d<-[1..4],y<-[x+d],z<-[y+d],d/=2||x==2,z<9]


J, 50 caracteres

w=:3 : ''{.>:I.+./"1*./"1]1 2=/y{~2 4 6,0 4 8,i,|:i=.i.3 3''


J, 97 caracteres.

1+1 i.~,+./"2>>(0 4 8,2 4 6,(],|:)3 3$i.9)&(e.~)&.>&.>(]<@:#"1~[:#:[:i.2^#)&.>(I.@(1&=);I.@(2&=))

Estaba planeando publicar una explicación de cómo funciona esto, pero eso fue ayer y ahora no puedo leer este código.

La idea es crear una lista de todos los triples ganadores posibles (048,246,012,345,678,036,147,258), luego hacer el conjunto de poderes de los cuadrados que cada jugador tiene y luego intersectar las dos listas. Si hay un partido, ese es el ganador.


Perl, 76 char

sub W{$n=$u=0;map{$n++;$u|=$_[$_-$n]&$_[$_]&$_[$_+$n]for/./g}147,4,345,4;$u}

Hay tres formas de ganar horizontalmente:

0,1,2 ==> 1-1, 1, 1+1 3,4,5 ==> 4-1, 4, 4+1 6,7,8 ==> 7-1, 7, 7+1

Una forma de ganar en diagonal desde la parte inferior izquierda a la superior derecha:

2,4,6 ==> 4-2, 4, 4+2

Tres formas de ganar verticalmente:

0,3,6 ==> 3-3, 3, 3+3 1,4,7 ==> 4-3, 4, 4+3 2,5,8 ==> 5-3, 5, 5+3

Una forma de ganar en diagonal desde la parte superior izquierda a la inferior derecha:

0,4,8 ==> 4-4, 4, 4+4

Lee las columnas del medio para obtener los números mágicos.


Perl, 87 85 caracteres

Una función que devuelve 0, 1 o 2, usando una expresión regular, por supuesto (la nueva línea solo existe para evitar la barra de desplazamiento):

sub V{$"='''';$x=''(1|2)'';"@_"=~ /^(...)*$x/2/2|^..$x./3./3|$x../4../4|$x.../5.../5/?$^N:0}

Se puede llamar como V(@b) , por ejemplo.


Python - 75 caracteres (64)

Se me ocurrieron 2 expresiones, cada una de 64chars:

max(a[c/8]&a[c/8+c%8]&a[c/8-c%8]for c in map(ord,''/t/33$#"!+9''))

y

max(a[c/5]&a[c/5+c%5]&a[c/5+c%5*2]for c in[1,3,4,8,12,13,16,31])

Cuando agregas "W = lambda b:" para que sea una función, eso hace 75chars. Python más corto hasta ahora?


Python 80 (69) char

No es la solución Python más corta, pero me gusta cómo introduce "DICE" en un juego de tic-tac-toe:

W=lambda b:max([b[c/5-9]&b[c/5+c%5-9]&b[c/5-c%5-9]for c in map(ord,"DICE>3BQ")])

69 caracteres para la expresión más simple:

max([b[c/5-9]&b[c/5+c%5-9]&b[c/5-c%5-9]for c in map(ord,"DICE>3BQ")])


Ruby, 115 caracteres

Ups: de alguna manera me misconté por mucho. Esto es en realidad 115 caracteres, no 79.

def t(b)[1,2].find{|p|[448,56,7,292,146,73,273,84].any?{|k|(k^b.inject(0){|m,i|m*2+((i==p)?1:0)})&k==0}}||false end # Usage: b = [ 1, 2, 1, 0, 1, 2, 1, 0, 2 ] t(b) # => 1 b = [ 1, 1, 0, 2, 2, 2, 0, 2, 1 ] t(b) # => 2 b = [ 0, 0, 1, 2, 2, 0, 0, 1, 1 ] t(b) # => false

Y el código ampliado, con fines educativos:

def tic(board) # all the winning board positions for a player as bitmasks wins = [ 0b111_000_000, # 448 0b000_111_000, # 56 0b000_000_111, # 7 0b100_100_100, # 292 0b010_010_010, # 146 0b001_001_001, # 73 0b100_010_001, # 273 0b001_010_100 ] # 84 [1, 2].find do |player| # find the player who''s won # for the winning player, one of the win positions will be true for : wins.any? do |win| # make a bitmask from the current player''s moves moves = board.inject(0) { |acc, square| # shift it to the left and add one if this square matches the player number (acc * 2) + ((square == player) ? 1 : 0) } # some logic evaluates to 0 if the moves match the win mask (win ^ moves) & win == 0 end end || false # return false if the find returns nil (no winner) end

Estoy seguro de que esto podría reducirse, especialmente la gran variedad y posiblemente el código para obtener una máscara de los movimientos de los jugadores, que me molesta, pero creo que esto es bastante bueno por ahora.


Ruby, 85 caracteres

def X(b) u=0 [2,6,7,8,9,13,21,-9].each do|c|u|=b[n=c/5+3]&b[n+c%5]&b[n-c%5]end u end

Si la entrada tiene ambos jugadores ganando, por ejemplo

X | O | X ---+---+--- X | O | O ---+---+--- X | O | X

entonces la salida es 3.


c - 144 caracteres

Minificado:

#define A(x) a[b[x%16]] int c,b[]={4,8,0,1,2,4,6,0,3,4,5,2,8,6,7,2};int T(int*a){for(c=0;c<16;c+=2)if(A(c)&A(c+1)&A(c+2))return A(c);return 0;}

Ambas devoluciones cuentan (una necesaria y otra necesaria para reemplazar con un espacio).

Los códigos de matriz para las ocho formas de ganar en tripletes a partir de posiciones iguales y tomados mod 16.

Bitwise y truco robado de Eric Pi .

Forma más legible:

#define A(x) a[b[x%16]] // Compact coding of the ways to win. // // Each possible was starts a position N*2 and runs through N*2+2 all // taken mod 16 int c,b[]={4,8,0,1,2,4,6,0,3,4,5,2,8,6,7,2}; int T(int*a){ // Loop over the ways to win for(c=0;c<16;c+=2) // Test for a win if(A(c)&A(c+1)&A(c+2))return A(c); return 0; }

Prueba de andamio:

#include <stdlib.h> #include <stdio.h> int T(int*); int main(int argc, char**argv){ int input[9]={0}; int i, j; for (i=1; i<argc; ++i){ input[i-1] = atoi(argv[i]); }; for (i=0;i<3;++i){ printf("%1i %1i %1i/n",input[3*i+0],input[3*i+1],input[3*i+2]); }; if (i = T(input)){ printf("%c wins!/n",(i==1)?''X'':''O''); } else { printf("No winner./n"); } return 0; }


C #, 180 caracteres:

var s=new[]{0,0,0,1,2,2,3,6}; var t=new[]{1,3,4,3,2,3,1,1}; return(s.Select((p,i)=>new[]{g[p],g[p+t[i]],g[p+2*t[i]]}).FirstOrDefault(l=>l.Distinct().Count()==1)??new[]{0}).First();

( g siendo la cuadrícula)

Probablemente podría mejorarse ... Todavía estoy trabajando en ello;)


Estoy seguro de que hay una forma más corta de hacer esto, pero ... Perl, 141 caracteres (134 dentro de la función)

sub t{$r=0;@b=@_;@w=map{[split//]}split/,/,"012,345,678,036,147,258,048,246";for(@w){@z=map{$b[$_]}@$_;$r=$z[0]if!grep{!$_||$_!=$z[0]}@z;}$r;}


No estoy contento con repetirme (horizontal / vertical y las diagonales), pero creo que es un buen comienzo.

C # w / LINQ:

public static int GetVictor(int[] b) { var r = Enumerable.Range(0, 3); return r.Select(i => r.Aggregate(3, (s, j) => s & b[i * 3 + j])).Concat( r.Select(i => r.Aggregate(3, (s, j) => s & b[j * 3 + i]))).Aggregate( r.Aggregate(3, (s, i) => s & b[i * 3 + i]) | r.Aggregate(3, (s, i) => s & b[i * 3 + (2 - i)]), (s, i) => s | i); }

Estrategia: A nivel de bit AND cada elemento de una fila / columna / diagonal con los otros elementos (con 3 como semilla) para obtener un vencedor para ese subconjunto, y OR todos juntos al final.


Octave / Matlab, 97 caracteres, incluyendo espacios y nuevas líneas. El resultado es 0 si no hay ganador, 1 si el jugador 1 ganó, 2 si el jugador 2 ganó y 2.0801 si ambos jugadores "ganaron":

function r=d(b) a=reshape(b,3,3) s=prod([diag(a) diag(fliplr(a)) a a'']) r=sum(s(s==1|s==8))^(1/3)

Si cambiamos la especificación y pasamos b como una matriz de 3x3 desde el principio, podemos eliminar la línea de remodelación, reduciéndola a 80 caracteres.


Probablemente podría mejorar, pero en este momento no me siento particularmente inteligente. Esto es solo para asegurarse de que Haskell se represente ...

Suponiendo que b ya existe, esto pondrá el resultado en w .

import List a l=2*minimum l-maximum l z=take 3$unfoldr(Just .splitAt 3)b w=maximum$0:map a(z++transpose z++[map(b!!)[0,4,8],map(b!!)[2,4,6]])

Asumiendo la entrada desde la entrada estándar y la salida a la salida estándar,

import List a l=2*minimum l-maximum l w b=maximum$0:map a(z++transpose z++[map(b!!)[0,4,8],map(b!!)[2,4,6]])where z=take 3$unfoldr(Just .splitAt 3)b main=interact$show.w.read


Solución C #.

Multiplica los valores en cada fila, col y diagonal. Si el resultado == 1, X gana. Si el resultado == 8, O gana.

int v(int[] b) { var i = new[] { new[]{0,1,2}, new[]{3,4,5}, new[]{6,7,8}, new[]{0,3,6}, new[]{1,4,7}, new[]{2,5,8}, new[]{0,4,8}, new[]{2,4,6} }; foreach(var a in i) { var n = b[a[0]] * b[a[1]] * b[a[2]]; if(n==1) return 1; if(n==8) return 2; } return 0; }


porque nadie gana en tictactoe cuando se juega correctamente, creo que este es el código más corto

echo 0;

7 caracteres

Actualización: Una mejor entrada para bash sería esta:

86 caracteres o 81 excluyendo la definición de la función (win ()).

win()for q in 1 28 55 3 12 21 4 20;{ [[ 3*w -eq B[f=q/8]+B[g=q%8]+B[g+g-f] ]]&&break;}

Pero, este es el código del programa tic-tac-toe en bash, por lo que no cumple con las especificaciones.

# player is passed in caller''s w variable. I use O=0 and X=2 and empty=8 or 9 # if a winner is found, last result is true (and loop halts) else false # since biggest test position is 7 I''ll use base 8. could use 9 as well but 10 adds 2 characters to code length # test cases are integers made from first 2 positions of each row # eg. first row (0 1 2) is 0*8+1 = 1 # eg. diagonal (2 4 6) is 2*8+4 = 20 # to convert test cases to board positions use X/8, X%8, and X%8+(X%8-X/8) # for each test case, test that sum of each tuplet is 3*player value


JavaScript - la función "w" a continuación tiene 114 caracteres

<html> <body> <script type="text/javascript"> var t = [0,0,2,0,2,0,2,0,0]; function w(b){ i = ''012345678036147258048642''; for (l=0;l<=21;l+=3){ v = b[i[l]]; if (v == b[i[l+1]]) if (v == b[i[l+2]]) return v; } } alert(w(t)); </script> </body> </html>


Python, 102 caracteres

Ya que realmente no especificó cómo obtener entrada y salida, esta es la versión "en bruto" que quizás tenga que ser envuelta en una función. b es la lista de entrada; r es la salida (0, 1 o 2).

r=0 for a,c in zip("03601202","11133342"):s=set(b[int(a):9:int(c)][:3]);q=s.pop();r=r if s or r else q


Solución de Python loco - 79 caracteres

max([b[x] for x in range(9) for y in range(x) for z in range(y) if x+y+z==12 and b[x]==b[y]==b[z]] + [0])

Sin embargo, esto supone un orden diferente para las posiciones de la junta en b:

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

Es decir, b[5] representa la esquina superior izquierda, y así sucesivamente.

Para minimizar lo anterior:

r=range max([b[x]for x in r(9)for y in r(x)for z in r(y)if x+y+z==12and b[x]==b[y]==b[z]]+[0])

93 caracteres y una nueva línea.

Actualización: hasta 79 caracteres y una nueva línea utilizando el truco AND a nivel de bits:

r=range max([b[x]&b[y]&b[z]for x in r(9)for y in r(x)for z in r(y)if x+y+z==12])


Una solución en C (162 caracteres):

Esto hace uso del hecho de que el valor un jugador (1) y el valor dos (2) del jugador tienen un conjunto de bits independientes. Por lo tanto, puede hacer bit y los valores de los tres cuadros de prueba juntos, si el valor es distinto de cero, entonces los tres valores deben ser idénticos. Además, el valor resultante == el jugador que ganó.

No es la solución más corta hasta ahora, pero lo mejor que pude hacer:

void fn(){ int L[]={1,0,1,3,1,6,3,0,3,1,3,2,4,0,2,2,0}; int s,t,p,j,i=0; while (s=L[i++]){ p=L[i++],t=3; for(j=0;j<3;p+=s,j++)t&=b[p]; if(t)putc(t+''0'',stdout);} }

Una versión más legible:

void fn2(void) { // Lines[] defines the 8 lines that must be tested // The first value is the "Skip Count" for forming the line // The second value is the starting position for the line int Lines[] = { 1,0, 1,3, 1,6, 3,0, 3,1, 3,2, 4,0, 2,2, 0 }; int Skip, Test, Pos, j, i = 0; while (Skip = Lines[i++]) { Pos = Lines[i++]; // get starting position Test = 3; // pre-set to 0x03 (player 1 & 2 values bitwise OR''d together) // search each of the three boxes in this line for (j = 0; j < 3; Pos+= Skip, j++) { // Bitwise AND the square with the previous value // We make use of the fact that player 1 is 0x01 and 2 is 0x02 // Therefore, if any bits are set in the result, it must be all 1''s or all 2''s Test &= b[Pos]; } // All three squares same (and non-zero)? if (Test) putc(Test+''0'',stdout); } }


Visual Basic 275 254 (con escritura suelta) caracteres

Function W(ByVal b()) Dim r For p = 1 To 2 If b(0) = b(1) = b(2) = p Then r = p If b(3) = b(4) = b(5) = p Then r = p If b(6) = b(7) = b(8) = p Then r = p If b(0) = b(3) = b(6) = p Then r = p If b(1) = b(4) = b(7) = p Then r = p If b(2) = b(5) = b(8) = p Then r = p If b(0) = b(4) = b(8) = p Then r = p If b(6) = b(4) = b(2) = p Then r = p Next Return r End Function