クロスワードグリッドの検証


8

提案されたクロスワードグリッドを検証します。

エントリは、提案されたグリッドを単純にテストして、クロスワードソルバーを満足させるための一連の条件を満たすかどうかを判断する完全なプログラムである必要があります。

入力

入力は、クロスワードグリッドを表すファイルの名前になります。入力ファイル名は、引数として、標準入力で、またはハードコーディング以外の従来の手段で渡すことができます。

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

出力

プログラムは有効なグリッドに出力を生成せず、通常の終了状態で終了します。提案されたグリッドが失敗した場合、実行環境でサポートされていれば、プログラムは診断エラーメッセージを生成し、異常終了状態(UNIXでは0ではない)で終了します。エラーメッセージには、違反している有効性の条件と違反している正方形の場所の両方が示されているはずです。これらの事実を伝える手段を自由に選択できます。

妥当性の条件

有効なグリッドには、1文字の長さ(最小長を入力パラメーターにするための追加のクレジット)の回答(横または下)がなく、通常の対称性を示します。通常の対称性は、クロスワードが後も同じままであることを意味します(同じ操作の3つの同等の説明)。

  • それ自身の中心を通した反射
  • 垂直方向と水平方向の両方の反射
  • 180度回転

テスト入力と期待される出力

パス:

5   5
#  ##
#    
  #  
    #
##  #

短い答えに失敗します:

5   5
## ##
#    
  #  
    #
## ##

対称性に失敗:

5   5
#  ##
#    
  #  
#   #
##  #

さておき

これは、クロスワードに関連するいくつかの課題の2番目です。私は一貫して一貫したファイル形式のセットを使用し、その過程でクロスワード関連ユーティリティの立派なスイートを構築する予定です。たとえば、後続のパズルでは、このパズルの入力と出力に基づいてクロスワードのASCIIバージョンを印刷する必要があります。

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


1
対称性の要件はグリッドの既知のコンテンツにも適用されますか、それとも構造(#または#ではない)のみに適用されますか?
JB、

ブロックされたインプレイスクエアの構造のみ。
dmckee ---元モデレーターの子猫11/02/12

ああ、これはすでに賞金がありました。残念。それでも、2つの答えは少し少ないと思います。
ジョーイ

中心の対称性と180度回転は同じものです。そうではありませんか。しかし、私は垂直方向も水平方向の対称性も見ていません。しかし90°回転。
ユーザー不明

回答:


4

ルビー- 215 207

t,*d=$<.map &:chop;n,d,e=t.size+1,(d*S=?#).gsub(/[^#]/,W=" "),->c,i{puts [c,i/n+1,i%n+1]*" ";exit 1}
0.upto(d.size-1){|i|d[i]==d[-i-1]||e[?R,i];d[i]==W&&(d[i-1]!=W&&d[i+1]!=W||d[i-n]!=W&&d[i+n]!=W)&&e[?L,i]}

未ゴルフ:

h, *g = $<.map &:chop
w = h.size+1
g = (g*?#).gsub(/[^#]/," ")
error = ->c,i{ puts [c,i/w+1,i% w+1]*" "; exit 1 }
0.upto(size-1) { |i|
        error[?R, i] if g[i] != g[-i-1]
        error[?L,i] if g[i]==" " && (g[i-1]!=" " && g[i+1]!=" " || g[i-w]!=" " && g[i+w] != " ")
}

h, *g = $<.map &:chop

これは基本的に、各入力行でchopメソッドを呼び出して結果の配列を返すことにより、各入力行の最後の文字(改行)を削除します。

hこの配列の最初の要素を*g取り、残りを取ります。したがって、最初の行がにhなり、クロスワードグリッドの行がになりgます。

g = (g*?#).gsub(/[^#]/," ")

g*?#*)と配列gを結合します"#"?#は文字リテラルです)。これはg.*("#")、またはと同じg.join("#")です。次に、すべての非#スペースがスペースに置き換えられます。

対称性チェックでは、すべてのインデックスの文字が文字列の反対側のインデックスの文字と等しいかどうかを確認するだけです。

0.upto(g.size-1) { |i| if g[i] != g[g.size - i - 1]; error() }

ルビーでは、負のインデックスを使用して端からインデックス文字列が(から開始することができる-1代わりに、0それはそう)g[-i-1]の反対であるg[i]文字列です。これはいくつかの文字を節約します:

0.upto(g.size-1) { |i| if g[i] != g[-i-1]; error() }

;条件ステートメントを使用してaを保存できます。

0.upto(g.size-1) { |i| error() if g[i] != g[-i-1] }

ゴルフバージョンでは、さらにいくつかの文字を保存できます。

0.upto(g.size-1){|i|g[i]==g[-i-1]||error()}

以前のバージョンでは、文字列を反復するために再帰を使用していました:

(f=->i{g[i]&&f[i+1]&&g[i]!=g[-i-1]&&error()})[0]

への範囲外のアクセスgはnil を返すため、一度をg[i]返すnilと、反復が停止します。

出力フォーマット:

{ L | R } line-number column-number

Lは長さエラー、Rは回転エラー(L 1 2つまり、行1、列2での長さエラーを意味します)


ルビーを話さない私たちのために少し説明してもらえますか?プレイ中のマスから黒以外のマスをどのように削除したか、解答の長さのチェックがどのように機能するか(いいですね、ところでBTW)はわかりますが、対称性のチェックは完全にはできていません。
dmckee ---元モデレーターの子猫

グリッドの幅がどのように決定されるかという問題がここにあります-最初の線の長さを取ることによって。これは正しくありません。その行が "5 --- 5"(中央に3つのスペース)である例でのみ機能します。「5 5」の場合は機能しません。
Nas Banov

また、1行目を上に移動して1行下(+ n)と1行上(-n)を見ると、「縦方向の折り返し」に問題があると思います。後者は最後の行を見て、誤ってそこから送迎スペース!
Nas Banov

さてあなたはグリッドの幅に適しています。最初の行では、2番目の数値は常に行の末尾に揃えられていると想定しました。
Arnaud Le Blanc

1

リファレンス実装

c99

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void readgrid(FILE *f, int m, int n, char grid[m][n]){
  int i = 0;
  int j = 0;
  int c = 0;
  while ( (c = fgetc(f)) != EOF) {
    if (c == '\n') {
      if (j != n) fprintf(stderr,"Short input line (%d)\n",i);
      i++;
      j=0;
    } else {
      grid[i][j++] = c;
    }
  }
}

int isSymmetric(int m, int n, char g[m][n]){
  for (int i=0; i<m; ++i)
    for (int j=0; j<n; ++j)
      if ( (g[i][j]=='#') != (g[m-i-1][n-j-1]=='#') )
    return j*m+i;
  return -1;
}

int isLongEnough(int m, int n, char g[m][n], int min){
  /* Check the rows */
  for (int i=0; i<m; ++i) {
    int lo=-(min+1); /* last open square */
    int lb=-1;       /* last blocked square */
    for (int j=0; j<n; ++j) {
      if ( g[i][j] == '#' ) {
    /* blocked square */
    if ( (lo == j-1) && (j-lb <= min+1) ) return lo*m+i;
    lb=j;
      } else {
    /* In-play square */
    lo=j;
      }
    }
  }

  /* Check the columns */
  for (int j=0; j<n; ++j) {
    int lo=-(min+1); /* last open square */
    int lb=-1;       /* last blocked square */
    for (int i=0; i<m; ++i) {
      if ( g[i][j] == '#' ) {
    /* blocked square */
    if ( (lo == i-1) && (i-lb <= min+1) ) return lo*m+i;
    lb=i;
      } else {
    /* In-play square */
    lo=i;
      }
    }
  }

  /* Passed */
  return -1;
}

int main(int argc, char** argv){
  const char *infname;
  FILE *inf=NULL;
  FILE *outf=stdout;
  int min=1;

  /* deal with the command line */
  switch (argc) {
  case 3: /* two or more arguments. Take the second to be the minium
         answer length */
    if ( (min=atoi(argv[2]))<1 ) {
      fprintf(stderr,"%s: Minimum length '%s' too short. Exiting.",
          argv[0],argv[2]);
      return 2;
    }
    /* FALLTHROUGH */
  case 2: /* exactly one argument */
    infname = argv[1];
    if (!(inf = fopen(infname,"r"))) {
      fprintf(stderr,"%s: Couldn't open file '%s'. Exiting.",
          argv[0],argv[1]);
      return 1;
    };
    break;
  default:
    printf("%s: Verify crossword grid.\n\t%s <grid file> [<minimum length>]\n",
       argv[0],argv[0]);
    return 0;
  }

  /* Read the grid size from the first line */
  int m=0,n=0,e=-1;
  char lbuf[81];
  fgets(lbuf,81,inf);
  sscanf(lbuf,"%d %d",&m,&n);

  /* Intialize the grid */
  char grid[m][n];
  for(int i=0; i<m; ++i) {
    for(int j=0; j<n; ++j) {
      grid[i][j]='#';
    }
  }

  readgrid(inf,m,n,grid);

  if ((e=isSymmetric(m,n,grid))>=0) {
    fprintf(stderr,"Symmetry violation at %d,%d.\n",e/m+1,e%m+1);
    return 4;
  } else if ((e=isLongEnough(m,n,grid,min))>=0) {
    fprintf(stderr,"Short answer at %d,%d.\n",e/m+1,e%m+1);
    return 8;
  }
  return 0;
}

1

C、278文字

char*f,g[999],*r=g;i,j,h,w;main(e){
for(fscanf(f=fopen(gets(g),"r"),"%*d%d%*[\n]",&w);fgets(g+h*w,99,f);++h);
for(;j++<h;)for(i=0;i++<w;++r)if(e=*r==35^g[g+w*h-r-1]==35?83:
*r==35||i>1&r[-1]!=35|i<w&r[1]!=35&&j>1&r[-w]!=35|j<h&r[w]!=35?0:76)
exit(printf("%d%c%d\n",j,e,i));exit(0);}

ご想像のとおり、エラーメッセージ自体が原因です。それらは次の形式を取ります:

11L8 -行11列8の長さエラーを示します

4S10 -行4列10の対称性エラーを示します


1

APL(115)

{∨/,k←⍵≠⌽⊖⍵:'⍉',(,k×⍳⍴k)~⊂2/0⋄×⍴d←(,⊃,/(g(⍉g←⍳⍴⍵))×{k↑1⌽1⊖0 1 0⍷¯1⌽¯1⊖⍵↑⍨2+k←⍴⍵}¨⍵(⍉⍵))~⊂2/0:'∘',d}d↑↑{'#'≠⍞}¨⍳⊃d←⎕

グリッドが対称的でない場合は、座標が後に出力されます。つまり、例では、

⍉2 5 4 1
グリッドに短い回答がある場合、グリッドに続いて座標が出力されます。つまり、例では
∘1 2 5 2

説明:

  • d↑↑{'#'≠⍞}¨⍳⊃d←⎕:最初の行を数値のリストとして読み取り、に格納してdから、最初の数値と同じ数の行を読み取り、サイズの行列として再形成しますd。「閉じた」正方形は0として格納され、「開いた」正方形は1として格納されます。
  • ∨/,k←⍵≠⌽⊖⍵kグリッドが非対称である場所に保管します。こんなところがあると...
  • '⍉',(,k×⍳⍴k)~⊂2/0:⍉に続いて問題の座標を出力します
  • : さもないと...
  • ~⊂2/0:次のリストからゼロ座標を削除します。
  • ¨⍵(⍉⍵):グリッドとその転置の両方について...
  • ¯1⌽¯1⊖⍵↑⍨2+k←⍴⍵:グリッドをゼロで囲みます(つまり、閉じた正方形)
  • 0 1 0⍷:2つの「閉じた」正方形で囲まれた「開いた」正方形が含まれている場所を確認(=短すぎる)
  • k↑1⌽1⊖:余分なゼロのリングを再度削除します
  • ,⊃,/(g(⍉g←⍳⍴⍵))×:座標と転置された座標を乗算し、結合して、問題のある座標(および削除する多くのゼロ)のリストを形成します。
  • ×⍴d←:問題の座標をに保存し、d存在する場合は...
  • :'∘',d:∘に続けて座標を出力します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.