Code Golf: узнайте боксы ascii art

Придумал это некоторое время назад, выполняя некоторую работу с данными, хотя это создало бы хороший код для гольфа. Учитывая двумерный массив символов, содержащих прямоугольники ascii, создайте список координат и размеров для прямоугольников.

  • Любой тривиально конвертируемый входной или выходной формат в порядке (например: char **, список строк, строки на стандартном входе, список из четырех целых чисел, структура, фиксированная сумма +/- для размера и т.д.).
  • Точно так же вывод не должен быть в каком-либо конкретном порядке.
  • У вас нет ничего полезного для недопустимых входных или неправильных прямоугольников, но вы не должны создавать корректные координаты для прямоугольника, который не находится на входе.
  • Нет двух допустимых прямоугольников, разделяющих + (хотя + может отображаться не только как часть прямоугольника)
  • Вы можете предположить, что все прямоугольники не менее 3x3: каждая сторона имеет в ней - или |.

Примеры:

"        "
"  +-+ | "
"  | | \-"
"  +-+   "
(2,1;3,3)

"+--+  +--+"
"|  |  |  |"
"+--+  +--+"
(0,0;4,3), (6,0;4,3)

"  +---+  "
"->|...|  "
"  +---+  "
(2,0;5,3)

"+-+ +--+  +--+"
"| | |  |  |  |"
"+-+ |  |  + -+"
"    |  |      "
"    +--+  +-+ "
"  +--+    |   "
"  +--+    +-+ "
(0,0;3,3), (4,0;4,5) # (2,5;4,2) is fine, but not needed

Ответы

Ответ 1

Perl, 167 165 159 символов

( 156 символов, если вы не считаете, что вы накладываете stdin на @a, просто удалите последние 3 символа и назначьте список строк, представляющих ваш вход, на @a)

Получает ввод из stdin. Новые строки не значимы, добавлены для удобства чтения. Обратите внимание на использование оператора +++, P

map{$l=$i++;while($c=/\+-+\+/g){$w=$+[0]-2-($x=$-[0]);
$c++while$a[$l+$c]=~/^.{$x}\|.{$w}\|/;
print"($x,$l;",$w+2,",$c)\n"if$a[$c+++$l]=~/^.{$x}\+-{$w}\+/}}@a=<>


Будьте либеральны в том, что вы принимаете версии, 170 символов

map{$l=$i++;while($c=/\+-*\+/g){pos=-1+pos;$w=$+[0]-2-($x=$-[0]);
$c++while$a[$l+$c]=~/^.{$x}\|.{$w}\|/;
print"($x,$l;",$w+2,",$c)\n"if$a[$c+++$l]=~/^.{$x}\+-{$w}\+/}}@a=<>


Будьте консервативны в том, что вы принимаете версии, 177 символов

map{$l=$i++;while($c=/\+-+\+/g){$w=$+[0]-2-($x=$-[0]);
$c++while$a[$l+$c]=~/^.{$x}\|.{$w}\|/;print
"($x,$l;",$w+2,",$c)\n"if$c>1&&$a[$c+++$l]=~s/^(.{$x})\+(-{$w})\+/$1v$2v/}}@a=<>


Прокомментированная версия:

@a=<>;          # slurp stdin into an array of lines
$l=0;           # start counting lines from zero
map{            # for each line
    while(/\+-+\+/g){               # match all box tops
            $c=1;                           # initialize height

            # x coordinate, width of box - sides
            $w=$+[0]-2-($x=$-[0]);

            # increment height while there are inner parts
            # of a box with x and w coinciding with last top
            # (look into next lines of array)
            $c++  while $a[$l+$c]=~/^.{$x}\|.{$w}\|/;

            # if there is a box bottom on line + height
            # with coinciding x and w, print coords
            # (after incrementing height)
            print "($x,$l;",$w+2,",$c)\n"  
                    if $a[$c+++$l]=~/^.{$x}\+-{$w}\+/
    }
    $l++    # line++
}@a


Мега-тест:

+--+  +-+ +-+  +++   +---+   +-+  +-+-+  +-++-+
|SO|  | | | |  +++   |+-+|   | |  | | |  | || |
+--+  +-+-+-+  +++   ||+||   +-+  +-+-+  +-++-+
        | |          |+-+|   | |
      +-+-+-+        +---+   +-+
      | | | |
      +-+ +-+


++ +-+ ++     +-+   +- + +--+ +--+ +--+
|| +-+ ++   +-+-+   |  | |  | |    |  |
++          | |     |  | |  | |  |    |
            +-+     +--+ + -+ +--+ +--+

Ответ 2

Ruby - 306 260 245 228 168

# 228 chars
g=->(s,u='-'){o=[];s.scan(/\+#{u}+\+/){o<<[$`,$`+$&].map(&:size)};o}
b=t.map{|i|i.split''}.transpose.map{|s|g[s*'','\|']}
(1...t.size).map{|i|i.times{|j|(g[t[i]]&g[t[j]]).map{|x,y|p [x,j,y-x,i-j+1]if(b[x]&b[y-1]&[[j,i+1]])[0]}}}

производит

[0, 0, 3, 3]
[4, 1, 4, 3]
[10, 3, 3, 3]

при t =

["+-+       +--+",
"| | +--+  |  |",
"+-+ |  |  + -+",
"    +--+  +-+ ",
"  +--+    | | ",
"  +--+    +-+ "]

Пояснение:

# function returns info about all inclusions of "+---+" in string
# "  +--+ +-+" -> [[2,5],[7,9]]
g=->(s,u='-'){o=[];s.scan(/\+#{u}+\+/){o<<[$`,$`+$&].map(&:size)};o}

# mapping transposed input with this function
b=t.map{|i|i.split''}.transpose.map{|s|g[s*'','\|']}
# earlier here was also mapping original input, but later was merged with "analyse"

# "analyse"
# take each pair of lines
(1...t.size).map{|i|i.times{|j|
    # find horizontal sides of the same length on the same positions
    (g[t[i]]&g[t[j]]).map{|x,y|
        # make output if there are correct vertical sides
        p [x,j,y-x,i-j+1]if(b[x]&b[y-1]&[[j,i+1]])[0]
    }
}}

# yeah, some strange +/-1 magick included ,.)

И более прямолинейное решение с 168-символами!

t.size.times{|i|t[0].size.times{|j|i.times{|k|j.times{|l|p [l,k,j-l+1,i-k+1]if
t[k..i].map{|m|m[j]+m[l]}*''=~/^\+\+\|+\+\+$/&&t[i][l..j]+t[k][l..j]=~/^(\+-+\+){2}$/}}}}

Ответ 3

Perl - 223 222 216

Версия для гольфа (новые строки не значимы):

$y=0;sub k{$s=$-[0];"($s,%i;".($+[0]-$s).",%i)"}while(<>){while(/\+-+\+/g){
if(exists$h{&k}){[email protected],sprintf k,@{$h{&k}};delete$h{&k}}else{$h{&k}=[$y,2]}}
while(/\|.+?\|/g){++${$h{&k}}[1]if exists$h{&k}}++$y}print"@o\n"

Пожилая версия для игры в гольф:

# y starts at line zero.
$y = 0;

# Abuse Perl dynamic scoping rules
# to get a key for the hash of current rectangles,
# which indexes rectangles by x and width,
# and is also used as a format string.
sub k {

    # The start of the current match.
    $s = $-[0];

    # $+[0] is the end of the current match,
    # so subtract the beginning to get the width.
    "($s,%i;" . ($+[0] - $s) . ",%i)"

}

# Read lines from STDIN.
while (<>) {

    # Get all rectangle tops and bottoms in this line.
    while (/\+-+\+/g) {

        # If line is a bottom:
        if (exists $h{&k}) {

            # Add to output list and remove from current.
            push @o, sprintf k, @{$h{&k}};
            delete $h{&k}

        # If line is a top:
        } else {

            # Add rectangle to current.
            $h{&k} = [$y, 2]

        }

    }

    # Get all rectangle sides in this line.
    while (/\|.+?\|/g) {

        # Increment the height of the corresponding
        # rectangle, if one exists.
        ++${$h{&k}}[1] if exists $h{&k}

    }

    # Keep track of the current line.
    ++$y

}

# Print output.
print join", ",@o

Обратите внимание, что это не обрабатывает нежелательные вертикальные столбцы слева от прямоугольников, а именно:

   +--+  +--+
|  |  |  |  |
   +--+  +--+

Будет неверно выдавать высоту 2 для обоих. Это происходит из-за того, что шаблон /\|.+?\|/g начинает поиск с начала строки. У кого-нибудь есть предложение, как это исправить?

Ответ 4

JavaScript — 156 символов *

Также на http://jsfiddle.net/eR5ee/4/ (используйте ссылку только при использовании Firefox или Chrome) или http://jsfiddle.net/eR5ee/5/ (адаптировано для Safari и Opera):

var A = [
    "+-+ +--+  +--+",
    "| | |  |  |  |",
    "+-+ |  |  + -+",
    "    |  |      ",
    "    +--+  +-+ ",
    "  +--+    |   ",
    "  +--+    +-+ "
    ]; // not counted

for(y=A.length;--y;)for(;m=/\+-*\+/g(A[y]);){
for(w=m[0].length,z=y;A[--z][x=m.index]+A[z][x+w-1]=="||";);
/^\+-*\+$/(A[z].substr(x,w))&&alert([x,z,w,y-z+1])}
  • За исключением символов новой строки и пробелов, которые совершенно не нужны.
  • По-видимому, Firefox и Chrome сохраняют lastIndex первого регулярного выражения. Для сохранения Safari и Opera из бесконечного цикла требуется еще четыре символа. Чтобы заставить Internet Explorer работать, потребуется еще четырнадцать символов для исправления как выше, так и ошибки "Функция ожидается". По-видимому, "... метод exec регулярного выражения может быть вызван... косвенно (с regexp(str))" (цитируется из документации Mozilla) не относится к IE.

Код обнаруживает все прямоугольники 2x2 и больше, если ни одно прямоугольное дно не касается ни одного другого верхнего или нижнего прямоугольника или знака плюс или минус и не перекрывается.

Порядок номеров в каждом окне предупреждения (который соответствует прямоугольнику) остается слева, сверху, шириной, высотой. Код делает ошибку, если прямоугольник продолжается сверху, но все необходимые координаты уже были выведены (из спецификации: "Вам не нужно (sic) ничего полезного для недопустимых входных или искаженных прямоугольников..." )

Так как большинство основных веб-браузеров реализуют тег canvas, еще в нескольких строках кода, рисование обнаруженных прямоугольников на экране возможно. http://jsfiddle.net/MquqM/6/ работает во всех браузерах, кроме Internet Explorer и Opera.

Изменить: исключено ненужное присвоение переменной Редактирование 2: избегайте бросать ошибки с полностью допустимым вводом (-y вместо y--), проясните конкретные случаи, когда код обрабатывает

Ответ 5

C ( 204 186 символов)

    #include<stdio.h>
    char H=7,W=14,*S =
    "+-+ +--+  +--+"
    "| | |  |  |  |"
    "+-+ |  |  + -+"
    "    |  |      "
    "    +--+  +-+ "
    "  +--+    |   "
    "  +--+    +-+ ";
    void main(){
#define F(a,r,t)if(*c==43){while(*(c+=a)==r);t}
char*c,*o,*e=S;while(*(c=e++))
F(1,45,F(W,'|',o=c;F(-1,45,F(-W,'|',c==e-1?
printf("%i,%i %i,%i\n",(c-S)%W,(c-S)/W,(o-c)%W+1,(o-c)/W+1):0;))))
    }

Счетчик символов - это тело main(). Этот код будет перемещаться по строке с e до тех пор, пока он не достигнет верхнего левого угла потенциального прямоугольника. Затем он проверяет края с помощью c и использует o для отслеживания нижнего правого угла.

Вывод программы:

0,0 3,3
4,0 4,5
2,5 4,2

Ответ 6

Scala 2.8 - 283 273 269 257

val a = Seq(
    "+-+ +--+  +--+",
    "| | |  |  |  |",
    "+-+ |  |  + -+",
    "    |  |      ",
    "    +--+  +-+ ",
    "  +--+    |   ",
    "  +--+    +-+ "
  )

// begin golf count
val (w,h) = (a(0).size-1,a.size-1)
for (
  x <- 0 to w;
  y <- 0 to h;
  u <- x+2 to w;
  v <- y+2 to h;
  if Set(a(y)(x),a(v)(x),a(y)(u),a(v)(u)) == Set(43)
  && (x+1 to u-1).forall(t => (a(y)(t)<<8|a(v)(t)) == 11565)
  && (y+1 to v-1).forall(t => (a(t)(x)<<8|a(t)(u)) == 31868)
) yield (x,y,u-x+1,v-y+1)
// end golf count

имеет значение:

Vector((0,0,3,3), (4,0,4,5))

Выражение for оценивает ответ (объект Vector), поэтому я подсчитал только эту часть (удаленные пробелы). Дайте мне знать, правильно ли это считать.

Как это работает

Координаты всех возможных прямоугольников (фактически, только >= 3x3) генерируются выражением for. Эти координаты фильтруются, ища +, - и | по краям и углам всех прямоугольников (часть if выражения for).

Ответ 7

Python 2.6 - 287 263 254

a = [
    "+-+ +--+  +--+",
    "| | |  |  |  |",
    "+-+ |  |  + -+",
    "    |  |      ",
    "    +--+  +-+ ",
    "  +--+    |   ",
    "  +--+    +-+ "
    ]

l=len
r=range
w,h=l(a[0]),l(a)
[(x,y,u,v)for x in r(0,w)for y in r(0,h)for u in r(x+2,w)for v in r(y+2,h)if a[y][x]==a[v][x]==a[y][u]==a[v][u]=='+' and a[y][x+1:u]+a[v][x+1:u]=="-"*2*(u-x-1)and l([c for c in r(y+1,v-y)if a[c][x]==a[c][u]=='|'])==v-y-1]

оценивается как:

[(0, 0, 3, 3), (4, 0, 4, 5)]

Ответ 8

Python 2.6 (251 символ)

Я прихожу немного поздно, во всяком случае, немного веселья. Python, используя регулярные выражения. Чтобы сохранить оператор печати и оставаться короче, чем Fredb219, это ничего не будет печатать, если вы запустите его как script, но набрав по одной строке за раз в интерпретаторе, он покажет результат. Не очень солидный, он не будет обрабатывать вложенные ящики и большинство случаев, более сложных, чем те, которые даются DavidX. Не проводили тестирование, но я думаю, что он может показать результаты в неправильном порядке, если произойдет что-то "странное".

import re
l,a,o=s.index("\n")+1,re.finditer,sorted
o(o(set((m.start(),m.end())for m in a(r'\+-* *-*\+',s)for n in a(r'\|.+\|',s)if(m.start()%l,m.end()%l)==(n.start()%l,n.end()%l)if m.start()+l==n.start()or m.start()-l==n.start())),key=lambda x:x[0]%l)

Ввод - это одна строка, строки (одинаковая длина), разделенные символом новой строки. Результатом являются строковые срезы сверху и снизу для каждого "хорошего" поля, начиная с левого верхнего угла. Он также позволяет "сломанные" коробки (т.е. С некоторым пространством посередине одной стороны, не без одной цельной стороны). Это был всего лишь способ исправить нежелательное поведение, создав много новых побочных эффектов!:-)

ввод:

>>>s = """+-+ +--+  +--+
| | |  |  |  |
+-+ |  |  + -+
    |  |      
    +--+  +-+ 
  +--+    |   
  +--+    +-+ """

или

>>>s = "+-+ +--+  +--+\n| | |  |  |  |\n+-+ |  |  + -+\n    |  |      \n    +--+  +-+ \n  +--+    | \n  +--+    +-+ "

то

>>>import re
>>>l,a,o=s.index("\n")+1,re.finditer,sorted
>>>o(o(set((m.start(),m.end())for m in a(r'\+-* *-*\+',s)for n in a(r'\|.+?\|',s)if(m.start()%l,m.end()%l)==(n.start()%l,n.end()%l)if m.start()+l==n.start()or m.start()-l==n.start())),key=lambda x:x[0]%l)

выход:

[(0, 3), (30, 33), (4, 8), (64, 68), (10, 14), (40, 44)]

так (0,3) верхняя часть 1-го ящика (30,33) снизу того же поля, (4,8) вверху второго ящика и т.д.

Ответ 9

F #, 297 символов

Своего рода, но просто.

let F a=
 for x=0 to Array2D.length1 a-1 do
  for y=0 to Array2D.length2 a-1 do
  if a.[x,y]='+' then
   let mutable i,j=x+1,y+1
   while a.[i,y]<>'+' do i<-i+1
   while a.[x,j]<>'+' do j<-j+1
   printfn"(%d,%d;%d,%d)"x y (i-x+1)(j-y+1)
   a.[i,y]<-' '
   a.[x,j]<-' '
   a.[i,j]<-' '

Ищите плюса. Найдите тот, который находится справа от него. Найдите ниже. Распечатайте эту информацию о прямоугольнике и "вычеркните" плюсы, которые мы уже использовали. Поскольку каждый плюс является только частью одного правильного прямоугольника, это все, что нам нужно сделать.

Ответ 10

XQuery (304 символа)

Вот мое решение:

declare variable $i external;let$w:=string-length($i[1]),$h:=count($i)for$y in 1 to$h,$x in 1 to$w,$w in 2 to$w+1 -$x,$h in 1 to$h where min(for$r in (0,$h),$s in 1 to$h return (matches(substring($i[$y+$r],$x,$w),'^\+-*\+$'),matches(substring($i[$y+$s],$x,$w),'^|.*|$')))return ($x -1,$y -1,$w,$h+1,'')

Вы можете запустить это (с помощью XQSharp), установив переменную $i в качестве строк ввода

>XQuery boxes.xq "i=('  +-+','+-+-+','| |  ','+-+  ')" !method=text

2 0 3 2  0 1 3 3

Я полагаю, можно утверждать, что declare variable $i external; просто устанавливает ввод и поэтому не добавляет к счету, и в этом случае 275 символов