Kreuzworträtselnummerierung


9

Erstellen Sie ein Programm, um ein Kreuzworträtsel richtig zu nummerieren.

Eingang

Die Eingabe ist der Name einer Datei, die das Kreuzworträtsel darstellt. Der Eingabedateiname kann als Argument, für die Standardeingabe oder auf andere herkömmliche Weise als durch Hardcodierung übergeben werden.

Rasterdateiformat: Eine Textdatei. Die erste Zeile besteht aus zwei durch Leerzeichen getrennten Ganzzahlkonstanten Mund N. Nach dieser Zeile folgen M Zeilen, die jeweils aus NZeichen (plus einer neuen Zeile) bestehen [#A-Z ]. Diese Zeichen werden so interpretiert, dass sie '#' ein blockiertes Quadrat, ' 'ein offenes Quadrat im Puzzle ohne bekannten Inhalt und einen Buchstaben ein offenes Quadrat anzeigen, das diesen Buchstaben enthält.

Ausgabe

Die Ausgabe ist eine Nummerierungsdatei und kann an die Standardausgabe, an eine Datei, deren Name vom Eingabedateinamen abgeleitet ist, an eine benutzerdefinierte Datei oder an ein anderes herkömmliches Ziel gesendet werden.

Nummerierungsdateiformat Eine Textdatei. Zeilen, die mit '#' beginnen, werden ignoriert und können für Kommentare verwendet werden. Alle anderen Zeilen enthalten eine Lasche getrennt Triplett i, m, nwobei ieine Reihe auf dem Raster gedruckt werden soll , darstellt, und mund ndie Zeile und Spalte des Quadrates darstellen , wo sie gedruckt werden sollen. Die Anzahl der Zeilen und Spalten beginnt bei 1.

Nummerierungsschema

Ein korrekt nummeriertes Raster hat die folgenden Eigenschaften:

  1. Die Nummerierung beginnt bei 1.
  2. Keine Spalte oder Spanne offener Quadrate ist nicht nummeriert. (Sie können davon ausgehen, dass das Problem keine Einzelzeichenantwort enthält.)
  3. Zahlen werden in Zählreihenfolge gefunden, indem von der oberen bis zur unteren Reihe gescannt wird, wobei jede Reihe von links nach rechts genommen wird. (Jede horizontale Spanne ist also am äußersten linken Quadrat nummeriert, und jede Spalte ist am obersten Quadrat nummeriert.)

Testeingabe und erwartete Ausgabe

Eingang:

5   5
#  ##
#    
  #  
    #
##  #

Ausgabe (Vernachlässigung von Kommentarzeilen):

1       1       2
2       1       3
3       2       2
4       2       4
5       2       5
6       3       1
7       3       4
8       4       1
9       4       3
10      5       3

Beiseite

Dies ist die erste von hoffentlich mehreren Herausforderungen im Zusammenhang mit Kreuzworträtseln. Ich plane, durchgehend eine konsistente Reihe von Dateiformaten zu verwenden und dabei eine seriöse Suite von Kreuzworträtsel-bezogenen Dienstprogrammen aufzubauen. Zum Beispiel erfordert ein nachfolgendes Puzzle das Drucken einer ASCII-Version des Kreuzworträtsels basierend auf der Eingabe und Ausgabe dieses Puzzles.


Einzelzeichenbereiche sind nicht nummeriert, oder?
Keith Randall

@Kieth: Ich bevorzuge die Regel, bei der es keine solchen Bereiche gibt, aber ich habe sie hier nicht angegeben, da die Validierung des Rasters als weiteres Problem geplant ist. Ich nehme an, was Sie verwenden, ist Geschmackssache.
dmckee --- Ex-Moderator Kätzchen

Wird die Eingabedatei in txt sein?
www0z0k

@ www0z0k: Ja. Der Unix-Geek in mir verwendet immer standardmäßig Text.
dmckee --- Ex-Moderator Kätzchen

1
@ www0z0k: Zeilenumbrüche sind alles, was auf Ihrer Plattform nativ ist. Das ist ASCII-Dezimalzahl 20 auf meiner und '\n'auf allen Plattformen wie in c dargestellt. Es wird davon ausgegangen, dass die Eingabedatei auf demselben System erstellt wurde, auf dem sie verarbeitet wird. Daher sollte dieses Problem transparent sein. Ein allgemeiner Hinweis zum Code-Golf: Wenn Sie in einer fremden Sprache oder auf einer fremden Plattform arbeiten, notieren Sie sich einfach alles, was den Leser überraschen könnte. Die Leute werden dies bei der Beurteilung Ihrer Einreichung berücksichtigen.
dmckee --- Ex-Moderator Kätzchen

Antworten:


4

Ruby - 210 139 Zeichen

o=0
(n=(/#/=~d=$<.read.gsub("
",S='#'))+1).upto(d.size-1){|i|d[i]!=S&&(i<n*2||d[i-1]==S||d[i-n]==S)&&print("%d\t%d\t%d
"%[o+=1,i/n,i%n+1])}

Getestet mit Rubin 1.9.


Ich folge dem größten Teil davon. Ich bin nicht sicher, was s.shift.split.map macht, aber das muss das Array aus der Eingabe bilden.
dmckee --- Ex-Moderator Kätzchen

Übrigens: Wie soll ich es über eine Unix-Befehlszeile aufrufen? Ich habe versucht, ihm einen für mein System geeigneten Schebang zu geben, aber er beschwert sich ./temp.ruby:4: wrong argument type Symbol (expected Proc) (TypeError).
dmckee --- Ex-Moderator Kätzchen

s.shift nimmt die erste Zeile, split gibt ["m", "n"] zurück, map gibt [m, n] zurück. Ich verwende es mit ruby1.9 wie folgt : ruby1.9 test.rb.
Arnaud Le Blanc

3

PHP - 175 Zeichen

<?for($i=$n=strpos($d=strtr(`cat $argv[1]`,"\n",$_="#"),$_)+$o=1;isset($d[$i]);++$i)$d[$i]!=$_&($i<$n*2|$d[$i-1]==$_|$d[$i-$n]==$_)&&printf("%d\t%d\t%d\n",$o++,$i/$n,$i%$n+1);

Ich fragte mich, wann jemand es in einem 1d-Array tun würde.
dmckee --- Ex-Moderator Kätzchen

3

Python, 194 177 176 172 Zeichen

f=open(raw_input())
V,H=map(int,next(f).split())
p=W=H+2
h='#'
t=W*h+h
n=1
for c in h.join(f):
 t=t[1:]+c;p+=1
 if'# 'in(t[-2:],t[::W]):print"%d\t%d\t%d"%(n,p/W,p%W);n+=1

Sie sollten in der Lage sein, h.join(f)denke ich
Gnibbler

und next(f)anstatt f.readline()wenn du> = 2.6 sonst f.next()
bist

Mein Python war nie sehr gut, aber es sieht so aus, als würden Sie zusätzliche '#' verwenden, um die Randfälle zu behandeln, nicht wahr? Ich erhalte jedoch einige ungerade Ausgaben für die Testdaten, einschließlich zusätzlicher Zahlen.
dmckee --- Ex-Moderator Kätzchen

@dmckee, ja, ich benutze zusätzliche #s, um die Kante zu markieren. Können Sie einen Testfall veröffentlichen, bei dem Sie glauben, dass er fehlschlägt?
Keith Randall

@ Kieth: Für den obigen Testfall bekomme ich 12 Ausgangsleitungen (und die ersten 10 stimmen nicht überein). Verwenden von Python2.6 oder 2.7 auf meinem Mac. Laufen Sie mit echo test_input_file_name | python golf.py, ist das falsch?
dmckee --- Ex-Moderator Kätzchen

2

C ++ 270 264 260 256 253 char

#include<string>
#include<iostream>
#define X cin.getline(&l[1],C+2)
using namespace std;int main(){int r=0,c,R,C,a=0;cin>>R>>C;string l(C+2,35),o(l);X;for(;++r<=R;o=l)for(X,c=0;++c<=C;)if(l[c]!=35&&(l[c-1]==35||o[c]==35))printf("%d %d %d\n",++a,r,c);}

Benutzen:

g++ cross.cpp -o cross
cat puzzle |  cross

Schön formatiert:

#include<string>
#include<iostream>
// using this #define saved 1 char
#define X cin.getline(&l[1],C+2)

using namespace std;

int main()
{
    int r=0,c,R,C,a=0;
    cin>>R>>C;
    string l(C+2,35),o(l);
    X;

    for(;++r<=R;o=l)
        for(X,c=0;++c<=C;)
            if(l[c]!=35&&(l[c-1]==35||o[c]==35))
                printf("%d %d %d\n",++a,r,c);
}

Ich habe versucht, das gesamte Kreuzworträtsel auf einmal zu lesen und eine einzige Schleife zu verwenden.
Aber die Kosten für die Kompensation des '\ n-Charakters überwogen alle Gewinne:

#include <iostream>
#include <string>
#define M cin.getline(&l[C+1],R*C
using namespace std;

int main()
{
    int R,C,a=0,x=0;
    cin>>R>>C;
    string l(++R*++C,35);
    M);M,0);

    for(;++x<R*C;)
        if ((l[x]+=l[x]==10?25:0)!=35&&(l[x-1]==35||l[x-C]==35))
            printf("%d %d %d\n",++a,x/C,x%C);
}

Komprimiert: 260 Zeichen

#include<iostream>
#include<string>
#define M cin.getline(&l[C+1],R*C
using namespace std;int main(){int R,C,a=0,x=0;cin>>R>>C;string l(++R*++C,35);M);M,0);for(;++x<R*C;)if((l[x]+=l[x]==10?25:0)!=35&&(l[x-1]==35||l[x-C]==35))printf("%d %d %d\n",++a,x/C,x%C);}

Ich habe ein paar Versuche unternommen, es richtig aufzurufen. Glatt.
dmckee --- Ex-Moderator Kätzchen

2

C, 184 189 Zeichen

char*f,g[999],*r=g;i,j,n;main(w){
for(fscanf(f=fopen(gets(g),"r"),"%*d%d%*[\n]",&w);fgets(r,99,f);++j)
for(i=0;i++<w;++r)
*r==35||j&&i>1&&r[-w]-35&&r[-1]-35||printf("%d\t%d\t%d\n",++n,j+1,i);}

Hier gibt es nicht viel zu sagen; Die Logik ist ziemlich einfach. Das Programm übernimmt zur Laufzeit den Dateinamen bei der Standardeingabe. (Es ist so ärgerlich, dass das Programm mit einem Dateinamen arbeiten muss und nicht einfach den Dateiinhalt direkt von der Standardeingabe lesen kann. Aber derjenige, der den Piper bezahlt, nennt die Melodie!)

Das seltsame fscanf()Muster ist mein Versuch, die gesamte erste Zeile zu scannen, einschließlich der neuen Zeile, jedoch ohne führende Leerzeichen in der folgenden Zeile. Es gibt einen Grund, warum niemand verwendet scanf().


Ich denke, Sie kehren die Zeilen- und Spaltennummer um. Wenn ich das richtig verstehe, ist die erste Zahl die Anzahl der Zeilen, aber Sie behandeln sie als die Anzahl der Spalten.
Ugoren

Soweit ich das beurteilen kann, entspricht die Ausgabe meines Programms dem in der Beschreibung angegebenen Beispiel und der Ausgabe der Referenzimplementierung. Können Sie mir ein konkretes Beispiel dafür geben, worauf Sie sich beziehen?
Brotkasten

Jedes Beispiel, bei dem die Zeilen- und Spaltennummern nicht gleich sind.
Ugoren

Okay, aber lassen Sie uns bitte spezifisch werden. Wenn das in der Beschreibung angegebene Beispielraster angegeben ist, gibt mein Programm (1,2) für die Nummer 1 aus. Wollen Sie damit sagen, dass mein Programm (2,1) ausgeben soll?
Brotkasten

Ich spreche von Eingabe, nicht Ausgabe. Wenn die erste Zeile ist 5 5, nehmen Sie die erste 5 als Breite, wenn Sie die zweite hätten nehmen sollen (was in diesem Beispiel natürlich keine Rolle spielt).
Ugoren

1

Referenzimplementierung:

c99 ungolfed und eher mehr als 2000 Zeichen, einschließlich verschiedener Debugging-Kittel, die noch vorhanden sind.

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

void printgrid(int m, int n, char grid[m][n]){
  fprintf(stderr,"===\n");
  for (int i=0; i<m; ++i){
    for (int j=0; j<n; ++j){
      switch (grid[i][j]) {
      case '\t': fputc('t',stderr); break;
      case '\0': fputc('0',stderr); break;
      case '\n': fputc('n',stderr); break;
      default: fputc(grid[i][j],stderr); break;
      }
    }
    fputc('\n',stderr);
  }
  fprintf(stderr,"===\n");
}

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 main(int argc, char** argv){
  const char *infname;
  FILE *inf=NULL;
  FILE *outf=stdout;

  /* deal with the command line */
  switch (argc) {
  case 3: /* two or more arguments. Take the second to be the output
         filename */
    if (!(outf = fopen(argv[2],"w"))) {
      fprintf(stderr,"%s: Couldn't open file '%s'. 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: Number a crossword grid.\n\t%s <grid file> [<output file>]\n",
       argv[0],argv[0]);
    return 0;
  }

  /* Read the grid size from the first line */
  int m=0,n=0;
  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]='#';
    }
  }

/*    printgrid(m,n,grid); */
  readgrid(inf,m,n,grid);
/*    printgrid(m,n,grid);  */

  /* loop through the grid  produce numbering output */
  fprintf(outf,"# Numbering for '%s'\n",infname);
  int num=1;
  for (int i=0; i<m; ++i){
    for (int j=0; j<n; ++j){
/*       fprintf(stderr,"\t\t\t (%d,%d): '%c' ['%c','%c']\n",i,j, */
/*        grid[i][j],grid[i-1][j],grid[i][j-1]); */
      if ( grid[i][j] != '#' &&
       ( (i == 0) || (j == 0) ||
         (grid[i-1][j] == '#') ||
         (grid[i][j-1] == '#') )
         ){
    fprintf(outf,"%d\t%d\t%d\n",num++,i+1,j+1);
      }
    }
  }
  fclose(outf);
  return 0;
}

1

PerlTeX : 1143 Zeichen (aber ich habe es noch nicht gespielt)

\documentclass{article}

\usepackage{perltex}
\usepackage{tikz}

\perlnewcommand{\readfile}[1]{
  open my $fh, '<', shift;
  ($rm,$cm) = split /\s+/, scalar <$fh>;
  @m = map { chomp; [ map { /\s/ ? 1 : 0 } split // ] } <$fh>;
  return "";
}

\perldo{
  $n=1;
  sub num {
    my ($r,$c) = @_;
    if ($r == 0) {
      return $n++;
    }
    if ($c == 0) {
      return $n++;
    }
    unless ($m[$r][$c-1] and $m[$r-1][$c]) {
      return $n++;
    }
    return;
  }
}

\perlnewcommand{\makegrid}[0]{
  my $scale = 1;
  my $return;
  my ($x,$y) = (0,$r*$scale);
  my ($ri,$ci) = (0,0);
  for my $r (@m) {
    for my $open (@$r) {
      my $f = $open ? '' : '[fill]';
      my $xx = $x + $scale;
      my $yy = $y + $scale;
      $return .= "\\draw $f ($x,$y) rectangle ($xx,$yy);\n";

      my $num = $open ? num($ri,$ci) : 0;
      if ( $num ) {
        $return .= "\\node [below right] at ($x, $yy) {$num};";
      }

      $x += $scale;
      $ci++;
    }
    $ci = 0;
    $x = 0;
    $ri++;
    $y -= $scale;
  }
  return $return;
}

\begin{document}
\readfile{grid.txt}

\begin{tikzpicture}
  \makegrid
\end{tikzpicture}

\end{document}

Es benötigt eine Datei, die grid.txtmit der Spezifikation aufgerufen und dann mit kompiliert wird

perltex --nosafe --latex=pdflatex grid.tex

1

Scala 252:

object c extends App{val z=readLine.split("[ ]+")map(_.toInt-1)
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(c+"\t"+(y+1)+"\t"+(x+1))}}
}}

Zusammenstellung und Aufruf:

scalac cg-318-crossword.scala && cat cg-318-crossword | scala c

0

SHELL-SKRIPT

#!/bin/sh
crossWordFile=$1

totLines=`head -1 $crossWordFile | cut -d" " -f1`
totChars=`head -1 $crossWordFile | awk -F' ' '{printf $2}'`

NEXT_NUM=1
for ((ROW=2; ROW<=(${totLines}+1); ROW++))
do
   LINE=`sed -n ${ROW}p $crossWordFile`
   for ((COUNT=0; COUNT<${totChars}; COUNT++))
   do
      lineNumber=`expr $ROW - 1`
      columnNumber=`expr $COUNT + 1`
      TOKEN=${LINE:$COUNT:1}
      if [ "${TOKEN}" != "#" ]; then
      if [ ${lineNumber} -eq 1 ] || [ ${columnNumber} -eq 1 ]; then
          printf "${NEXT_NUM}\t${lineNumber}\t${columnNumber}\n"
          NEXT_NUM=`expr $NEXT_NUM + 1`
      elif [ "${TOKEN}" != "#" ] ; then
          upGrid=`sed -n ${lineNumber}p $crossWordFile | cut -c"${columnNumber}"`
          leftGrid=`sed -n ${ROW}p $crossWordFile | cut -c${COUNT}`
          if [ "${leftGrid}" = "#" ] || [ "${upGrid}" = "#" ]; then
          printf "${NEXT_NUM}\t${lineNumber}\t${columnNumber}\n"
          NEXT_NUM=`expr $NEXT_NUM + 1`
          fi
      fi
      fi
   done
done

Beispiel-E / A:

./numberCrossWord.sh crosswordGrid.txt

1       1       2
2       1       3
3       2       2
4       2       4
5       2       5
6       3       1
7       3       4
8       4       1
9       4       3
10      5       3

Ich habe die Anforderungen möglicherweise nicht vollständig verstanden, da ich nur versucht habe, anhand der bereitgestellten E / A zu verstehen. Bitte verzeihen Sie, wenn die Lösung nur eine Problemumgehung für einen bestimmten Fall darstellt :)
Aman ZeeK Verma

Meine /bin/shBeschwerden über Zeile 11. Können Sie sagen, welche Shell Sie verwenden (einschließlich Versionsnummer)?
dmckee --- Ex-Moderator Kätzchen

Zeile 8 scheint Zeile 11 ähnlich zu sein. $ bash --version GNU bash, Version 3.1.17 (1) -Veröffentlichung (x86_64-suse-linux)
Aman ZeeK Verma

Versuchen Sie, #! bin / sh in # /! / bin / bash zu ändern. Es sollte jetzt funktionieren!
Aman ZeeK Verma

0

ANSI C 694 Zeichen

Dies ist eine C-Version, die nach horizontalen oder vertikalen Läufen von zwei Leerzeichen sucht, die entweder gegen die Kante oder gegen ein # -Zeichen stoßen.

Die Eingabedatei stammt von stdin und muss sein:

<rows count> <cols count><newline>
<cols characters><newline> x rows
...

Alle Tipps zum Verdichten werden dankbar entgegengenommen.

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

#define H '#'

char *p,*g;
int m=0,d=0,r=0,c=0,R=0,C=0;
void n() {
    while(!isdigit(d=getchar()));
    m=d-'0';
    while(isdigit(d=getchar()))
        m=m*10+d-'0';
}

int t() {
    return (((c<1||*(p-1)==H)&&c<C-1&&*p!=H&&p[1]!=H)||
            ((r<1||*(p-C-1)==H)&&r<R-1&&*p!=H&&p[C+1]!=H));
}

int main (int argc, const char * argv[]) 
{
    n();R=m;m=0;n();C=m;
    p=g=malloc(R*C+R+1);
    while((d=getchar())!=EOF) {
        *p++=d;
    }
    int *a,*b;
    b=a=malloc(sizeof(int)*R*C+R+1);
    p=g;m=0;
    while(*p) {
        if(t()) {
            *a++=++m;
            *a++=r+1;
            *a++=c+1;
        }
        if(++c/C) r++,p++;
        c-=c/C*c;
        p++;
    }
    while(*b) {
        printf("%d\t%d\t%d\n",*b,b[1],b[2]);
        b+=3;
    }
}

Ausgabe für das bereitgestellte Beispiel

1   1   2
2   1   3
3   2   2
4   2   4
5   2   5
6   3   1
7   3   4
8   4   1
9   4   3
10  5   3

Dieser Code behandelt # _ # vertikale und horizontale Einzelraumlücken korrekt, die, obwohl sie möglicherweise nicht als einzelner nicht verbundener Raum auftreten, zulässig zu sein scheinen, z. B. als letzter Buchstabe eines beispielsweise horizontalen Wortes.
Jonathan Watmough
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.