Numeracja krzyżówek

9

Utwórz program do poprawnego numerowania siatki krzyżówek.

Wejście

Dane wejściowe to nazwa pliku reprezentującego siatkę krzyżówki. Wejściowa nazwa pliku może być przekazana jako argument na standardowym wejściu lub w inny konwencjonalny sposób niż kodowanie na stałe.

Format pliku siatki: plik tekstowy. Pierwszy wiersz składa się z dwóch stałych całkowitych oddzielonych spacjami Mi N. Po tej linii są M wiersze składające się ze Nznaków (plus nowy wiersz) wybranych spośród [#A-Z ]. Znaki te są interpretowane w taki sposób, że '#' oznaczają zablokowany kwadrat, ' 'otwarty kwadrat w łamigłówce bez znanej zawartości, a dowolną literę otwarty kwadrat zawierający tę literę.

Wynik

Wynik będzie plikiem numeracji i może zostać wysłany na standardowe wyjście, do pliku, którego nazwa pochodzi od wejściowej nazwy pliku, do pliku określonego przez użytkownika lub do innego konwencjonalnego miejsca docelowego.

Format pliku numeracji Plik tekstowy. Linie zaczynające się od „#” są ignorowane i mogą być użyte do komentarzy. Wszystkie inne linie zawierać kartę wydzielił triplet i, m, ngdzie ioznacza liczbę drukowany na siatce i mi nreprezentują wiersza i kolumny na placu, gdzie powinien zostać wydrukowany. Liczba zarówno wierszy, jak i kolumn zaczyna się od 1.

Schemat numerowania

Prawidłowo numerowana siatka ma następujące właściwości:

  1. Numeracja zaczyna się od 1.
  2. Żadna kolumna ani zakres otwartych kwadratów nie jest numerowany. (Możesz założyć, że w problemie nie będzie odpowiedzi na pojedynczy znak).
  3. Liczby będą napotykane w kolejności liczenia, skanując od górnego rzędu do dołu, biorąc każdy wiersz od lewej do prawej. (Tak więc każde przęsło poziome jest ponumerowane w jego lewym kwadracie, a każda kolumna jest ponumerowana w jego najwyższym kwadracie).

Testuj wejście i oczekiwane wyjście

Wejście:

5   5
#  ##
#    
  #  
    #
##  #

Dane wyjściowe (pomijając wiersze komentarza):

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

Na bok

Jest to pierwsze z wielu wyzwań związanych z krzyżówką. Planuję używać spójnego zestawu formatów plików w całym procesie i zbudować w tym czasie porządny zestaw narzędzi związanych z krzyżówkami. Na przykład kolejna układanka będzie wymagała wydrukowania wersji krzyżówki ASCII na podstawie danych wejściowych i wyjściowych tej układanki.

dmckee --- były kot moderator
źródło
Rozpiętości pojedynczych znaków nie są numerowane, prawda?
Keith Randall
@Kieth: Wolę regułę, w której nie ma takich zakresów, ale nie określiłem jej tutaj, ponieważ sprawdzanie poprawności siatki jest planowane jako kolejny problem. Przypuszczam, że to, czego używasz, jest kwestią gustu.
dmckee --- były moderator kociak
czy plik wejściowy będzie w txt?
www0z0k,
@ www0z0k: Tak. Maniak unixowy we mnie zawsze domyślnie korzysta z tekstu.
dmckee --- były moderator kociak
1
@ www0z0k: Podziały wierszy są rodzime na Twojej platformie. To dziesiętne ASCII 20 na mojej i reprezentowane jako '\n'c na wszystkich platformach. Założono, że plik wejściowy został utworzony w tym samym systemie, który go przetworzy, więc ten problem powinien być przejrzysty. Ogólna uwaga na temat golfa kodowego: jeśli pracujesz w obcym języku lub na dziwnej platformie, po prostu zanotuj wszystko, co może zaskoczyć czytelnika. Ludzie uwzględnią to, oceniając twoje zgłoszenie.
dmckee --- były moderator kociak

Odpowiedzi:

4

Rubin - 210 139 znaków

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])}

Testowane z Ruby 1.9.

Arnaud Le Blanc
źródło
Śledzę większość tego. Nie jestem pewien, co robi s.shift.split.map, ale to musi tworzyć tablicę z danych wejściowych.
dmckee --- były moderator kociak
BTW-- Jak powinienem wywołać go w linii poleceń unix. Próbowałem nadać mu odpowiedni szarpanie odpowiedni dla mojego systemu, ale narzeka ./temp.ruby:4: wrong argument type Symbol (expected Proc) (TypeError).
dmckee --- były moderator kociak
s.shift zajmuje pierwszą linię, split zwraca [„m”, „n”], mapa zwraca [m, n]. Używam go z ruby1.9 tak: ruby1.9 test.rb.
Arnaud Le Blanc
3

PHP - 175 znaków

<?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);
Arnaud Le Blanc
źródło
Zastanawiałem się, kiedy ktoś zrobi to w tablicy 1d.
dmckee --- były moderator kociak
3

Python, 194 177 176 172 znaków

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
Keith Randall
źródło
h.join(f)Myślę, że powinieneś być w stanie korzystać
gnibbler
i next(f)zamiast f.readline()jeśli masz> = 2,6 elsef.next()
gnibbler
Mój python nigdy nie był zbyt dobry, ale wygląda na to, że używasz dodatkowych „#” do obsługi skrzynek, nie? Otrzymuję jednak dziwne dane wyjściowe dotyczące danych testowych, w tym dodatkowe liczby.
dmckee --- były moderator kociak
@dmckee, tak, używam dodatkowych #s do zaznaczenia krawędzi. Czy możesz opublikować przypadek testowy, w którym uważasz, że zawodzi?
Keith Randall
@Kieth: W powyższym przypadku testowym otrzymuję 12 wierszy wyjściowych (a pierwszych 10 nie pasuje). Używam python2.6 lub 2.7 na moim komputerze Mac. Działa z tym echo test_input_file_name | python golf.py, czy to źle?
dmckee --- były moderator kociak
2

C ++ 270 264 260 256 253 znak

#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);}

Używać:

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

Ładnie sformatowane:

#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);
}

Próbowałem odczytać całą krzyżówkę za jednym razem i użyć jednej pętli.
Ale koszt rekompensaty dla postaci \ n przewyższał wszelkie zyski:

#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);
}

Skompresowany: 260 znaków

#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);}
Martin York
źródło
Zajęło mi to kilka prób prawidłowego wywołania tego. Przysiek.
dmckee --- były moderator kociak
2

C, 184 189 znaków

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);}

Nie ma tu wiele do powiedzenia; logika jest dość podstawowa. Program pobiera nazwę pliku na standardowe wejście w czasie wykonywania. (To tak denerwujące, że program musi pracować z nazwą pliku i nie może po prostu odczytać zawartości pliku bezpośrednio ze standardowego wejścia. Ale ten, kto płaci piperowi, wywołuje melodię!)

Dziwny fscanf()wzór to moja próba zeskanowania pełnej pierwszej linii, w tym nowej linii, ale bez uwzględnienia początkowych białych znaków w następnej linii. Jest powód, dla którego nikt nie używa scanf().

chlebak
źródło
Myślę, że odwrócisz liczbę wierszy i kolumn. Jeśli dobrze rozumiem, pierwsza liczba to liczba wierszy, ale traktujesz ją jako liczbę kolumn.
ugoren
Z tego, co mogę powiedzieć, dane wyjściowe mojego programu są zgodne z przykładem podanym w opisie oraz dane wyjściowe z implementacji referencyjnej. Czy możesz podać konkretny przykład tego, o czym mówisz?
pudełko
Dowolny przykład, w którym numery wierszy i kolumn nie są równe.
ugoren
Okej, ale przejdźmy do konkretów. Gdy podano przykładową siatkę podaną w opisie, mój program wypisuje (1,2) dla liczby 1. Czy mówisz, że mój program powinien wypisać (2,1)?
pudełko chleba
Mówię o danych wejściowych, a nie wyjściowych. Kiedy jest pierwszy wiersz 5 5, bierzesz pierwsze 5 jako szerokość, kiedy powinieneś wziąć drugi (co oczywiście nie ma znaczenia w tym przykładzie).
ugoren
1

Referencyjne wdrożenie:

ok. 99 nieoszlifowanych i ponad 2000 znaków, w tym wciąż dostępne różne froby debugujące.

#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;
}
dmckee --- były kot moderator
źródło
1

PerlTeX : 1143 znaków (ale jeszcze nie grałem w golfa)

\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}

Potrzebuje pliku wywołanego grid.txtze specyfikacją, a następnie skompilować z

perltex --nosafe --latex=pdflatex grid.tex
Joel Berger
źródło
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))}}
}}

kompilacja i wywołanie:

scalac cg-318-crossword.scala && cat cg-318-crossword | scala c
nieznany użytkownik
źródło
0

SKRYPT POWŁOKI

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

próbki I / O:

./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
Aman ZeeK Verma
źródło
Być może nie w pełni zrozumiałem wymagania, ponieważ właśnie próbowałem zrozumieć z podanych I / O, proszę wybaczyć, jeśli rozwiązanie jest tylko obejściem dla konkretnego przypadku :)
Aman ZeeK Verma
Moje /bin/shskargi dotyczą wiersza 11. Czy możesz powiedzieć, jakiej powłoki używasz (w tym numer wersji)?
dmckee --- były moderator kociak
Linia 8 wydaje się być podobna do linii 11 .. prawda? $ bash - wersja GNU bash, wersja 3.1.17 (1) -release (x86_64-suse-linux)
Aman ZeeK Verma 10.02 11.02
spróbuj zmodyfikować #! bin / sh do # /! / bin / bash, powinno działać teraz!
Aman ZeeK Verma,
0

Znaki ANSI C 694

Jest to wersja C, która szuka poziomych lub pionowych przebiegów dwóch spacji, które są albo skierowane ku krawędzi, albo przeciwko znakowi „#”.

Plik wejściowy jest pobierany ze standardowego wejścia i musi być:

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

Wszelkie wskazówki dotyczące kompaktowania zostaną z wdzięcznością przyjęte.

#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;
    }
}

Dane wyjściowe dla podanego przykładu

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
Jonathan Watmough
źródło
Ten kod poprawnie obsługuje # _ # pionowe i poziome luki pojedynczej spacji, które chociaż nie mogą występować jako pojedyncze niepołączone spacje, wydają się być dozwolone, np. Jako ostatnia litera, powiedzmy, poziomego słowa.
Jonathan Watmough