language-agnostic code-golf rosetta-stone

language agnostic - Código Golf: Jugar Tetris



language-agnostic code-golf (14)

C, 727 [...] 596 581 556 517 496 471 461 457 caracteres

Este es mi primer código de golf, creo que el recuento de personajes puede ser mucho menor, sería bueno si los golfistas experimentados pueden darme algunas pistas.

La versión actual también puede manejar campos de juego con diferentes dimensiones. La entrada puede tener saltos de línea en formato DOS / Windows y Unix.

El código era bastante directo antes de la optimización, los tetrominós se almacenan en 4 enteros que se interpretan como una matriz (7 * 3) x4 bits, el campo de juego se almacena tal como está, se eliminan los mosaicos y las líneas completas se eliminan al inicio y después de cada caída de azulejo.

No estaba seguro de cómo contar los caracteres, así que utilicé el tamaño del código con todos los saltos de línea innecesarios.

EDIT 596 => 581: Gracias a KitsuneYMG, todo excepto la sugerencia %ls funcionó perfectamente, adicionalmente, noté que se podía usar putch lugar de putchar ( getch alguna manera no funciona) y quitaba todos los paréntesis en #define G

EDITAR 581 => 556: No estaba satisfecho con lo que quedaba for y con los bucles F anidados, por lo que hubo cierta fusión, cambio y eliminación de bucles, bastante confuso pero definitivamente valió la pena.

EDITAR 556 => 517: Finalmente encontré una forma de hacer a matriz int. Algunos N; se fusionó con c , ya no hay break .

EDITAR 496 => 471: ancho y altura del campo de juego fijos ahora.

EDIT 471 => 461: modificaciones menores, putchar usado de nuevo ya que putch no es una función estándar.

EDIT: Bugfix, las líneas completas fueron eliminadas antes de la colocación del azulejo en lugar de después , por lo que las líneas completas podrían dejarse al final. La reparación no cambia el recuento de caracteres.

#define N (c=getchar()) #define G T[j%4]&1<<t*3+j/4 #define X j%4*w+x+j/4 #define F(x,m) for(x=0;x<m;x++) #define W while T[]={916561,992849,217,1},C[99],c,i,j,s,t,x,A,a[99],w=13; main(){F(j,7)C["IJLSTZO"[j]]=j; F(j,91)a[j]=N; W(N>w){t=C[c];x=N-86; W(c){F(j,12)if(G&&X>1?a[X]-32:0)c=0; F(j,12)if(G&&X>w&&!c)a[X-w]=35;x+=w;}N; F(i,6){A=0;t=i*w;F(x,w)A|=(a[t+x]==32); if(!A){s++;F(j,t)a[t+w-j]=a[t-j]; x=1;W(a[x]-93)a[x++]=32;}}} F(i,91)putchar(a[i]);printf("%i0",s);}

Los basicos:

Considere los siguientes tetrominós y el campo de juego vacío:

0123456789 I O Z T L S J [ ] [ ] # ## ## ### # ## # [ ] # ## ## # # ## # [ ] # ## ## [ ] # [ ] [==========]

Las dimensiones del campo de juego son fijas. Los números en la parte superior están aquí para indicar el número de columna (también ver entrada).

Entrada:

1 . Se le otorga un campo de juego específico (basado en lo anterior) que ya puede rellenarse parcialmente con tetrominoes (esto puede estar en un archivo separado o proporcionado a través de stdin).

Muestra de entrada:

[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========]

2 . Se le da una cadena que describe (separados por espacios) qué tetromino insertar (y desplegar) en qué columna. Tetrominoes no necesitan ser rotados. La entrada se puede leer desde stdin.

Muestra de entrada:

T2 Z6 I0 T7

Puede suponer que la entrada está ''bien formada'' (o producir un comportamiento indefinido cuando no lo está).

Salida

Renderice el campo resultante (las líneas "completas" deben desaparecer) e imprima el recuento de puntajes (cada línea eliminada representa 10 puntos).

Muestra de salida basada en la entrada de muestra anterior:

[ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10

Ganador:

Solución más corta (por número de caracteres de código). Los ejemplos de uso son agradables. ¡Diviértete jugando golf!

Editar : se ha añadido una recompensa de más de +500 reputación para llamar más la atención sobre los buenos esfuerzos que ya hicieron los que respondieron (y posiblemente algunas nuevas soluciones a esta pregunta) ...


Golfscript 260 caracteres

Estoy seguro de que esto podría mejorarse, soy nuevo en Golfscript.

[39 26.2/0:$14{.(}:?~1?15?1?14 2??27?13.!14?2?27?14 1]4/:t;n/)/n*:|;'' ''/-1%.,:c;~{)18+:&;''XIOZTLSJX''/%~;,1-t/={{.&+.90>{;.}*|/=32=!{&13-:&;}*}%}6*{&+}/|{/.@<''#''+/)|>+}4*{''[''/10*'']''++}: ;n/0/~n+:|;0/{.''#'' ={;)}{n+|+:|;}if/.}do;'' '' n+/.@*|+/$+:$;.,1-<:|;}c*|n?$*

El final de las líneas es relevante (no debe haber una al final). De todos modos, aquí están algunos de los casos de prueba que utilicé:

> cat init.txt [ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7> cat init.txt | ruby golfscript.rb tetris.gsc [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10 > cat init.txt [ ] [ ] [ ] [ ] [ # # #] [ ## ##### ] [==========] I0 O7 Z1 S4> cat init.txt | ruby golfscript.rb tetris.gsc [ ] [ ] [ ] [# ] [### #### ] [### ##### ] [==========] 10 > cat init.txt [ ] [ ] [ ] [ ## ### ] [ # # ] [ ## ######] [==========] T7 I0 I3> cat init.txt | ruby golfscript.rb tetris.gsc [ ] [ ] [ ] [ ] [# # ] [## # # # ] [==========] 20

Note that there is no end of line in the input file, an end of line would break the script as is.


Perl, 586 523 483 472 427 407 404 386 387 356 353 caracteres

(Necesita Perl 5.10 para el operador definido o // ).

Toma todas las entradas desde stdin. Todavía necesita un poco de golf serio.
Tenga en cuenta que ^ Q representa ASCII 17 (DC1 / XON), ^ C representa ASCII 3 y ^ @ representa ASCII 0 (NUL).

while(<>){push@A,[split//]if/]/;while(//w/g){for$i(0..6){for($f=0,$j=4;$j--;){$c=0;map{if($_){$i--,$f=$j=3,redo if$A[$k=$i+$j][$C=$c+$''+1]ne$";$A[$k][$C]="#"if$f}$c++}split//,unpack"b*",chr vec"3^@''^@c^@^Q^C6^@/"^C^Q^Q",index(OTZLSJI,$&)*4+$j,4;$s+=10,@A[0..$k]=@A[$k,0..$k-1],map{s/#/ /}@{$A[0]},$i++if 9<grep/#/,@{$A[$k]}}last if$f}}}print+(map@$_,@A),$s//0,$/

Versión comentada:

while(<>){ # store the playfield as an AoA of chars push@A,[split//]if/]/; # while we''re getting pieces while(//w/g){ # for each line of playfield for$i(0..6){ # for each line of current piece for($f=0,$j=4;$j--;){ # for each column of current piece $c=0; map{ if($_){ # if there''s a collision, restart loop over piece lines # with a mark set and playfield line decremented $i--,$f=$j=3,redo if$A[$k=$i+$j][$C=$c+$''+1]ne$"; # if we already found a collision, draw piece $A[$k][$C]="#"if$f } $c++ # pieces are stored as a bit vector, 16 bits (4x4) per piece, # expand into array of 1''s and 0''s }split//,unpack"b*",chr vec"3^@''^@c^@^Q^C6^@/"^C^Q^Q",index(OTZLSJI,$&)*4+$j,4; # if this playfield line is full, remove it. Done by array slicing # and substituting all "#"''s in line 0 with " "''s $s+=10,@A[0..$k]=@A[$k,0..$k-1],map{s/#/ /}@{$A[0]},$i++if 9<grep/#/,@{$A[$k]} } # if we found a collision, stop iterating over the playfield and get next piece from input last if$f } } } # print everything print+(map@$_,@A),$s//0,$/

Edición 1: algunos errores graves de golf, solución de salida.
Edición 2: algunos en línea, fusionaron dos bucles en uno para un ahorro neto de (tambor de tambor ...) 3 caracteres, misc golfing.
Edición 3: alguna eliminación común de subexpresiones, un poco de fusión constante y ajustado una expresión regular.
Edición 4: modificación de la representación de tetrominoes en un vector de bits empaquetados, misc golfing.
Edición 5: traducción más directa de la letra tetromino al índice de matriz, uso de caracteres no imprimibles, misc golfing.
Editar 6: solucionó la línea superior de limpieza de errores, introducida en r3 (edición 2), detectada por Nakilon. Use más caracteres no imprimibles.
Edición 7: use vec para obtener datos tetrominos. Aproveche el hecho de que el campo de juego tiene dimensiones fijas. if statement => if modifier, la fusión de los bucles de edición 2 comienza a dar sus frutos. Use // para el caso 0-score.
Editar 8: corrigió otro error, introducido en r6 (edición 5), detectado por Nakilon.
Edición 9: no cree nuevas referencias al borrar líneas, simplemente mueva las referencias a través de la división en matriz. Fusiona dos map en uno. Regex más inteligente. "Más inteligente" for . Varios campos de golf.
Edición 10: matriz tetromino en línea, versión comentada añadida.


Python, 298 caracteres

Toca todas las soluciones de lenguaje no esotéricas hasta el momento (Perl, Ruby, C, bash ...)

... y ni siquiera usa trampas de código cerrado.

import os r=os.read b=''[%11c/n''%'']''*99+r(0,91) for k,v in r(0,99).split(): t=map(ord,'' -:G!.:; -:; !-.!"-. !". !./'')[''IJLOSTZ''.find(k)*4:][:4];v=int(v)-31 while''!''>max(b[v+j+13]for j in t):v+=13 for j in t:b=b[:v+j]+''#''+b[v+j+1:] b=b.replace(''[##########]/n'','''') print b[-91:],1060-10*len(b)/13

En el ejemplo de prueba

[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7

produce

[ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10

PD. corrigió un error señalado por Nakilon a un costo de +5


Python: 504 519 caracteres

(Solución Python 3) Actualmente se requiere configurar la entrada en el formato que se muestra en la parte superior (el código de entrada no se cuenta). Expandiré para leer de un archivo o stdin después. Ahora funciona con un aviso, solo pega la entrada en (8 líneas en total).

R=range f,p=[input()[1:11]for i in R(7)],p for(a,b)in input().split(): t=['' ''*int(b)+r+'' ''*9for r in{''I'':''#,#,#,#'',''O'':''##,##'',''Z'':''##, ##'',''T'':''###, # '',''L'':''#,#,##'',''S'':'' ##,##'',''J'':'' #, #,##''}[a].split('','')] for r in R(6-len(t),0,-1): for i in R(len(t)): if any(a==b==''#''for(a,b)in zip(t[i],f[r+i])):break else: for i in R(0,len(t)): f[r+i]=''''.join(a if b!=''#''else b for(a,b)in zip(t[i],f[r+i])) if f[r+i]==''#''*10:del f[r+i];f[0:0]=['' ''*10];p+=10 break print(''/n''.join(''[''+r+'']''for r in f[:7]),p,sep=''/n'')

No estoy seguro de si puedo ahorrar mucho más allí. Se pierden muchos personajes de la transformación a campos de bits, pero eso ahorra muchos más caracteres que trabajar con las cuerdas. Además, no estoy seguro si puedo eliminar más espacios en blanco allí, pero lo intentaré más adelante.
No podrá reducirlo mucho más; Después de tener la solución basada en el campo de bits, volví a las cadenas, ya que encontré una manera de comprimirla más (¡guardé 8 caracteres en el campo de bits!). Pero dado que olvidé incluir la L y tuve un error con los puntos internos, el recuento de mi personaje solo se dispara ... Tal vez encuentre algo más tarde para comprimirlo un poco más, pero creo que estoy cerca del final. Para el código original y comentado, ver a continuación:

Versión original:

field = [ input()[1:11] for i in range(7) ] + [ 0, input() ] # harcoded tetrominoes tetrominoes = {''I'':(''#'',''#'',''#'',''#''),''O'':(''##'',''##''),''Z'':(''##'','' ##''),''T'':(''###'','' # ''),''L'':(''#'',''#'',''##''),''S'':('' ##'',''##''),''J'':('' #'','' #'',''##'')} for ( f, c ) in field[8].split(): # shift tetromino to the correct column tetromino = [ '' '' * int(c) + r + '' '' * 9 for r in tetrominoes[f] ] # find the correct row to insert for r in range( 6 - len( tetromino ), 0, -1 ): for i in range( len( tetromino ) ): if any( a == b == ''#'' for (a,b) in zip( tetromino[i], field[r+i] ) ): # skip the row if some pieces overlap break else: # didn''t break, insert the tetromino for i in range( 0, len( tetromino ) ): # merge the tetromino with the field field[r+i] = ''''.join( a if b != ''#'' else b for (a,b) in zip( tetromino[i], field[r+i] ) ) # check for completely filled rows if field[r+i] == ''#'' * 10: # remove current row del field[r+i] # add new row field[0:0] = ['' ''*10] field[7] += 10 # we found the row, so abort here break # print it in the requested format print( ''/n''.join( ''['' + r + '']'' for r in field[:7] ) ) # and add the points = 10 * the number of redundant lines at the end print( str( field[7] ) )


Ruby - 427 408 398 369 359

t=[*$<] o=0 u=->f{f.transpose} a=u[t.reverse.join.scan /#{''( |#)''*10}/] t.pop.split.map{|w|m=(g=''I4O22Z0121T01201L31S1201J13''[/#{w[0]}/d+/].scan(/0?/d/).zip a.drop w[1].to_i).map{|r,b|(b.rindex ?#or-1)-r.size+1}.max g.map{|r,b|b.fill ?#,m+r.size,r.to_i} v=u[a] v.reject!{|i|i-[?#]==[]&&(o+=10;v)<<['' '']*10} a=u[v]} puts u[a].reverse.map{|i|?[+i*''''+?]},t[-1],o


GolfScript - 181 personajes

Las nuevas líneas no son necesarias. La salida está en salida estándar, aunque algunos errores están presentes en stderr.
/10 debe reemplazarse por el carácter ASCII correspondiente para que el programa tenga 181 caracteres.

{):X!-{2B{" #"=}%X" ":f*+-1%}%:P;:>.{/!:F;>P{/(@{3&/(@.2$&F|:F;|}%/+}%/+F![f]P+:P ;}do;{"= "&},.,7^.R+:R;[>0="#"/f*]*/+}0"R@1(XBc_""~/10"{base}:B/3/~4*"nIOZTLSJR " ";:"*~;n%)n*~ 10R*+n*

E / S de muestra:

$ cat inp [ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7 $ cat inp|golfscript tetris.gs 2>/dev/null [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10

Compresión de Tetromino:
Las piezas se almacenan en tres bases de 8 dígitos. Esta es una representación binaria simple, por ejemplo, T=[7,2,0], S=[6,3,0], J=[2,2,3] . [1] se usa para la pieza I en compresión, pero esto se establece explícitamente en [1,1,1,1] más tarde (es decir, el 4* en el código). Todas estas matrices se concatenan en una única matriz, que se convierte en un número entero, y luego en una cadena (base 126 para minimizar los caracteres no imprimibles, la longitud y no encontrar utf8). Esta cadena es muy corta: "R@1(XBc_" .

La descompresión es entonces directa. Primero hacemos una conversión base 126 seguida de una conversión base 8 ( "~/10"{base}/ , es decir, iteramos a través de "~/10" y hacemos una conversión base para cada elemento). La matriz resultante se divide en grupos de 3, la matriz para I es fija ( 3/~4* ). Luego convertimos cada elemento a la base 2 y (después de eliminar los ceros) reemplazamos cada dígito binario con el carácter de ese índice en la cadena " #" ( 2base{" #"=}%...-1% - tenga en cuenta que necesitamos para invertir la matriz, de lo contrario 2 se convertiría en "# " lugar de " #" ).

Formato de tablero / pieza, cayendo piezas
La placa es simplemente una matriz de cadenas, una para cada línea. Al principio no se realiza ningún trabajo, por lo que podemos generarlo con n/( en la entrada. Las piezas también son matrices de cadenas, rellenas con espacios a la izquierda para su posición X, pero sin espacios finales. Las piezas se quitan antes de la matriz, y continuamente probando si hay una colisión.

La prueba de colisión se realiza al iterar a través de todos los personajes de la pieza y al compararla con el personaje de la misma posición en la pizarra. Queremos considerar # + = y # + # como colisiones, así que probamos si ((piecechar & 3) & boardchar) es distinto de cero. Al hacer esta iteración, también actualizamos (una copia de) la placa con ((piecechar & 3) | boardchar), que establece correctamente el valor para los pares # + , + # , + [ . Usamos este tablero actualizado si hay una colisión después de mover la pieza hacia abajo en otra fila.

Eliminar filas rellenas es bastante simple. Eliminamos todas las filas para las cuales "= "& devolvemos falso. Una fila llena no tendrá = o , entonces la conjunción será una cadena en blanco, lo que equivale a falso. Luego contamos el número de filas que se han eliminado, agregamos el conteo al puntaje y anteponemos muchos "[ ... ]" . Generamos esto de forma compacta tomando la primera fila de la grilla y reemplazando # con .

Prima
Ya que calculamos cómo se vería el tablero en cada posición de la pieza a medida que cae, ¡podemos mantener estos en la pila en lugar de eliminarlos! Para un total de tres caracteres más, podemos generar todas estas posiciones (o dos caracteres si tenemos los estados de la tabla a un solo espacio).

{):X!-{2B{" #"=}%X" ":f*+-1%}%:P;:>.{>[f]P+:P(!:F;{/(@{3&/(@.2$&F|:F;|}%/+}%/+F!} do;{"= "&},.,7^.R+:R;[>0="#"/f*]*/+}0"R@1(XBc_""~/10"{base}:B/3/~4*"nIOZTLSJR " ";:"*~;n%)n*~ ]{n*n.}/10R*


Python 2.6+ - 334 322 316 caracteres

397 368 366 caracteres sin comprimir

#coding:l1 exec''xÚEPMO!½ï¯ i,P*Ýlš%ì­‰=‰Ö–*†­þz©‰:‡—Lò¾fÜ”bžAù,MVi™.ÐlǃwÁ„eQL&•uÏÔ‹¿1O6ǘ.€LSLÓ’¼›î”3òšL¸tŠv[ѵl»h;ÁºŽñÝ0Àë»Ç‡ÛûH.ª€¼âBNjr}¹„V5¾3Dë@¼¡•gO. ¾ô6 çÊsÃЮürÃ1&›ßVˆ­ùZ`Ü€ÿžcx±ˆ‹sCàŽ êüRô{U¯ZÕDüE+³ŽFA÷{CjùYö„÷¦¯Î[0þøõ…(Îd®_›â»E#–Y%’›”ëýÒ·X‹d¼.ß9‡kD''.decode(''zip'')

Se necesita una sola nueva línea, y la he contado como un personaje.

El código malicioso de la página de códigos del navegador podría evitar una copia y pegado exitosos de este código, por lo que puede generar el archivo de forma opcional desde este código:

s = """ 23 63 6F 64 69 6E 67 3A 6C 31 0A 65 78 65 63 27 78 DA 45 50 4D 4F 03 21 10 BD EF AF 20 69 2C 50 2A 02 DD 6C 9A 25 EC AD 07 8D 89 07 3D 89 1C D6 96 2A 86 05 02 1B AD FE 7A A9 89 3A 87 97 4C F2 BE 66 DC 94 62 9E 41 F9 2C 4D 56 15 69 99 0F 2E D0 6C C7 83 77 C1 16 84 65 51 4C 26 95 75 CF 8D 1C 15 D4 8B BF 31 4F 01 36 C7 98 81 07 2E 80 4C 53 4C 08 D3 92 BC 9B 11 EE 1B 10 94 0B 33 F2 9A 1B 4C B8 74 8A 9D 76 5B D1 B5 6C BB 13 9D 68 3B C1 BA 8E F1 DD 30 C0 EB BB C7 87 DB FB 1B 48 8F 2E 1C AA 80 19 BC E2 42 4E 6A 72 01 7D B9 84 56 35 BE 33 44 8F 06 EB 40 BC A1 95 67 4F 08 2E 20 BE F4 36 A0 E7 CA 73 C3 D0 AE FC 72 C3 31 26 9B DF 56 88 AD F9 5A 60 DC 80 FF 9E 63 78 B1 88 8B 73 43 E0 8E A0 EA FC 52 F4 7B 55 8D AF 5A 19 D5 44 FC 45 2B B3 8E 46 9D 41 F7 7B 43 6A 12 F9 59 F6 84 F7 A6 01 1F AF CE 5B 30 FE F8 F5 85 28 CE 64 AE 5F 9B E2 BB 45 23 96 59 25 92 9B 94 EB FD 10 D2 B7 58 8B 64 BC 2E DF 39 87 6B 44 27 2E 64 65 63 6F 64 65 28 27 7A 69 70 27 29 """ with open(''golftris.py'', ''wb'') as f: f.write(''''.join(chr(int(i, 16)) for i in s.split()))

Pruebas

intetris

[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7

Las líneas nuevas deben ser de estilo Unix (solo avance de línea). Una nueva línea final en la última línea es opcional.

Probar:

> python golftris.py < intetris [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10

Este código descomprime el código original y lo ejecuta con exec . Este código descomprimido pesa 366 caracteres y se ve así:

import sys r=sys.stdin.readlines();s=0;p=r[:1];a=''[##########]/n'' for l in r.pop().split(): n=int(l[1])+1;i=0xE826408E26246206601E>>''IOZTLSJ''.find(l[0])*12;m=min(zip(*r[:6]+[a])[n+l].index(''#'')-len(bin(i>>4*l&31))+3for l in(0,1,2)) for l in range(12): if i>>l&2:c=n+l/4;o=m+l%4;r[o]=r[o][:c]+''#''+r[o][c+1:] while a in r:s+=10;r.remove(a);r=p+r print''''.join(r),s

Se requieren nuevas líneas, y son un personaje cada una.

No trates de leer este código. Los nombres de las variables se eligen literalmente al azar en busca de la compresión más alta (con diferentes nombres de variable, vi hasta 342 caracteres después de la compresión). Una versión más comprensible sigue:

import sys board = sys.stdin.readlines() score = 0 blank = board[:1] # notice that I rely on the first line being blank full = ''[##########]/n'' for piece in board.pop().split(): column = int(piece[1]) + 1 # "+ 1" to skip the ''['' at the start of the line # explanation of these three lines after the code bits = 0xE826408E26246206601E >> ''IOZTLSJ''.find(piece[0]) * 12 drop = min(zip(*board[:6]+[full])[column + x].index(''#'') - len(bin(bits >> 4 * x & 31)) + 3 for x in (0, 1, 2)) for i in range(12): if bits >> i & 2: # if the current cell should be a ''#'' x = column + i / 4 y = drop + i % 4 board[y] = board[y][:x] + ''#'' + board[y][x + 1:] while full in board: # if there is a full line, score += 10 # score it, board.remove(full) # remove it, board = blank + board # and replace it with a blank line at top print ''''.join(board), score

El quid de la cuestión está en las tres líneas crípticas que dije que explicaría.

La forma de los tetrominós está codificada en el número hexadecimal allí. Se considera que cada tetrónomo ocupa una cuadrícula de celdas de 3x4, donde cada celda está en blanco (un espacio) o llena (un signo numérico). Cada pieza se codifica con 3 dígitos hexadecimales, cada dígito describe una columna de 4 celdas. Los dígitos menos significativos describen las columnas más a la izquierda, y el bit menos significativo en cada dígito describe la celda más alta en cada columna. Si un bit es 0, entonces esa celda está en blanco, de lo contrario es un ''#''. Por ejemplo, el I tetronimo está codificado como 00F , con los cuatro bits del dígito menos significativo activado para codificar los cuatro signos numéricos en la columna de la izquierda, y el T es 131 , con el bit superior a la izquierda y el derecho, y los dos primeros bits en el medio.

El número hexadecimal completo se desplaza un bit hacia la izquierda (multiplicado por dos). Esto nos permitirá ignorar el bit más inferior. Explicaré por qué en un minuto.

Así que dada la pieza actual de la entrada, encontramos el índice en este número hexadecimal donde comienzan los 12 bits que describen su forma, luego lo bajan para que los bits 1 a 12 (omitiendo el bit 0) de la variable de bits describan la pieza actual.

La asignación para drop determina cuántas filas desde la parte superior de la cuadrícula la pieza caerá antes de aterrizar en otros fragmentos de piezas. La primera línea encuentra cuántas celdas vacías hay en la parte superior de cada columna del campo de juego, mientras que la segunda encuentra la celda ocupada más baja en cada columna de la pieza. La función zip devuelve una lista de tuplas, donde cada tupla consiste en la n- ésima celda de cada elemento en la lista de entrada. Entonces, usando el tablero de entrada de muestra, volverá a aparecer el zip(board[:6] + [full]) :

[ (''['', ''['', ''['', ''['', ''['', ''['', ''[''), ('' '', '' '', '' '', '' '', '' '', '' '', ''#''), ('' '', '' '', '' '', '' '', ''#'', ''#'', ''#''), ('' '', '' '', '' '', '' '', '' '', ''#'', ''#''), ('' '', '' '', '' '', '' '', '' '', '' '', ''#''), ('' '', '' '', '' '', '' '', '' '', ''#'', ''#''), ('' '', '' '', '' '', '' '', '' '', ''#'', ''#''), ('' '', '' '', '' '', '' '', ''#'', ''#'', ''#''), ('' '', '' '', '' '', '' '', '' '', ''#'', ''#''), ('' '', '' '', '' '', '' '', '' '', ''#'', ''#''), ('' '', '' '', '' '', '' '', ''#'', ''#'', ''#''), ('']'', '']'', '']'', '']'', '']'', '']'', '']'') ]

Seleccionamos la tupla de esta lista correspondiente a la columna apropiada, y buscamos el índice del primer ''#'' en la columna. Esta es la razón por la que agregamos una fila "completa" antes de llamar a zip , por lo que el index tendrá un retorno razonable (en lugar de arrojar una excepción) cuando la columna esté en blanco.

Luego, para encontrar el ''#'' más bajo en cada columna de la pieza, cambiamos y enmascaramos los cuatro bits que describen esa columna, luego usamos la función bin para convertirla en una cadena de unos y ceros. La función bin solo devuelve bits significativos, por lo que solo necesitamos calcular la longitud de esta cadena para encontrar la celda ocupada más baja (bit más significativo). La función bin también precede ''0b'' , por lo que debemos restarla. También ignoramos el bit menos significativo. Esta es la razón por la cual el número hexadecimal se desplaza un bit hacia la izquierda. Esto es para dar cuenta de columnas vacías, cuyas representaciones de cadena tendrían la misma longitud que una columna con solo la celda superior llena (como la pieza T ).

Por ejemplo, las columnas del I tetromino, como se mencionó anteriormente, son F , 0 y 0 . bin(0xF) es ''0b1111'' . Después de ignorar el ''0b'' , tenemos una longitud de 4, que es correcta. Pero bin(0x0) es 0b0 . Después de ignorar el ''0b'' , todavía tenemos una longitud de ''1, que es incorrecta. Para dar cuenta de esto, hemos agregado un bit adicional al final, para que podamos ignorar este bit insignificante. Por lo tanto, el +3 en el código está ahí para dar cuenta de la longitud adicional tomada por el ''0b'' al comienzo, y el bit insignificante al final.

Todo esto ocurre dentro de una expresión de generador para tres columnas ( (0,1,2) ), y tomamos el resultado min para encontrar el número máximo de filas que la pieza puede caer antes de que toque en cualquiera de las tres columnas.

El resto debe ser bastante fácil de entender leyendo el código, pero el bucle for sigue a estas asignaciones agrega la pieza al tablero. Después de esto, el ciclo while elimina las filas completas, reemplazándolas con filas en blanco en la parte superior y suma el puntaje. Al final, el tablero y la puntuación se imprimen en la salida.


Ruby 1.9, 357 355 353 339 330 310 309 caracteres

d=0 e=[*$<] e.pop.split.map{|f|f="L/003/003/007J/005/005/007O/007/007Z/007/013S/013/007I/003/003/003/003T/017/005"[/#{f[j=0]}(/W*)/,1].bytes.map{|z|?/0+?/0*f[1].hex+z.to_s(2).tr("01"," #")[1,9]} k,f,i=i,[p]+f,e.zip(f).map{|l,m|l.bytes.zip(m.to_s.bytes).map{|n,o|j|=n&3&q=o||0;(n|q).chr}*""}until j>0 e=[] e+=k.reject{|r|r.sum==544&&e<<r.tr(?#,?/s)&&d+=10}} puts e,d

Tenga en cuenta que los /000 escapes (incluidos los bytes nulos en la tercera línea) deberían reemplazarse por su equivalente real no imprimible.

Muestra de entrada:

[ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] T2 Z6 I0 T7

Uso:

ruby1.9 tetris.rb < input

o

ruby1.9 tetris.rb input


Script de shell Bash ( 301 304 caracteres)


ACTUALIZACIÓN: se corrigió un error que involucraba piezas que se extendían hasta la fila superior. Además, la salida ahora se envía a la salida estándar, y como beneficio adicional, es posible ejecutar el script de nuevo para continuar jugando un juego (en cuyo caso debe sumar el puntaje total).

Esto incluye caracteres no imprimibles, por lo que he proporcionado un volcado hexadecimal. tetris.txt como tetris.txt :

0000000: 7461 696c 202d 3120 245f 7c7a 6361 743e tail -1 $_|zcat> 0000010: 753b 2e20 750a 1f8b 0800 35b0 b34c 0203 u;. u.....5..L.. 0000020: 5590 516b 8330 10c7 dff3 296e 4c88 ae64 U.Qk.0....)nL..d 0000030: a863 0c4a f57d 63b0 07f7 b452 88d1 b4da .c.J.}c....R.... 0000040: 1a5d 5369 91a6 df7d 899a d05d 5e72 bfbb .]Si...}...]^r.. 0000050: fbff 2fe1 45d5 0196 7cff 6cce f272 7c10 ../.E...|.l..r|. 0000060: 387d 477c c4b1 e695 855f 77d0 b29f 99bd 8}G|....._w..... 0000070: 98c6 c8d2 ef99 8eaa b1a5 9f33 6d8c 40ec ...........3m.@. 0000080: 6433 8bc7 eeca b57f a06d 27a1 4765 07e6 d3.......m''.Ge.. 0000090: 3240 dd02 3df1 2344 f04a 0d1d c748 0bde 2@..=.#D.J...H.. 00000a0: 75b8 ed0f 9eef 7bd7 7e19 dd16 5110 34aa u.....{.~...Q.4. 00000b0: c87b 2060 48a8 993a d7c0 d210 ed24 ff85 .{ `H..:.....$.. 00000c0: c405 8834 548a 499e 1fd0 1a68 2f81 1425 ...4T.I....h/..% 00000d0: e047 bc62 ea52 e884 42f2 0f0b 8b37 764c .G.b.R..B....7vL 00000e0: 17f9 544a 5bbd 54cb 9171 6e53 3679 91b3 ..TJ[.T..qnS6y.. 00000f0: 2eba c07a 0981 f4a6 d922 89c2 279f 1ab5 ...z....."..''... 0000100: 0656 c028 7177 4183 2040 033f 015e 838b .V.(qwA. @.?.^.. 0000110: 0d56 15cf 4b20 6ff3 d384 eaf3 bad1 b9b6 .V..K o......... 0000120: 72be 6cfa 4b2f fb03 45fc cd51 d601 0000 r.l.K/..E..Q....

Luego, en el prompt del comando bash, preferiblemente con elvis lugar de vim instalado como vi :

$ xxd -r tetris.txt tetris.sh $ chmod +x tetris.sh $ cat << EOF > b > [ ] > [ ] > [ ] > [ ] > [ # # #] > [ ## ######] > [==========] > EOF $ ./tetris.sh T2 Z6 I0 T7 2>/dev/null -- removed stuff that is not in standard out -- [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10

Cómo funciona

El código se gzexe manera similar a la forma en que se gzexe los programas ejecutables mediante el script gzexe . Las piezas de Tetromino se representan como secuencias de comandos del editor vi. El recuento de caracteres se usa para detectar colisiones y el conteo de líneas se usa para calcular el puntaje.

El código descomprimido:

echo ''rej.j.j.:wq!m''>I echo ''2rejh.:wq!m''>O echo ''2rej.:wq!m''>Z echo ''3rejh1.:wq!m''>T echo ''rej.j2.:wq!m''>L echo ''l2rej2h.:wq!m''>S echo ''lrej.jh2.:wq!m''>J for t do for y in `seq 1 5` do echo -n ${y}jk$((${t:1}+1))l|cat - ${t:0:1}|vi b>0 grep ========== m>0||break [ `tr -cd ''#''<b|wc -c` = `tr -cd ''#''<m|wc -c` ]||break tr e ''#''<m>n done cat n>b grep -v ''##########'' b>m $((S+=10*(`wc -l < b`-`wc -l < m`))) yes ''[ ]''|head -7|cat - m|tail -7>b done cat b echo $S

El código original antes de jugar al golf:

#!/bin/bash mkpieces() { pieces=(''[email protected].'' ''2r@jh.'' ''2r@j.'' ''3r@jh1.'' ''[email protected].'' ''l2r@j2h.'' ''[email protected].'') letters=(I O Z T L S J) for j in `seq 0 9`; do for i in `seq 0 6`; do echo "jk$(($j+1))l${pieces[$i]}:wq! temp" > ${letters[$i]}$j done done } counthashes() { tr -cd ''#'' < $1 | wc -c } droppiece() { for y in `seq 1 5`; do echo -n $y | cat - $1 | vi board > /dev/null egrep ''={10}'' temp > /dev/null || break [ `counthashes board` -eq `counthashes temp` ] || break tr @ "#" < temp > newboard done cp newboard board } removelines() { egrep -v ''#{10}'' board > temp SCORE=$(($SCORE + 10 * (`wc -l < board` - `wc -l < temp`))) yes ''[ ]'' | head -7 | cat - temp | tail -7 > board } SCORE=0 mkpieces for piece; do droppiece $piece removelines done cat board echo $SCORE


Common Lisp 667 657 645 Chars

My first attempt at code golf, so there are probably many tricks that I don''t know yet. I left some newlines there to keep some residual "readability" (I counted newlines as 2 bytes, so removing 6 unnecessary newlines gains 12 more characters).

In input, first put the shapes then the field.

(let(b(s 0)m(e''(0 1 2 3 4 5 6 7 8 9))) (labels((o(p i)(mapcar(lambda(j)(+ i j))p))(w(p r)(o p(* 13 r)))(f(i)(find i b)) (a(&aux(i(position(read-char)"IOZTLSJ")))(when i(push(o(nth i''((0 13 26 39)(0 1 13 14)(0 1 14 15)(0 1 2 14)(0 13 26 27)(1 2 13 14)(1 14 26 27)))(read))m)(a)))) (a)(dotimes(i 90)(if(find(read-char)"#=")(push i b)))(dolist(p(reverse m)) (setf b`(,@b,@(w p(1-(position-if(lambda(i)(some #''f(w p i)))e))))) (dotimes(i 6)(when(every #''f(w e i))(setf s(1+ s)b(mapcar(lambda(k)(+(if(>(* 13 i)k)13(if(<=(* 13(1+ i))k)0 78))k))b))))) (dotimes(i 6)(format t"[~{~:[ ~;#~]~}] "(mapcar #''f(w e i))))(format t"[==========] ~a0"s)))

Pruebas

T2 Z6 I0 T7 [ ] [ ] [ ] [ ] [ # # #] [ ## ######] [==========] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10 NIL


O''Caml 809 782 Chars

open String let w=length let c s=let x=ref 0in iter(fun k->if k=''#''then incr x)s;!x open List let(@),g,s,p,q=nth,ref[],ref 0,(0,1),(0,2)let l=length let u=Printf.printf let rec o x i j=let a=map(fun s->copy s)!g in if snd(fold_left(fun(r,k)(p,l)->let z=c(a@r)in blit(make l ''#'')0(a@r)(i+p)l;if c(a@r)=z+l then r+1,k else r,false)(j-l x+1,true)x)then g:=a else o x i(j-1)and f x=let s=read_line()in if s.[1]=''=''then g:=rev x else f(sub s 1 10::x)let z=f [];read_line();;for i=0to w z/3 do o(assoc z.[i*3][''I'',[p;p;p;p];''O'',[q;q];''Z'',[q;1,2];''T'',[0,3;1,1];''L'',[p;p;q];''S'',[1,2;q];''J'',[1,1;1,1;q]])(Char.code z.[i*3+1]-48)(l!g-1);let h=l!g in g:=filter(fun s->c s<>w s)!g;for i=1to h-(l!g)do incr s;g:=make 10'' ''::!g done;done;iter(fun r->u"[%s]/n"r)!g;u"[==========]/n";u"%d/n"(!s*10)


Ruby 505 479 474 442 439 426 chars

A first attempt. Have done it with IronRuby. I''m sure it can be improved, but I really should get some work done today!

p,q,r,s=(0..9),(0..2),(0..6),0 t=[*$<] f=p.map{|a|g=0;r.map{|b|g+=2**b if t[6-b][a+1]==?#};g} t.pop.split.map{|x|w,y=[15,51,306,562,23,561,113]["IOZTLSJ"=~/#{x[0]}/],x[1].to_i l=q.map{|d|r.inject{|b,c|f[d+y]&(w>>(d*4)&15-c+1)>0?c:b}}.max q.map{|b|f[b+y]|=w>>(b*4)&15-l} r.map{i=f.inject{|a,b|a&b};f.map!{|a|b=i^(i-1);a=((a&~b)>>1)+(a&(b>>1))};s+=i>0?10:0}} p.map{|a|r.map{|b|t[6-b][a+1]=f[a]&2**b>0??#:'' ''}} puts t,s

Pruebas

cat test.txt | ruby tetris.rb [ ] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10

Edit Now using normal ruby. Got the walls output..


Otro en Ruby, 573 546 caracteres

: **

Z={I:?#*4,J:''#,###'',L:''###,#'',O:''##,##'',S:''#,##, #'',Z:'' #,##,#'',T:'' #,##, #''} t=[*$<] R=->s{s.reverse} T=->m{m.transpose} a = T[R[t].join.scan /.#{''(/D)''*10}.$/] t.pop.split.each{|z| t,o=Z[z[0].to_sym].split('','').map{|x|x.split //},z[1].to_i r=0..t.size-1 y=r.map{|u|1+a[o+u].rindex(?#).to_i-t[u].count('' '')}.max (0..3).each{|i|r.each{|j|t[j][i]==?#&&a[o+j][y+i]=t[j][i]}}} s=0 a.each{|x|s=a.max_by(&:size).size;x[s-=1]||='' ''while s>0} a=R[T[a].reject{|x|x*''''=~/[#]{10}/&&s+=10}.map{|x|?[+x*''''+?]}[0..6]] puts (0..8-a.size).map{?[+'' ''*10+?]},a,s

Pruebas:

cat test.txt | ruby 3858384_tetris.rb [ ] [ ] [ ] [ ] [# ###] [# ### ] [##### ####] [==========] 10