Salida de una cuadrícula de crucigramas jugable

8

Escriba un programa para producir un archivo que contenga una cuadrícula de crucigramas que el usuario pueda imprimir y resolver el rompecabezas.

Entrada

Un nombre de archivo que representa un archivo de cuadrícula de crucigramas y, opcionalmente, un segundo nombre de archivo que representa un archivo de numeración de crucigramas. La entrada debe ser aceptada por un medio convencional para su entorno de programación: argumentos de línea de comando, entrada estándar, formularios web, etc.

Puede suponer que el crucigrama ha sido validado , y si utiliza un archivo de numeración que corresponde a la cuadrícula proporcionada .

Formato de archivo de cuadrícula: la primera línea consta de dos constantes enteras separadas por espacios en blanco M y N. A continuación de esa línea hay M líneas que consisten en N caracteres (más una nueva línea) seleccionados entre [#A-Z ]. Estos caracteres se interpretan de tal manera que '#' indican un cuadrado bloqueado, ' 'un cuadrado abierto en el rompecabezas sin contenido conocido y cualquier letra un cuadrado abierto que contenga esa letra.

Formato del archivo de numeración Las líneas que comienzan con '#' se ignoran y pueden usarse para comentarios. Todas las demás líneas contienen una pestaña separada triplete i, m, ndonde irepresenta un número que va a imprimirse en la parrilla, y my nrepresentan la fila y columna de la plaza donde debe ser impreso. El número de filas y columnas comienza en 1.

Salida

El resultado será un archivo que el usuario puede imprimir y trabajar con un crucigrama. Se aceptarán ASCII, postscript, pdf, png y cualquier otro formato razonable, pero todos deben cumplir con estas reglas:

  1. Debe haber una regla alrededor del rompecabezas completo y entre cada par de cuadrados.
  2. Los cuadrados bloqueados deben rellenarse a oscuras
  3. En el cuadro de juego que representa el comienzo de una pista numerada (cruzada o hacia abajo) se debe proporcionar un número en la esquina superior izquierda del cuadrado, dejando la mayor parte del cuadrado en blanco para que la obra escriba. Tenga en cuenta que la cuadrícula típica publicado en los documentos tendrá muchas decenas de pistas y puede tener más de 100.

La salida será solo de la cuadrícula, sin la lista de pistas.

La salida debe enviarse a un destino convencional (un archivo cuyo nombre se deriva del nombre de archivo de entrada, producido como una página web, etc.)

Caso de prueba

Dada una entrada de

5   5
#  ##
#    
  #  
    #
##  #

la esquina inicial de una salida ASCII aceptable podría verse así

+-----+-----+-----+---
|#####|1    |2    |###
|#####|     |     |###
|#####|     |     |###
+-----+-----+-----+---
|#####|3    |     |4  
|#####|     |     |   
|#####|     |     |   
+-----+-----+-----+---
|6    |     |#####|   
|     |     |#####|   

Aquellos que utilizan formatos gráficos deben inspirarse en las fuentes impresas habituales.

Esquema de numeración

Una cuadrícula numerada correctamente tiene las siguientes propiedades:

  1. La numeración comienza en 1.
  2. Ninguna columna o tramo de cuadrados abiertos está sin numerar.
  3. Los números se encontrarán en orden de conteo escaneando de la fila superior a la inferior tomando cada fila de izquierda a derecha.

Aparte

Este es el tercero de varios desafíos relacionados con crucigramas. Planeo usar un conjunto consistente de formatos de archivo en todo momento y construir un conjunto respetable de utilidades relacionadas con crucigramas en el proceso.

Retos anteriores en esta serie:

dmckee --- gatito ex moderador
fuente
No puedo comentar, pero el resultado del ejemplo viola su propio esquema de numeración.
Megan Walker
@Samuel: Así es. Eso es lo que obtengo por escribirlo a mano en lugar de mirar hacia atrás en mi propio trabajo. Gracias. Corregido
dmckee --- ex-gatito moderador

Respuestas:

4

Python, 379 caracteres

import sys
A=sys.argv
f=open(A[1])
V,H=map(int,f.readline().split())
M={}
if A[2:]:
 for r in open(A[2]).readlines():n,y,x=map(int,r.split());M[y*H+y+x]=n
R='+-----'*H+'+'
n,v,s='\n| '
x=y=z=''
p=V+1
for c in n+''.join(f):
 if c==n:print x+n+y+n+z+n+R;x=y=z=''
 elif'@'>c:x+=5*c;y+=5*c;z+=5*c
 else:x+=5*s;y+=s+s+c+s+s;z+=5*s
 if p in M:x=x[:-5]+"%-5d"%M[p]
 x+=v;y+=v;z+=v;p+=1
Keith Randall
fuente
Funciona bien siempre que no haya comentarios en el archivo de numeración.
dmckee --- ex-gatito moderador
Puedes usar en next(f)lugar de f.readline(). No necesitas el .readlines()allí en absoluto.
gnibbler
10

Posdata 905 797 677 675 629 608 330 320 308

{G N}/Times-Roman .3 2 22 1 30/.{<920>dup 1 4 3 roll put cvx 
exec}def/${//. 73 .}def[/R{99<a51f3e7d75>$}/G{<1fab75>$ 
R(uN)${0 R{1(X)$ 0 1 -1 5 4 roll 35 eq{4<1980>$}if<81>$ 
1 add}(I)$(u)$ 0 -1<ad>$}<834d>$}/X{{exit}if}/N{-.9
.7<ad>${<1fab70>$ X}loop{{(>nk)$(  )<31a0>$}<a3>$
X}loop}>><0d38388b369bad8e3f>$

Este programa está escrito como un "prólogo de protocolo", por lo que solo debe juntarlo con la cuadrícula y los archivos de números (en ese orden, separados por líneas en blanco) y canalizar todo el desastre a ghostscript o Distiller o una impresora PS. Se adjunta a la versión de referencia a continuación un rompecabezas de NYT (del 5 de noviembre de 2011) con números y una respuesta de la que estoy bastante seguro (¡los sábados son difíciles!).

La nueva revisión utiliza estos dos procedimientos para ejecutar nombres de sistema codificados en binario a partir de cadenas.

/.{
    <920>  % two-byte binary-encoded name template with 0x92 prefix
    dup 1 4 3 roll put  % insert number into string
    cvx exec  % and execute it
}def
/${
    //.   %the /. procedure body defined above
    73 .  %"forall" (by code number)
}def

Sangrado y (algo) comentado.

/Times-Roman .3 2 22 1 30
/.{<920>dup 1 4 3 roll put cvx exec}def/${//. 73 .}def
[
/R{99<a51f3e7d75>$}    %currentfile 99 string readline pop 
/G{<1fab75>$ %currentfile token pop 
    R (uN)$ %<754e>$ %pop gsave
    {   
        0 R { 
            1 (X)$ %index
            0 1 -1 5 4 roll
            35 eq{ 
                4<1980>$ %copy rectfill
            }if 
            <81>$ %rectstroke
            1 add 
        }(I)$
        (u)$ % 73 . %forall pop 
        0 -1<ad>$ %translate
    }<834d>$ %repeat grestore
}
/X{{exit}if}
/N{
    -.9 .7<ad>$ %translate
    %{ currentfile token not {exit} if } loop
    {<1fab70>$
        X %{exit}if
    }loop
    {   
        %dup type/integertype ne{exit}if
        {
            (>nk)$ %<3e6e6b>$ %exch neg moveto
            (  )<31a0>$ %cvs show
        }<a3>$ %stopped
        X %{exit}if
    }loop
}
>>
<0d38388b369bad8e>$
%begin dup dup scale div setlinewidth translate selectfont
{G N}exec

Archivos de información.

15 15
     #   #     


       #     ##
##   #   #     
    #     #    
   #    #      
       #       
      #    #   
    #     #    
    K#   #   ##
##  I  #       
    L          
    N          
    S#   #     

#i m n   figure(number), row, col
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
6 1 7
7 1 8
8 1 9
9 1 11
10 1 12
11 1 13
12 1 14
13 1 15
14 2 1
15 2 6
16 2 10
17 3 1
18 4 1
19 4 9
20 5 3
21 5 7
22 5 8
23 5 11
24 5 14
25 5 15
26 6 1
27 6 2
28 6 6
29 6 10
30 6 12
31 7 1
32 7 5
33 7 10
34 7 11
35 8 1
36 8 4
37 8 9
38 9 1
39 9 8
40 9 13
41 10 1
42 10 6
43 10 7
44 10 12
45 11 1
46 11 5
47 11 7
48 11 11
49 12 3
50 12 6
51 12 9
52 12 10
53 12 14
54 12 15
55 13 1
56 13 2
57 13 8
58 14 1
59 15 1
60 15 7
60 15 11

Debería verse bien desde una impresora, pero en la pantalla necesita un poco de ayuda. Este procedimiento de 19 caracteres y 9 caracteres para invocarlo en todos los puntos de espacio de usuario ayuda a que las líneas espaciadas de manera uniforme se vean más uniformes. Entonces 308 + 19 + 9 = 337, usado para generar esta imagen.

/F{<ac893e893e5f>$} % transform round exch round exch itransform

salida de crucigramas

Postdata 608

Esta versión anterior (de la revisión 8 ) usa un enfoque completamente diferente, reutilizando el código de la línea principal como un "léxico" a partir del cual se pueden indexar tokens más largos usando cadenas.

<<-1{{30 700 translate 0 0 moveto
currentfile 2{(@A1*)*}repeat exch string
3 2 roll{('BO1)*{( )(@#)*
4(,.N:;<%)*<<( ){p}/#{(1:;>%)*}0{(;,'.)*
6 -26(CE%)*}>>(IJ'B)* known not{p
0}if(LG #C)*}forall(#;*1 D%)*}repeat
p/Times-Roman 8 selectfont 99
string{('BO)*{(@)* length(#=)*{p}{(@#L)*
35(=)*{p}{cvx(GID ?'H*ID ?KHF%)*(   )cvs(E)*}e}e}{showpage
exit}e}loop exit{( @#M# FMF#M)*
closepath}currentpoint stroke eq fill
mul dup token copy rmoveto sub show
neg exec add 1 index 9 get rlineto
put readline}loop}0 1 index 0 get{1
index 1 add}forall pop/*{{32 sub load
exec}forall}/e{ifelse}/p{pop}>>begin(23,?4)*<1f>*

Fue escrito usando esta versión comentada que ilustra la codificación del léxico. El primer token 30se comenta, spacepor ( )*lo tanto, es sinónimo de 30. No es muy beneficioso para 30, pero para tokens más largos esto es (fue) una gran victoria (hasta que se descubran posibilidades de codificación más profundas).

<<-1{{
%space  !    "         # $ %      &           '(        )     %*    +      , - .   %/
 30     700  translate 0 0 moveto currentfile 2{(@A1*)*}repeat exch string 3 2 roll
{('BO1)*{( )(@#)* 4(,.N:;<%)*<<( ){p}/#{(1:;>%)*}0{(;,'.)* 6 -26(CE%)*}>>(IJ'B)*
known not{p 0}if(LG #C)*}forall(#;*1 D%)*}
%0      1   2          3 4          5  6     7
 repeat p /Times-Roman 8 selectfont 99 string{('BO)*{(@)* length(#=)*{p}{
(@#L)* 35(=)*{p}{cvx(GID ?'H*ID ?KHF%)*(   )cvs(E)*}e}e}{showpage clear exit}e}
%8    9   :                         %;            <      =    >    ?
 loop exit{( @#M# FMF#M)* closepath} currentpoint stroke eq fill mul
%@   A     B    C       D   E    F   G    H   I J     K L   M       N   O
 dup token copy rmoveto sub show neg exec add 1 index 9 get rlineto put readline
}loop}0 1 index 0 get{1 index 1 add}forall
pop/*{{32 sub load exec}forall}/e{ifelse}/p{pop}>>begin(23,?4)*<1f>*
luser droog
fuente
1
No necesita conservar todas las versiones anteriores, ya que las personas pueden acceder al historial de la publicación si están realmente interesadas.
Peter Taylor
Entendido. Recortaré algo de grasa cuando actualice.
luser droog
He publicado algunas versiones alternativas en este hilo .
luser droog
La invocación funciona, ¿cómo?
usuario desconocido
1
Parece que la sobrecarga para el PostScript de estilo golf es aún mayor que mi solución "tradicional" ;-).
Thomas W.
4

C (salida a SVG), 553 caracteres

Lo sé, el código es enorme, pero este problema solo está pidiendo una respuesta SVG.

char*f,b[99];h,w;main(i){fscanf(f=fopen(gets(b),"r"),"%d%d%*[\n]",&h,&w);for(
printf("<svg xmlns='http://www.w3.org/2000/svg' viewBox='.9 .9 %d.2 %d.2'><path d='M1 1",
i=w,h);i--;)printf("v%dv-%dh1",h,h);for(;h--;)printf("v1h-%dh%d",w,w);for(
puts("' style='fill:none;stroke:#000;stroke-width:.04'/><path d='");
fgets(b,99,f);++h)for(i=0;i<w;)b[i++]-35||printf("M%d %dh1v1h-1Z",i,h+2);puts("'/>");
for(f=fopen(gets(b),"r");fgets(b,99,f);)sscanf(b,"%d%d%d",&i,&h,&w)>2&&
printf("<text x='%d.1' y='%d.3' style='font-size:.3px'>%d</text>",w,h,i);puts("</svg>");}

Cuando se ejecuta, obtiene los dos nombres de archivo en dos líneas separadas de entrada estándar; primero el archivo de cuadrícula, luego el archivo de números.

La lógica en este caso es bastante simple. El formato de SVG le permite crear todos los elementos en cualquier orden (en lugar de ir de arriba a abajo como con la solución de salida ASCII). El tamaño se debe casi por completo a la plantilla de SVG.

¡Pero la imagen resultante se ve genial!

Editado para agregar: Aquí hay una versión más corta (517 caracteres) que genera una resolución específica. Esto permite que el código use más configuraciones predeterminadas, pero con el costo prohibitivo (en mi opinión) de que el SVG ya no se redimensiona automáticamente en su navegador web.

char*f,b[99];h,w;main(i){fscanf(f=fopen(gets(b),"r"),"%d%d%*[\n]",&h,&w);for(
printf("<svg xmlns='http://www.w3.org/2000/svg'><path d='M1 1",i=w,h);i--;)
printf("v%d0v-%d0h50",h*5,h*5);for(;h--;)printf("v50h-%d0h%d0",w*5,w*5);for(
puts("' style='fill:none;stroke:#000'/><path d='");fgets(b,99,f);++h)
for(i=-1;++i<w;)b[i]-35||printf("M%d1 %d1h50v50h-50Z",i*5,h*5+5);puts("'/>");
for(f=fopen(gets(b),"r");fgets(b,99,f);)sscanf(b,"%d%d%d",&i,&h,&w)>2&&
printf("<text x='%d3' y='%d5'>%d</text>",w*5-5,h*5-4,i);puts("</svg>");}
caja de pan
fuente
¡El SVG se ve genial!
usuario desconocido
3

Haskell, 328 caracteres

import System
main=do(g:d)<-mapM(fmap lines.readFile)=<<getArgs;mapM_ putStrLn$g% \i k->[t|x<-d,y@(c:_)<-x,c/='#',(t,q)<-lex y,w q==i,k<1]
(s:g)%n=[q|(i,x)<-e g,q<-b s:[c['|':f#n[i,j]k|(j,f)<-e x]++"|"|k<-[0..2]]]++[b s]
'#'#_="#####";_#n=take 5$c n++"     ";b n='+':([1..w n!!1]>>"-----+")
e=zip[1..];c=concat;w=map read.words
hammar
fuente
2

C, 375 caracteres

char b[99];g[999],*r=g,*f,i,j,w;main(n){
for(fscanf(f=fopen(gets(b),"r"),"%*d%d%*[\n]",&w);fgets(b,99,f);)
for(i=0;i<w;)*r++=-(b[i++]==35);
for(f=fopen(gets(b),"r");fgets(b,99,f);)
sscanf(b,"%d%d%d",&n,&j,&i)?g[j*w-w+i-1]=n:0;
for(f=g;f<=r;f+=w){for(i=w;i--;)printf(" ----");puts("");
if(f<r)for(j=3;j--;puts("|"))
for(i=0;i<w;printf(~n?n&&j>1?"|%-4d":"|    ":"|////",n))n=f[i++];}}

Los dos nombres de archivo de entrada se ingresan en la entrada estándar, cada uno en una línea separada. La cuadrícula se representa en ASCII en la salida estándar. Sí, es una pésima interfaz de usuario, pero cualquier cosa mejor cuesta personajes. Me puse a invocarlo así:

printf "%s\n%s" grid.txt numbering.txt | ./crosswd-render > render.txt

El programa debe manejar correctamente cosas como líneas comentadas en el archivo de numeración.

caja de pan
fuente
*r++-=b[i++]==35( gse inicializa a ceros).
Ugoren
for(j=3*(f<r);j--;puts("|"))salva if.
Ugoren
n&&j>1->j/2*n
ugoren
2

Scala 463, formato de salida: html

object H extends App{val z=readLine.split("[ ]+")map(_.toInt-1)
val d="\t\t<td width='50' height='50'"
println("<html><table border='1'><tr>")
val b=(0 to z(0)).map{r=>readLine}
var c=0
(0 to z(0)).map{
y=>(0 to z(1)).map{
x=>if(b(y)(x)==' '&&((x==0||b(y)(x-1)==35)||(y==0||b(y-1)(x)==35))){
c+=1
println(d+"valign='top'>"+c+"</td>")}
else println(d+{if(b(y)(x)!=' ')"bgcolor='#0'>"else">&nbsp;"}+"</td>")}
println("\t</tr>\n\t<tr>")}
println("</table></html>")
}

Salida de muestra

usuario desconocido
fuente
Muy bonito. La salida se ve bien .
dmckee --- ex gatito moderador
2

Posdata (435) (434)

[/r{currentfile 999 string readline pop}/p{pop}/x{exch}/T{translate}/S{scale}/G{gsave}/R{grestore}/_( )>>begin/Courier 1 selectfont 
20 20 S
.05 setlinewidth{r token
p x p
dup 3 x 3 add
T
G G{R
0 -1 T
G
_ 0
r{0 0 1 1
4 index 35 eq{rectfill p}{rectstroke
put
.3 .1 moveto
_ show}ifelse
1 0 T _ 0}forall}repeat
R R
1 -1 S -.9 -.7 T{{r
dup 0 get 35 ne{( )search
p 3 2 roll
cvx exec
G
x
T
.4 -.4 S
0 0 moveto show
p
R}if}loop}stopped}exec

Sin golf con datos:

%!
<<
  /r{currentfile 999 string readline pop}
  /p{pop}
  /x{exch}
  /T{translate}
  /S{scale}
  /G{gsave}
  /R{grestore}
  /_( )
>>begin
/Courier 1 selectfont
% In theory, 20 20 scale isn't needed, 
% but it would make the whole thing very tiny when printed
% (on screen it doesn't matter too much, it can be zoomed)
20 20 S
.05 setlinewidth
{ % exec
% Read number of lines
r token                          % restString numberOfLines true
% Discard rest of line (Contains number of columns.
% It becomes clear implicitly from number of letters in a line of grid definition)
p x p                            % numberOfLines
% Move to where the top line starts
dup 3 x 3 add                    % numberOfLines x y
T                                % numberOfLines
G G
{ %repeat
  R
  % Move to next line
  0 -1 T
  G
  _ 0
  r                              % ( ) 0 line
  { %forall                      % ( ) 0 char
    0 0 1 1                      % ( ) 0 char 0 0 x y
    % Check whether char is a hash
    4 index 35 eq{ %ifelse
      4 copy rectfill
    }if
    rectstroke                   % ( ) 0 char
    put                          % -/-
    .3 .1 moveto
    _ show
    1 0 T
    _ 0                          % ( ) 0
  }forall                        % 
}repeat
R R
% Now, render the numbers according to the numbering definitions
1 -1 S -.9 -.7 T
{{
  r
  %Check whether this is a comment
  dup 0 get 35 ne{               % line
    % Split at the first tab
    %TODO: Ust tab instead of space
    ( )search                    % (y x) tab number true
    p 3 2 roll                   % tab number (y x)
    cvx exec                     % tab number y x
    G
    x                            % tab number x y
    T                            % tab number
    .4 -.4 S
    0 0 moveto show              % tab
    % This pop can be eliminated in theory to save two characters,
    % but the operand stack will continue to grow
    p
    R
  }if
}loop}stopped
}exec
15 15
     #   #     


       #     ##
##   #   #     
    #     #    
   #    #      
       #       
      #    #   
    #     #    
    K#   #   ##
##  I  #       
    L          
    N          
    S#   #     
#i m n   figure(number), row, col
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
6 1 7
7 1 8
8 1 9
9 1 11
10 1 12
11 1 13
12 1 14
13 1 15
14 2 1
15 2 6
16 2 10
17 3 1
18 4 1
19 4 9
20 5 3
21 5 7
22 5 8
23 5 11
24 5 14
25 5 15
26 6 1
27 6 2
28 6 6
29 6 10
30 6 12
31 7 1
32 7 5
33 7 10
34 7 11
35 8 1
36 8 4
37 8 9
38 9 1
39 9 8
40 9 13
41 10 1
42 10 6
43 10 7
44 10 12
45 11 1
46 11 5
47 11 7
48 11 11
49 12 3
50 12 6
51 12 9
52 12 10
53 12 14
54 12 15
55 13 1
56 13 2
57 13 8
58 14 1
59 15 1
60 15 7
60 15 11
Thomas W.
fuente
Increíble. Realmente necesito hacer un mejor uso de stopped. ... Dejaré la recompensa abierta por un día más o menos para llamar la atención.
luser droog
1

Postdata, no combatiente.

Inspirado (una vez más) por su pregunta relacionada con SO , hice una versión de referencia en Postscript usando file-IO. También crea una fuente derivada de ancho fijo para que los datos de la cuadrícula simplemente se pasen show. es una caja vacía y #es una caja llena. Cualquier otro carácter ascii se dibuja como un pequeño glifo de la época romana rodeado de una caja.

Este programa utiliza una función ghostscript que puede no estar presente en todos los intérpretes PostScript. Si se invoca ghostscript con la --opción, pasa los argumentos de la línea de comandos al programa postscript en una matriz de cadenas llamada / ARGUMENTOS. Entonces necesita invocar el programa de esta manera gs -- xw-io.ps grid-file number-file.

%!

ARGUMENTS{}forall
/numfile exch (r) file def
/gridfile exch (r) file def

/q{0 0 moveto 1 0 lineto 1 1 lineto 0 1 lineto closepath}def
/X<</FontType 3/FontBBox[0 0 1 1]/FontMatrix[1 0 0 1 0 0]
    /Encoding StandardEncoding
    /BuildChar{
        1 0 0 0 1 1 setcachedevice
        .001 setlinewidth
        q stroke
        dup 35 eq { pop
            q fill
        }{
            .3 .1 moveto
            .1 .1 scale
            /Times-Roman 8 selectfont
            (?)dup 0 4 3 roll put show
        }ifelse pop}
>>definefont pop /X 30 selectfont
40 700 moveto {
    gridfile 2{dup token pop exch}repeat pop pop
    {
        gridfile =string readline{
            dup length 0 ne{
                show currentpoint exch pop 30 sub 40 exch moveto
            }{clear exit}ifelse
        }{clear exit}ifelse
    }loop
    /Times-Roman 8 selectfont
    {
        40 700 moveto
        numfile =string readline{
            dup length 0 ne{
                dup 0 get 35 ne{
                    cvx exec
                    1 sub 30 mul 2 add exch
                    1 sub -30 mul 22 add rmoveto
                    (   )cvs show
                }{clear}ifelse
            }{clear}ifelse
        }{clear exit}ifelse
    }loop showpage
}exec
luser droog
fuente
Se ve muy bien. ¿Como es de grande? Cuento 1247 caracteres. Pero se puede jugar al golf, ¿no? Una traducción simple 4 espacios en blanco => 1 pestaña lleva a 980 caracteres, eliminando todas las pestañas a 891.
usuario desconocido
Debido a todas las palabras especiales necesarias para crear una fuente, esta no puede hacerse más pequeña que mi otra respuesta PostScript.
luser droog