再生可能なクロスワードグリッドを出力する


8

ユーザーが印刷してパズルを作成できるクロスワードグリッドを含むファイルを作成するプログラムを記述します。

入力

クロスワードグリッドファイルを表すファイル名と、オプションでクロスワード番号付けファイルを表す2番目のファイル名。入力は、コマンドライン引数、標準入力、Webフォームなど、プログラミング環境の従来の方法で受け入れる必要があります。

クロスワードが検証済みで提供されたグリッドに対応するナンバリングファイルを使用していると想定できます

グリッドファイル形式:最初の行は、空白で区切られた2つの整数定数MとNで構成され[#A-Z ]ます。その行の後には、から選択されたN文字(および新しい行)で構成されるM行があります。これらの文字は'#' 、ブロックされた四角、' '内容が不明なパズルの開いた四角、およびその文字を含む開いた四角を示すように解釈されます。

番号付けファイル形式 '#'で始まる行は無視され、コメントに使用できます。他のすべての行はタブ区切りトリプレット含むim、数がグリッド上に印刷されるべきであり、そしてそれが印刷されるべきである正方形の行と列を表しています。行と列の両方の数は1から始まります。nimn

出力

出力は、ユーザーが印刷してクロスワードを処理できるファイルになります。ASCII、postscript、pdf、png、およびその他の合理的な形式はすべて受け入れられますが、すべて次の規則に従う必要があります。

  1. パズル全体と、正方形の各ペアの間にはルールが必要です。
  2. ブロックされた正方形は暗く塗りつぶす必要があります。
  3. 番号付き(横または下)の開始を表すプレイスクエアでは、スクエアの左上隅に番号を付け、プレイが書き込むためにスクエアの大部分を空白のままにする必要があります。一般的なグリッドに注意してください論文で公開されたものは、数十の手がかりがあり、100以上ある場合があります。

手がかりのリストなしで、出力はグリッドのみになります。

出力は従来の宛先(入力ファイル名から派生した名前のファイル、Webページとして生成されたファイルなど)に送信する必要があります。

テストケース

の入力が与えられた

5   5
#  ##
#    
  #  
    #
##  #

受け入れ可能なASCII出力の開始コーナーは次のようになります。

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

グラフィック形式を使用している人は、通常の印刷されたソースからインスピレーションを得るべきです。

採番スキーマ

正しい番号のグリッドには、次のプロパティがあります。

  1. 番号は1から始まります。
  2. 開いた正方形の列またはスパンには番号が付けられていません。
  3. 番号は、各行を左から右に取って、上から下にスキャンすることにより、カウント順に発生します。

さておき

これは、いくつかのクロスワード関連の課題の3番目です。私は一貫して一貫したファイル形式のセットを使用し、その過程でクロスワード関連ユーティリティの立派なスイートを構築する予定です。

このシリーズの以前の課題:


コメントはできませんが、出力例は独自の番号付けスキームに違反しています。
Megan Walker

@サミュエル:それはそうです。それは自分の作品を振り返るのではなく、手で書くことで得られるものです。ありがとう。修正。
dmckee ---元モデレーターの子猫

回答:


4

Python、379文字

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

ナンバリングファイルにコメントがない限りうまくいきます。
dmckee ---元モデレーターの子猫

next(f)代わりに使用できますf.readline()。そこはまったく必要ありません.readlines()
gnibbler

10

追記 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>$

このプログラムは「プロトコルプロローグ」として書かれているので、グリッドファイルと番号ファイル(この順序で、空白行で区切られています)と一緒にcatし、混乱全体をghostscriptまたはDistillerまたはPSプリンターにパイプします。以下の参照バージョンに追加されたのは、数字と1つの答えが含まれたNYTパズル(2011年11月5日から)です(1つは確かにわかります(土曜日は難しい!)。

新しいリビジョンでは、これらの2つの手順を使用して、バイナリエンコードされたシステム名を文字列から実行します。

/.{
    <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

インデントされ、(ある程度)コメントされました。

/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

データファイル。

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

プリンタからは問題なく見えるはずですが、画面上では少し手助けが必要です。この19文字の手順とすべてのユーザー空間ポイントでそれを呼び出すための9文字は、等間隔の線をより均一に見えるようにするのに役立ちます。したがって、308 + 19 + 9 = 337は、この画像の生成に使用されます。

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

クロスワード出力

追記608

この以前のバージョン(リビジョン8以降)は完全に異なるアプローチを使用しており、メイン行のコードを「レキシコン」として再利用し、そこから文字列を使用して長いトークンにインデックスを付けることができます。

<<-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>*

これは、レキシコンのエンコーディングを示すこのコメント付きバージョンを使用して書かれました。最初のトークン30はコメント化されているspaceため( )*、の同義語です30。にとってはそれほど有益で30はありませんが、より長いトークンにとっては、これは大きな勝利でした(より深いエンコーディングの可能性が発見されるまで)。

<<-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>*

1
本当に興味があれば投稿の履歴にアクセスできるので、古いバージョンをすべて保持する必要はありません。
Peter Taylor

わかった。更新時に脂肪を少し減らします。
luser droog

このスレッドにいくつかの代替バージョンを投稿しました。
luser droog

呼び出しはどのように機能しますか?
ユーザー不明の

1
ゴルフスタイルのPostScriptのオーバーヘッドは、私の「従来の」ソリューションよりも大きいようです;-)。
Thomas W.

4

C(SVGへの出力)、553文字

コードは巨大ですが、この問題は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>");}

実行すると、標準入力の2つの別々の行で2つのファイル名を取得します。最初にグリッドファイル、次に数値ファイル。

これのロジックは実際には非常に単純です。SVGの形式により、すべての要素を任意の順序で作成できます(ASCII出力ソリューションのように上から下に移動するのではなく)。サイズは、ほぼ完全にSVGボイラープレートによるものです。

しかし、結果の画像は見栄えがいいです!

追加用に編集:特定の解像度で出力する短いバージョン(517文字)です。これにより、コードはより多くのデフォルト設定を使用できますが、(私の頭では)非常に高いコストで、SVGが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>");}

SVGはすばらしく見えます!
ユーザー不明

3

Haskell、328文字

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

2

C、375文字

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++];}}

2つの入力ファイル名は、標準入力で、それぞれ別の行に入力されます。グリッドは標準出力でASCIIでレンダリングされます。はい、UIはお粗末ですが、文字の方がコストが高くなります。私はそれを次のように呼び出すことにしました:

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

プログラムは、ナンバリングファイルのコメント行などを正しく処理する必要があります。


*r++-=b[i++]==35gゼロに初期化されます)。
ugoren

for(j=3*(f<r);j--;puts("|"))保存しifます。
ugoren

n&&j>1->j/2*n
ugoren

2

Scala 463、出力フォーマット: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>")
}

出力例


非常にきれい。出力は良さそうです。
dmckee ---元モデレーターの子猫2013

2

PostScript (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

データなしのゴルフ:

%!
<<
  /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

驚くばかり。をもっとうまく活用する必要がありstoppedます。...注目を集めるために、賞金を1日ほど開いたままにします。
luser droog

1

追記、非戦闘。

SOに関する関連する質問に触発されて(まだ)、私はファイルIOを使用してPostscriptで参照バージョンを作成しました。また、グリッドデータが単にに渡されるように、派生した固定幅フォントを作成しshowます。空のボックスで#あり、塗りつぶされたボックスです。その他のASCII文字は、ボックスで囲まれた小さなTimes-Romanグリフとして描画されます。

このプログラムは、すべてのPostscriptインタープリターには存在しない可能性があるゴーストスクリプト機能を利用します。オプションを指定してghostscriptを呼び出すと、--コマンドライン引数が/ ARGUMENTSという名前の文字列の配列でpostscriptプログラムに渡されます。したがって、このようなプログラムを呼び出す必要があります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

素晴らしく見える。それはどれくらい大きいですか?1247文字を数えます。しかし、それはゴルフすることができます-それはできませんか?簡単な翻訳4つのブランク891にすべてのタブを排除する980文字まで=> 1点のタブリード、
ユーザー不明

フォントを作成するために必要なすべての特別な単語のため、これは他のポストスクリプトの回答よりも小さくすることはできません。
luser droog
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.