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


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 --- кошеня колишнього модератора

вхідний файл буде в txt?
www0z0k

@ www0z0k: Так. Uniek geek у мені завжди за замовчуванням тексту.
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])}

Тестували з рубіном 1.9.


Я дотримуюсь більшості цього. Не впевнений, що робить s.shift.split.map, але це має формувати масив із вхідних даних.
dmckee --- кошеня колишнього модератора

BTW - Як слід викликати це в командному рядку unix. Я спробував дати йому шебанг, відповідний моїй системі, але він скаржиться ./temp.ruby:4: wrong argument type Symbol (expected Proc) (TypeError).
dmckee --- кошеня колишнього модератора

s.shift приймає перший рядок, розділяє повернення ["m", "n"], карта повертає [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);}

Взяв у мене кілька спроб викликати це правильно. Гладкий.
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().


Думаю, ви перевернули номер рядків і стовпців. Якщо я правильно розумію, перше число - це кількість рядків, але ви трактуєте це як кількість стовпців.
ugoren

З того, що я можу сказати, вихід моєї програми відповідає прикладу, наведеному в описі, та результату з посилальної реалізації. Чи можете ви надати мені конкретний приклад того, про що ви маєте на увазі?
хлібопекарня

Будь-який приклад, коли числа рядків і стовпців не рівні.
ugoren

Гаразд, але давайте конкретно, будь ласка. Якщо вказано приклад сітки, наведеної в описі, моя програма виводить (1,2) для числа 1. Ви говорите, що моя програма повинна виводити (2,1)?
хлібниця

Я говорю про вхід, а не про вихід. Коли перший рядок 5 5, ви приймаєте перші 5 за ширину, коли ви мали взяти другий (що, звичайно, не має значення в цьому прикладі).
угорен

1

Реалізація довідок:

c99 unololfed і досить більше 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

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

компіляція та виклик:

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 кросвордGrid.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.