Historias
Slashboxes
Comentarios
 

Login Barrapunto

Login

[ Crear nueva cuenta ]

SEEDHVB (12751)

SEEDHVB
  (email no mostrado públicam.)
http://www.vernis.com.ar/

Down Kill Up Publicidad

Bitácora de SEEDHVB (12751)

Lunes, 06 de Octubre 2008

Haciendo crucigramas

06:32h.
Programación
El 3 de octubre Marga (Margarita Manterola) público un crucigrama hecho con Python [1].

[1] http://blogs.lug.fi.uba.ar/marga?title=cruzamiento &more=1&c=1&tb=1&pb=1

Hace algún tiempo yo había tenido la necesidad de hacer crucigramas por razones didácticas. Y busque alguna aplicación que me permitiera hacer los crucigramas en forma automática.

En aquel entonces, lo mejor que encontré fue ujpuzz [2]. Que aunque decía que entregaba una salida compatible con TeX, esta salida no era valida para mi versión de LaTeX. Sin embargo, escribí un pequeño script en Python que permitía utilizar los cruces de palabras generados por ujpuzz y usarlos para obtener una salida que si funcionara con mi LaTeX.

[2] http://www.gtoal.com/wordgames/gatekeeper/ujpuzz.c .

Hasta ahora no había publicado el código de este script, porque es feo. Pero dado que Marga público el código de su script [3,4], y pude hacer que este exporte fácilmente para mi propio script, decido publicar aquí tanto la pequeña modificación al script de Marga, como mi propio script, por sí le es de utilidad a alguien.

[3] http://blogs.lug.fi.uba.ar/marga/?p=183&more=1&c=1 &tb=1&pb=1#more183
[4] http://www.marga.com.ar/~marga/crucigrama.py

La siguiente función debe ser agregada al código del script de Marga, yo lo puse después de "imprimir_tablero", como verán es una modificación de esta función para guardar los cruces en un archivo en el disco.

Nota: ¿Alguien sabe donde puedo colgar archivos, y que no sea una molestía como RapidShare?

def exportar_a_LaTeX(tablero):
____posicion_maxima = 255
____lineas = []
____for linea in tablero:
________junto=''
________posicion = -1
________for letra in linea:
____________if letra!='*':
________________junto = junto + letra
____________else:
________________junto = junto + ' '
____________if letra!='*' and letra!=' ' and posicion<posicion_maxima:
________________posicio n_maxima = posicion
____________posicion+=1
________lineas. append(junto)
____fw=open('cruces.txt','w')
____ for linea in lineas:
________if not linea.isspace():
____________fw.write(linea[posic ion_maxima:]+u'\n')
____fw.close()

Mi script es:

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-

import sys
from Numeric import *

def EstaCercaDeUnaLetra(A,H,AM,HM,M):
____ECDUL=False
____## print 'A: ',A,'H: ',H,'AM: ',AM,'HM: ',HM,'M: ',M
____if A>0 and H>0 and M[A-1,H-1]==1:
________## print M[A-1,H-1]
________ECDUL=True
____elif H>0 and M[A,H-1]==1:
________## print M[A,H-1]
________ECDUL=True
____elif A<AM-1 and H>0 and M[A+1,H-1]==1:
________## print M[A+1,H-1]
________ECDUL=True
____elif A>0 and M[A-1,H]==1:
________## print M[A-1,H]
________ECDUL=True
____elif A<AM-1 and M[A+1,H]==1:
________ECDUL=True
____elif A>0 and H<HM-1 and M[A-1,H+1]==1:
________ECDUL=True
____elif H<HM-1 and M[A,H+1]==1:
________ECDUL=True
____elif A<AM-1 and H<HM-1 and M[A+1,H+1]==1:
________ECDUL=True
____return ECDUL

## Cargar Definiciones y Palabras
f=open(sys.argv[2], 'r')
Palabras=[]
Definiciones={}
CantidadPalabr as=0
for Linea in f.readlines():
____Linea=Linea.splitlines()[0]
_ ___Lugar=0
____Encontrado=0
____for Letra in Linea:
________if Letra==' ' and not Encontrado:
____________Encontrado=1
___________ _Palabras.append(Linea[0:Lugar])
____________Defi niciones[Linea[0:Lugar]]=Linea[Lugar+1:len(Linea)]
________Lugar+=1
____CantidadPalabras+=1
f.clo se
print 'Cantidad de Palabras: ',CantidadPalabras

## print Palabras
## print Definiciones

## Primera Pasada
f=open(sys.argv[1], 'r')
AnchoMaximo=0
AltoMaximo=0
PrimeroEspacio= True
for Linea in f.readlines():
____if PrimeroEspacio and Linea[0]!=' ':
________PrimeroEspacio=False
____LargoLinea=l en(Linea)-1
____if LargoLinea > AnchoMaximo:
________AnchoMaximo=LargoLinea
____ AltoMaximo+=1
f.close
if PrimeroEspacio:
____AnchoMaximo-=1
## AnchoMaximo+=1
print 'Ancho Maximo : ',AnchoMaximo
print 'Alto Maximo____: ',AltoMaximo
print 'Primero Espacio:',PrimeroEspacio

## Segunda Pasada
f=open(sys.argv[1], 'r')
Matriz=zeros((AnchoMaximo,AltoMaximo))
Alto =0
for Linea in f.readlines():
____## print Linea
____Ancho=0
____if PrimeroEspacio:
________Linea=Linea[1:len(Linea)- 1]
____for Letra in Linea:
________Matriz[Ancho,Alto]=Letra!=' '
________Ancho+=1
____Alto+=1
f.close

## print Matriz

## Preparar escritura
NuevoArchivo=sys.argv[1]+'.tex'
Archiv oSolucion=sys.argv[1]+'-sol.tex'
Espacio='|{}'
N egro='|*'
Terminacion='|.\n'
fw=open(NuevoArchiv o,'w')
fs=open(ArchivoSolucion,'w')
fw.write('\\ begin{Puzzle}{'+str(Ancho)+'}{'+str(Alto)+'}%\n')
fs.write('\\begin{Puzzle}{'+str(Ancho)+'}{'+str(A lto)+'}%\n')
fw.write('\Marco%\n')
fs.write('\Ma rco%\n')

## Tercera Pasada
f=open(sys.argv[1], 'r')
Alto=0
Numero=0
PalabrasHorizontales={}
P alabrasVerticales={}
PalabraColumna={}
NumeroCol umnas={}
Columnas=[]
Horizontales=[]
Verticales =[]
for Linea in f.readlines():
____Ancho=0
____Linea=Linea[0:len (Linea)-1]
____if len(Linea)<=AnchoMaximo:
________for i in range(len(Linea),AnchoMaximo+1):
____________Line a=Linea+' '
____if PrimeroEspacio:
________Linea=Linea[1:len(Linea)] +' '
____EsPalabraHorizontal=0
____EsPalabraVertica l=0
____for Letra in Linea:
________if Letra!=' ':
____________NumeroYa=0
____________if (Ancho>0 and Matriz[Ancho-1,Alto]==0 and Ancho<AnchoMaximo-1 and Matriz[Ancho+1,Alto]==1) or (Ancho==0 and Matriz[Ancho+1,Alto]==1):
________________## print 'H: ',Ancho,Alto,': ',Matriz[Ancho,Alto],': ',Matriz[Ancho-1,Alto],': ',Letra,': ' ,Linea
________________Numero+=1
_______________ _NumeroYa=1
________________EsPalabraHorizontal=1
________________PalabraHorizontal=''
__________ ______NumeroPalabraHorizontal=Numero
____________ if (Alto>0 and Matriz[Ancho,Alto-1]==0 and Alto<AltoMaximo-1 and Matriz[Ancho,Alto+1]==1) or (Alto==0 and Matriz[Ancho,Alto+1]==1):
________________if not NumeroYa:
____________________Numero+=1
________ ____________NumeroYa=1
________________NumeroColu mnas[Ancho]=Numero
________________Columnas.appen d(Ancho)
________________PalabraColumna[Ancho]=''
________________## print 'V: ',Ancho,Alto,': ',Matriz[Ancho,Alto],': ',Matriz[Ancho-1,Alto],': ',Letra,': ' ,Linea,Numero
____________if EsPalabraHorizontal:
________________PalabraHoriz ontal=PalabraHorizontal+Letra
____________if Ancho in Columnas:
________________PalabraColumna[Ancho]=P alabraColumna[Ancho]+Letra
____________## Escribir
____________LetraAEscribir='|'
________ ____if NumeroYa:
________________LetraAEscribir=LetraAEs cribir+'['+str(Numero)+']'+'[gf]'
____________if Letra!='-' and Letra!='_':
________________LetraAEscribir=LetraA Escribir+Letra
____________elif Letra=='-':
________________LetraAEscribir='\G{}| *\N{}'
____________elif Letra=='_':
________________LetraAEscribir='\E{}| *\N{}'
____________fw.write(LetraAEscribir)
____ ________fs.write(LetraAEscribir)
________else:
_ ___________if Ancho<AnchoMaximo:
________________## print EstaCercaDeUnaLetra(Ancho,Alto,AnchoMaximo,AltoMax imo,Matriz)
________________if EstaCercaDeUnaLetra(Ancho,Alto,AnchoMaximo,AltoMax imo,Matriz):
____________________fw.write(Negro)
________________else:
____________________fw.wri te(Espacio)
________________fs.write(Espacio)
__ __________if EsPalabraHorizontal:
________________PalabrasHori zontales[NumeroPalabraHorizontal]=PalabraHorizonta l
________________Horizontales.append(NumeroPalab raHorizontal)
________________## print PalabraHorizontal
________________EsPalabraHorizo ntal=0
____________if Ancho in Columnas:
________________PalabrasVerticales[Nume roColumnas[Ancho]]=PalabraColumna[Ancho]
________ ________Verticales.append(NumeroColumnas[Ancho])
________________del PalabraColumna[Ancho]
________________Columnas.re move(Ancho)
________Ancho+=1
____fw.write(Termin acion)
____fs.write(Terminacion)
____Alto+=1
f. close
## Guardar Ultimas Verticales

for Ancho in Columnas:
________PalabrasVerticales[NumeroColumn as[Ancho]]=PalabraColumna[Ancho]
________Vertical es.append(NumeroColumnas[Ancho])
fw.write('\\end{ Puzzle}%\n\n')
fs.write('\\end{Puzzle}%\n\n')
## print PalabrasHorizontales
## print PalabrasVerticales
## print Horizontales
## print Verticales

## Horizontales
fw.write('\\begin{PuzzleClues}{\\tex tbf{Horizontales: }}%\n')
fs.write('\\begin{PuzzleClues}{\\textbf{H orizontales: }}%\n')
## print "Horizontales: ",Horizontales
for i in Horizontales:
____## print "i:",i
____## print "i:",i
____fw.write('\\Clue{'+str(i)+'}{'+Palabra sHorizontales[i]+'}{'+Definiciones[PalabrasHorizon tales[i]]+'}%\n')
____fs.write('\\Clue{'+str(i)+' }{'+PalabrasHorizontales[i]+'}{'+Definiciones[Pala brasHorizontales[i]]+'}%\n')
fw.write('\\end{Puzz leClues}%\n')
fs.write('\\end{PuzzleClues}%\n')

## Verticales
Verticales.sort()
fw.write('\\begin{P uzzleClues}{\\textbf{Verticales: }}%\n')
fs.write('\\begin{PuzzleClues}{\\textbf{V erticales: }}%\n')
for i in Verticales:
____fw.write('\\Clue{'+str(i)+'}{'+Pa labrasVerticales[i]+'}{'+Definiciones[PalabrasVert icales[i]]+'}%\n')
____fs.write('\\Clue{'+str(i)+ '}{'+PalabrasVerticales[i]+'}{'+Definiciones[Palab rasVerticales[i]]+'}%\n')
fw.write('\\end{PuzzleC lues}%\n')
fs.write('\\end{PuzzleClues}%\n')

f w.close
fs.close

Además se necesita de una plantilla de LaTeX:

%
% basico.tex:
% basico (La)TeX
% Sergio Dami&#225;n Vernis (Octubre-2006)
% Versi&#243;n: v1.0
%
%%% * CLASE DE DOCUMENTO Y PAQUETES =================================
%%% ** General -------------------------------------------------- ----
%\documentclass[12pt,landscape]{article}____ % Habitual
\documentclass[11pt]{article}____ % Habitual
%\documentclass[a4paper,10pt]{scrartcl} % Usando el paquete
________________________________________ % koma-script: mejor
________________________________________ % preparado para
________________________________________ % documentos europeos.
\usepackage[english,spanish]{babel}
%% % ** Margenes de la p&#225;gina ----------------------------------------
%\usepac kage[top=0.95cm,bottom=0.95cm,left=2cm,right=2cm]{ geometry}
\usepackage[top=2cm,bottom=2cm,left=1.2 5cm,right=2.75cm]{geometry}
%%% ** Fuentes -------------------------------------------------- ----
\usepackage{lmodern}____________________ % Fuentes type1 basadas en
________________________________________ % CM que incluyen letras
________________________________________ % acentuadas: resuelve
________________________________________ % problemas en los pdf.
\usepackage[latin1]{inputenc}
\usepackage[T 1]{fontenc}
\usepackage{pifont}__________________ __ % Fuente para adornos
%%% ** Encabezados --------------------------------------------------
\usepackage{fancyhdr}
%%% ** Entornos verbatim --------------------------------------------
\use package{fancyvrb}
\usepackage{alltt}

%%% ** Bibliografia -------------------------------------------------
\usepackage[nottoc]{tocbibind}____________% No incluye TOC en TOC
\usepackage[longnamesfirst]{natbib}____ % Nombres largos primero
%%% ** Indices -------------------------------------------------- ----
%\usepackage{makeidx}____________________ % Indice de Materias
%%% ** Varios -------------------------------------------------- -----
\usepackage{longtable}____________________% Tablas Largas
\usepackage{color}________________________ % Color
\usepackage{texnames}____________________ % Procesado de nombres
________________________________________ % como BibTeX
%%% ** Salida pdf con hipervinculos ---------------------------------
%\usepackage{pd flscape}____________________% modo apaisado: mejor que
________________________________________ % lscape, en salidas pdf.
%\usepackage[pdftex]{graphicx, hyperref} % V&#237;nculos y gr&#225;ficos
___________________________________ _____ % en salida pdf.
\usepackage[pdftex,urlbordercolor=0 0 0,linkbordercolor=0 0 0,citebordercolor=0 0 0]{hyperref}
\usepackage[pdftex]{graphicx}
\usep ackage{epic}
\usepackage{rotating}
\usepackage{s oul} % \ul{texto subrayado equilibrado}
\usepackage{textcomp} % \textquotesingle ' Apostrofo sin inclinaci&#243;n
\usepackage{latexsym}
\usepacka ge{amsmath}
\usepackage{amssymb}

%%% * CONFIGURACIONES, ENTORNOS Y COMANDOS ==========================
%%% ** Configuracion del paquete hyperref ---------------------------
\hypersetup{
breaklinks = true,
colorlinks = false, % true,
pdftitle = {Crucigrama},
pdfauthor = {Sergio Dami&#225;n Vernis},
pdfsubject = {Palabras Cruzadas},
pdfkeywords = {Palabras Cruzadas},
pdfborder = 0 0 0,
pdfstartpage = 1}
%%% ** Macros para definir estructuras logicas ----------------------
\newcommand{\Code}[1]{{\sm all\texttt{#1}}}________ % Codigo `inline'.
\newcommand{\SCode}[1]{{\footnotesize\t exttt{#1}}} % Codigo `inline'
________________________________________ ____________% peque&#241;o.
\newcommand{\Prog}[1]{{\upshape\tex tsf{#1}}}________% Nombres de
______________________________________________ ______% programas.
______________________________________ ______________% y paquetes.
\DefineVerbatimEnvironment%____________ ____________ % Bloques de codigo.
{CodeBlock}{Verbatim}
{fontsize=\small}
\DefineVerbatimEnvironment%____ ____________________ % Bloques de codigo
{SCodeBlock}{Verbatim}____________________________ % pequeno.
{fontsize=\footnotesize}
\newenvironment{CodeEx}{ %________________________ % Bloques de codigo.
\begin{alltt}\small}{\end{alltt}}________ ________ % con instrucciones
___________________________________ _________________% procesables.
\newcommand{\Email}[1]{%
\href{mail to:#1?Subject=[basico]}{email: \texttt{#1}}}
\newenvironment{License}{\begin{quo tation}\sffamily}{\end{quotation}}
%%% ** Abreviaturas -------------------------------------------------
\definecolor{Mygrey}{gray}{0.50}
\newcommand{\Tu x}[1]{{\Code{\textcolor{Mygrey}{#1}}}}
\newcomman d{\SVerb}{\small\verb}
\newcommand{\BS}{\textback slash}

% Definiciones
% Puntuaci&#243;n en bibliograf&#237;a
\bibpunct[:]{\char40}{\char41}{ ,}{}{;}
% Relajaci&#243;n de reglas de composici&#243;n
\sloppy
% Desactivar ~ para la &#209;=~N
\deactivatetilden
% Espaciado tipo Espa&#241;ol - Frances
%\frenchspacing

% Crucigramas
%\usepackage[numbered,nocenter,small] {cwpuzzle}
\usepackage[numbered,small]{cwpuzzle}
% El tama&#241;o tambi&#233;n esta influenciado por el tama&#241;o de la letra en
% \documentclass[10pt]{article}

%%% * CUERPO DEL DOCUMENTO ==========================================
%%% ** -------------------------------------------------- ----
\begin{document}
\pagestyle{empty}
% Comun
\newcommand{\Marco}{}
\definecolor{griscla ro}{gray}{.9} % Color Cuadrado Negro
\definecolor{gray}{gray}{1} % Color primer Cuadrado de Palabras. 1=Blanco, 0=Gris
\newcommand{\N}{\renewcommand{\PuzzleBlack Box}{\textcolor{grisclaro}{\rule{\PuzzleUnitlength }{\PuzzleUnitlength}}}}
\newcommand{\E}{\renewcom mand{\PuzzleBlackBox}{\raisebox{-3ex}{\textvisible space{}}}}
\newcommand{\G}{\renewcommand{\PuzzleB lackBox}{--}}
\N{}
\PuzzleDefineColorCell{g}{gra y}
% Diferenciado
% ************ Solucion *************
% \PuzzleSolution
% ************ Solucion *************
\xdef\CrucigramaNormal{normal} % Crucigrama Normal
\makeatletter \ifx\Puzzle@TYPE\CrucigramaNormal \makeatother
\include{cruces.txt}
\else
\include{cruces.txt-sol}
\fi
\end{document}

También es necesario tener instalado el paquete cwpuzzle de LaTeX en su última versión. La que viene con Debian Lenny aún esta desactualizada.

Mi script recibe como parámetros dos archivos, uno con los cruces de palabras y otro con las palabras y las definiciones.

Los cruces de palabras es la salida del script de Marga hecho por mi función exportar_a_LaTeX.

El archivo de palabras y definiciones debe tener las palabras en mayúsculas, una por línea, cada una seguida por la definición, y separadas de las palabras por solo un espacio:

RECONSTRUCTIVA Relativa a la reconstrucción.
SUPERIORA Mujer que dirige una congregación religiosa.
DESAHUCIO Acción y efecto de deshauciar.
REFUGIADOS Hombres que se han encontrado refugio en otro país.
EDUCACION Formación acadámica de las personas.
COMIQUEA Representa comedias caseras.
MORDISQUEAR Morder de manera repetida pero con poca fuerza.
ADULTERIOS Infidelidades, deslealtades.
ESQUILAMOS Sacamos la lana de las ovejas.
EUFONIA Efecto acústico agradable, producido por una buena combinación de sílabas.
ESCUALIDOS Que está muy flaco.
SARDONICE Originario de Cerdeña.
HIPOTENUSA Lado opuesto al ángulo recto en un triángulo rectángulo.
SEUDONIMA Escritora que oculta su nombre verdadero con uno falso.
ESCUALIDO Extremadamente pobre.
QUEJILLOSAS Mujer que se queja demasiado.
HUMILLADERO Lugar devoto, marcado con una imagen o cruz, a la entrada de los pueblos o junto a los caminos.
FEUDALISMOS Sistemas de gobierno basados en un señor feudal y sus vasallos.
ESTUDIALO Aprendelo, entendelo, memorizalo.
GUIONAJE Oficio del guía que conduce y enseña el camino.
EUFORIAS Estados de alegría y optimismo.

El script de Marga toma las palabras de un archivo llamado 5vocales.txt que debe contener las palabras, una por línea, en mayúsculas.

Las palabras del crucigrama deben estar en mayúsculas y sin acentos.

Saludos.

Sergio.

Actualización: Se agregaron los links a la entrada del blog de Marga donde incluyó un link al código, y a varios textos interesantes sobre crucigramas. Así como, el link directo al código para los crucigramas.
Este hilo ha sido archivado. No pueden publicarse nuevos comentarios.
Mostrar opciones Umbral:
Y recuerda: Los comentarios que siguen pertenecen a las personas que los han enviado. No somos responsables de los mismos.
  • por lasizoillo (9545) el Lunes, 06 Octubre de 2008, 20:39h (#1088794)
    ( http://127.0.0.1/ | Última bitácora: Jueves, 01 Julio de 2010, 03:18h )
    No encuentro el código del script de marga en el enlace adjunto.

    Por otro lado, comentarte que hace un tiempo me interesé por algoritmos para jugar al scrabble. En cierta forma es un tema parecido al de hacer crucigramas y hay gran cantidad de analisis publicado sobre el tema. Algunos de los algoritmos que se utilizaban los he vuelto a ver en buscadores de texto y otras aplicaciones menos lúdicas. ¿Qué algoritmos usa el código de Marga?
    --
    Una vez metido, recordad lo sucedido [laquadrature.net].