Нумерация кроссвордов


9

Создайте программу для правильной нумерации сетки кроссвордов.

вход

Входными данными будет имя файла, представляющего сетку кроссвордов. Имя файла ввода может быть передано в качестве аргумента на стандартном вводе или другими обычными способами, кроме жесткого кодирования.

Формат файла сетки: текстовый файл. Первая строка состоит из двух целочисленных констант, разделенных пробелами, Mи N. После этой строки находятся M строки, каждая из которых состоит из Nсимволов (плюс новая строка), выбранных из [#A-Z ]. Эти символы интерпретируются так, что они '#' обозначают заблокированный квадрат, ' 'открытый квадрат в загадке без известного содержания, а любая буква - открытый квадрат, содержащий эту букву.

Вывод

Вывод будет файлом нумерации и может быть отправлен на стандартный вывод, в файл, имя которого получено из имени входного файла, в указанный пользователем файл или в другое обычное место назначения.

Формат файла нумерации Текстовый файл. Строки, начинающиеся с «#», игнорируются и могут использоваться для комментариев. Все остальные строки содержат вкладки разделены триплет i, m, nгде iпредставляет собой число , которое будет напечатано на сетке, а также mи nпредставлять строку и столбец площади , где он должен быть напечатан. Количество строк и столбцов начинается с 1.

Схема нумерации

Правильно пронумерованная сетка имеет следующие свойства:

  1. Нумерация начинается с 1.
  2. Ни один столбец или диапазон открытых квадратов не пронумерован. (Вы можете предположить, что в задаче не будет односимвольного ответа.)
  3. Числа будут встречаться в порядке подсчета путем сканирования от верхнего ряда к нижнему, принимая каждый ряд слева направо. (Таким образом, каждый горизонтальный промежуток пронумерован в самом левом квадрате, а каждый столбец пронумерован в самом верхнем квадрате.)

Проверка ввода и ожидаемого выхода

Входные данные:

5   5
#  ##
#    
  #  
    #
##  #

Вывод (без учета комментариев):

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

В стороне

Это первая из нескольких проблем, связанных с кроссвордами. Я планирую использовать согласованный набор форматов файлов и создать респектабельный набор утилит, связанных с кроссвордами. Например, последующая головоломка потребует распечатать ASCII-версию кроссворда на основе входных и выходных данных этой головоломки.


Односимвольные интервалы не нумеруются, верно?
Кит Рэндалл

@Kieth: Я предпочитаю правило, когда таких промежутков нет, но я не указал его здесь, потому что проверка сетки запланирована как другая проблема. Я полагаю, что вы используете это вопрос вкуса.
dmckee --- котенок экс-модератора

входной файл будет в текстовом формате?
www0z0k

@ www0z0k: да. У меня вундеркинд unix по умолчанию всегда текст.
dmckee --- котенок экс-модератора

1
@ www0z0k: Разрывы строк - это то, что присуще вашей платформе. Это ASCII десятичный 20 на моем и представлен как '\n'в c на всех платформах. Предполагается, что входной файл был создан в той же системе, в которой он будет обрабатываться, поэтому эта проблема должна быть прозрачной. Общее примечание о код-гольфе: если вы работаете на странном языке или на странной платформе, просто запишите все, что может удивить читателя. Люди будут учитывать это при оценке вашего представления.
dmckee --- котенок экс-модератора

Ответы:


4

Рубин - 210 139 символов

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

Протестировано с ruby ​​1.9.


Я следую большую часть этого. Не уверен, что делает s.shift.split.map, но это должно формировать массив из входных данных.
dmckee --- котенок экс-модератора

Кстати, как я должен вызвать его в командной строке Unix. Я попытался дать ему шебанг, соответствующий моей системе, но он жалуется ./temp.ruby:4: wrong argument type Symbol (expected Proc) (TypeError).
dmckee --- котенок экс-модератора

s.shift занимает первую строку, split возвращает ["m", "n"], map возвращает [m, n]. Я бегу это с ruby1.9 , как это: ruby1.9 test.rb.
Арно Ле Блан


3

Питон, 194 177 176 172 символов

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

Вы должны быть в состоянии использовать, h.join(f)я думаю
gnibbler

и next(f)вместо того, f.readline()если вы> = 2,6 иначеf.next()
gnibbler

Мой питон никогда не был очень хорош, но похоже, что вы используете дополнительные # для обработки крайних случаев, не так ли? Тем не менее, я получаю странный вывод на тестовые данные, в том числе дополнительные цифры.
dmckee --- котенок экс-модератора

@dmckee, да, я использую дополнительные # для обозначения края. Можете ли вы опубликовать тестовый случай, где вы думаете, что это не удается?
Кит Рэндалл

@Kieth: Для тестового примера выше я получаю 12 выходных строк (и первые 10 не совпадают). Использование python2.6 или 2.7 на моем Mac. Запуск с этим echo test_input_file_name | python golf.py, это неправильно?
dmckee --- котенок экс-модератора

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

Использовать:

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

Красиво отформатирован:

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

Я попытался прочитать весь кроссворд за один раз и использовать один цикл.
Но стоимость компенсации персонажа '\ n перевесила любую выгоду:

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

Сжатый: 260 символов

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

Взял у меня несколько попыток вызвать это правильно. Slick.
dmckee --- котенок экс-модератора

2

C 184 189 символов

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

Не так много, чтобы сказать здесь; логика довольно проста. Программа берет имя файла на стандартный ввод во время выполнения. (Это так раздражает, что программа должна работать с именем файла и не может просто читать содержимое файла напрямую из стандартного ввода. Но тот, кто платит пайперу, вызывает мелодию!)

Странный fscanf()шаблон - моя попытка отсканировать всю первую строку, включая новую строку, но не включая начальные пробелы в следующей строке. Есть причина, почему никто не использует scanf().


Я думаю, что вы измените номер строк и столбцов. Если я правильно понимаю, первое число - это число строк, но вы относитесь к нему как к числу столбцов.
Угорен

Из того, что я могу сказать, выходные данные моей программы соответствуют примеру, приведенному в описании, и выходным данным эталонной реализации. Можете ли вы дать мне конкретный пример того, что вы имеете в виду?
хлебница

Любой пример, где номера строк и столбцов не равны.
Угорен

Хорошо, но давайте уточним, пожалуйста. Когда приведен пример сетки, представленной в описании, моя программа выдает (1,2) для числа 1. Вы говорите, что моя программа должна вывести (2,1)?
хлебница

Я говорю о входе, а не о выходе. Когда первая строка 5 5, вы берете первые 5 в качестве ширины, когда вы должны были взять вторую (что, конечно, не имеет значения в этом примере).
Угорен

1

Эталонная реализация:

c99 ungolfed и более 2000 персонажей, включая различные отладочные лягушки, все еще там.

#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 символа (но я еще не играл в гольф)

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

Нужен файл, вызванный grid.txtс помощью спецификации, затем скомпилируйте с

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

1

Скала 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))}}
}}

компиляция и вызов:

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

0

ОБОЛОЧКА

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

образец ввода / вывода:

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

Мои /bin/shжалобы на строку 11. Не могли бы вы сказать, какую оболочку вы используете (включая номер версии)?
dmckee --- котенок экс-модератора

Строка 8, похоже, похожа на строку 11 .. не так ли? $ bash - версия GNU bash, версия 3.1.17 (1) -релиз (x86_64-suse-linux)
Aman ZeeK Verma

попробуйте изменить #! bin / sh на # /! / bin / bash, теперь все должно работать!
Aman ZeeK Verma

0

ANSI C 694 символа

Это версия на C, которая ищет горизонтальные или вертикальные участки двух пробелов, которые либо примыкают к краю, либо к символу «#».

Входной файл взят из stdin и должен быть:

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

Любые советы по уплотнению этого будут с благодарностью приняты.

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

Выходные данные для предоставленного примера

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

Этот код правильно обрабатывает # _ # вертикальные и горизонтальные одиночные пробелы, которые, хотя они могут и не встречаться в виде одного не связанного пробела, представляются допустимыми, например, как последняя буква, скажем, горизонтального слова.
Джонатан Уотмоф
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.